[RFC] Path building api

This PR is a rewrite of #1097 since it got too sloppy to maintain. Sorry for all the reviewers having to re-read the same code. Here's a summary of what it adds:

| function | was | post | returns |
------------|------|-------|---
| path_save(p) | (N/A) | (N/A) | add_sep(strdup(p)) |
| path_copy(buf,p) | (N/A) | buf = add_sep(p) | STRLEN(buf) |
| path_join(a,b) | concat_fnames | (N/A) | add_sep(a) + b |
| path_buf_join(buf,a,b) | (N/A) | buf = join(a,b) | STRLEN(buf) |
| path_append(a,b) | append_path | a = buf_join(a,a,b) | STRLEN(a) |
| path_append_with_sep(a,b) | (N/A) | add_sep(append(a,b)) | STRLEN(a) |
| path_add_sep(p) | add_pathsep | p = p + PATHSEPSTR (if needed) | STRLEN(p) |

Maybe this table should be in the code somewhere (minus the "was" column), and doxygen does support tables, but I wasn't sure where.

My goal was to remove instances of `add_pathsep()` as much as possible, thinking of copying a path and adding a separator as one atomic action. The functions returning an `STRLEN` return a zero on truncation which I hope makes error checking easier--if not enforced when the caller actually requires the length. I've done my best to ensure they produce optimal code as well.

Travis failed on the python api, but that's a known issue.
Right... `path_copy(buf, base)` will return `0` to signal truncation, so we should return early.