diff options
author | Ben Straub <bstraub@github.com> | 2012-07-17 08:08:34 -0700 |
---|---|---|
committer | Ben Straub <bstraub@github.com> | 2012-07-17 08:08:34 -0700 |
commit | bfc65634050dc52e3ed6b4497ebbb511e39d6e1e (patch) | |
tree | 32b03847b8a152b69bc3b48b6bb32e7b8621f45e /src/path.c | |
parent | 1d68fcd04b21a2c5665d0ca6a5543e7166c73457 (diff) | |
parent | ea5d2ce4cfa6cec89e2d844a70d1eb24bb401c7d (diff) | |
download | libgit2-bfc65634050dc52e3ed6b4497ebbb511e39d6e1e.tar.gz |
Merge branch 'development' into clone
Diffstat (limited to 'src/path.c')
-rw-r--r-- | src/path.c | 73 |
1 files changed, 68 insertions, 5 deletions
diff --git a/src/path.c b/src/path.c index ee7e07e45..22391c52b 100644 --- a/src/path.c +++ b/src/path.c @@ -17,9 +17,7 @@ #include <stdio.h> #include <ctype.h> -#ifdef GIT_WIN32 #define LOOKS_LIKE_DRIVE_PREFIX(S) (git__isalpha((S)[0]) && (S)[1] == ':') -#endif /* * Based on the Android implementation, BSD licensed. @@ -172,11 +170,11 @@ int git_path_root(const char *path) { int offset = 0; -#ifdef GIT_WIN32 /* Does the root of the path look like a windows drive ? */ if (LOOKS_LIKE_DRIVE_PREFIX(path)) offset += 2; +#ifdef GIT_WIN32 /* Are we dealing with a windows network path? */ else if ((path[0] == '/' && path[1] == '/') || (path[0] == '\\' && path[1] == '\\')) @@ -527,6 +525,71 @@ int git_path_find_dir(git_buf *dir, const char *path, const char *base) return error; } +int git_path_resolve_relative(git_buf *path, size_t ceiling) +{ + char *base, *to, *from, *next; + size_t len; + + if (!path || git_buf_oom(path)) + return -1; + + if (ceiling > path->size) + ceiling = path->size; + + /* recognize drive prefixes, etc. that should not be backed over */ + if (ceiling == 0) + ceiling = git_path_root(path->ptr) + 1; + + /* recognize URL prefixes that should not be backed over */ + if (ceiling == 0) { + for (next = path->ptr; *next && git__isalpha(*next); ++next); + if (next[0] == ':' && next[1] == '/' && next[2] == '/') + ceiling = (next + 3) - path->ptr; + } + + base = to = from = path->ptr + ceiling; + + while (*from) { + for (next = from; *next && *next != '/'; ++next); + + len = next - from; + + if (len == 1 && from[0] == '.') + /* do nothing with singleton dot */; + + else if (len == 2 && from[0] == '.' && from[1] == '.') { + while (to > base && to[-1] == '/') to--; + while (to > base && to[-1] != '/') to--; + } + + else { + if (*next == '/') + len++; + + if (to != from) + memmove(to, from, len); + + to += len; + } + + from += len; + + while (*from == '/') from++; + } + + *to = '\0'; + + path->size = to - path->ptr; + + return 0; +} + +int git_path_apply_relative(git_buf *target, const char *relpath) +{ + git_buf_joinpath(target, git_buf_cstr(target), relpath); + return git_path_resolve_relative(target, 0); +} + int git_path_cmp( const char *name1, size_t len1, int isdir1, const char *name2, size_t len2, int isdir2) @@ -570,7 +633,7 @@ int git_path_direach( return -1; } -#ifdef __sun +#if defined(__sun) || defined(__GNU__) de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); #else de_buf = git__malloc(sizeof(struct dirent)); @@ -624,7 +687,7 @@ int git_path_dirload( return -1; } -#ifdef __sun +#if defined(__sun) || defined(__GNU__) de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); #else de_buf = git__malloc(sizeof(struct dirent)); |