Signed-off-by: Alex Riesen <raa.lkml@xxxxxxxxx> --- This will be used by the following patch. I actually already have sent this one in, as suggestion for some problem back then. It is a bit generic, so it gets its own patch. cache.h | 2 ++ path.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 0 deletions(-) diff --git a/cache.h b/cache.h index 054f106..25ce5da 100644 --- a/cache.h +++ b/cache.h @@ -383,6 +383,8 @@ static inline int is_absolute_path(const char *path) return path[0] == '/'; } const char *make_absolute_path(const char *path); +/* Returns the analog of "cd path" from a directory "cwd" */ +extern char *pathexpand(const char *cwd, const char *path); /* Read and unpack a sha1 file into memory, write memory to a sha1 file */ extern int sha1_object_info(const unsigned char *, unsigned long *); diff --git a/path.c b/path.c index 4260952..8231cd8 100644 --- a/path.c +++ b/path.c @@ -353,3 +353,62 @@ const char *make_absolute_path(const char *path) return buf; } + +/* + * Returns the analog of "cd path" from a directory "cwd". + * The root is defined as empty path (instead of "/") + * An attempt to go past the root (with "..") leaves the path at root. + * The cwd is not expanded. + */ +char *pathexpand(const char *cwd, const char *path) +{ + static const char SEP[] = "/"; + if (!*path) /* empty path -> "." (don't move) */ + path = "."; + if (!cwd || !*cwd || *SEP == *path) /* no cwd, or path begins with "/" */ + cwd = ""; + + while (*cwd && *SEP == *cwd) + ++cwd; + + size_t len = strlen(cwd); + char *out = malloc(len + 1 + strlen(path) + 1); + char *p = strcpy(out, cwd) + len; + + for (; *path; ++path) + { + char *pl; + if (p > out && p[-1] != *SEP) + *p++ = *SEP; + pl = p; + while (*path && *SEP != *path) + *p++ = *path++; + *p = '\0'; + /* ..."//"... */ + if (p == pl) + ; /* just ignore */ + /* ..."/./"... */ + else if ( p - pl == 1 && '.' == *pl ) + --p; /* just ignore */ + /* ..."/../"... */ + else if ( p - pl == 2 && '.' == pl[0] && '.' == pl[1] ) + { + /* drop the last element of the resulting path */ + if (pl > out && --pl > out) + for (--pl; pl > out && *SEP != *pl; --pl) + ; + p = pl > out ? ++pl: out; + } + /* ..."/path/"... */ + else if (*path) + *p++ = *path; /* just add the separator */ + + if (!*path) + break; + } + if (p > out+1 && *SEP == p[-1]) + --p; + *p = '\0'; + return out; +} + -- 1.5.4.rc0.86.g30f5 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html