diff options
author | Vicent Marti <tanoku@gmail.com> | 2011-07-04 13:43:34 +0400 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2011-07-05 04:04:03 +0400 |
commit | f79026b4912bcd2336667f4c1663c06e233f0b32 (patch) | |
tree | 645b776032e924b587fad986aa3f3dc08c98d4c5 /src/path.c | |
parent | 678e9e045becdc5d75f2ce2259ed01c3531ee181 (diff) |
fileops: Cleanup
Cleaned up the structure of the whole OS-abstraction layer.
fileops.c now contains a set of utility methods for file management used
by the library. These are abstractions on top of the original POSIX
calls.
There's a new file called `posix.c` that contains
emulations/reimplementations of all the POSIX calls the library uses.
These are prefixed with `p_`. There's a specific posix file for each
platform (win32 and unix).
All the path-related methods have been moved from `utils.c` to `path.c`
and have their own prefix.
Diffstat (limited to 'src/path.c')
-rw-r--r-- | src/path.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/src/path.c b/src/path.c new file mode 100644 index 000000000..766f67427 --- /dev/null +++ b/src/path.c @@ -0,0 +1,204 @@ +#include "common.h" +#include <stdarg.h> +#include <stdio.h> +#include <ctype.h> + +/* + * Based on the Android implementation, BSD licensed. + * Check http://android.git.kernel.org/ + */ +int git_path_basename_r(char *buffer, size_t bufflen, const char *path) +{ + const char *endp, *startp; + int len, result; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + startp = "."; + len = 1; + goto Exit; + } + + /* Strip trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* All slashes becomes "/" */ + if (endp == path && *endp == '/') { + startp = "/"; + len = 1; + goto Exit; + } + + /* Find the start of the base */ + startp = endp; + while (startp > path && *(startp - 1) != '/') + startp--; + + len = endp - startp +1; + +Exit: + result = len; + if (buffer == NULL) { + return result; + } + if (len > (int)bufflen-1) { + len = (int)bufflen-1; + result = GIT_ENOMEM; + } + + if (len >= 0) { + memmove(buffer, startp, len); + buffer[len] = 0; + } + return result; +} + +/* + * Based on the Android implementation, BSD licensed. + * Check http://android.git.kernel.org/ + */ +int git_path_dirname_r(char *buffer, size_t bufflen, const char *path) +{ + const char *endp; + int result, len; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + path = "."; + len = 1; + goto Exit; + } + + /* Strip trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* Find the start of the dir */ + while (endp > path && *endp != '/') + endp--; + + /* Either the dir is "/" or there are no slashes */ + if (endp == path) { + path = (*endp == '/') ? "/" : "."; + len = 1; + goto Exit; + } + + do { + endp--; + } while (endp > path && *endp == '/'); + + len = endp - path +1; + +Exit: + result = len; + if (len+1 > GIT_PATH_MAX) { + return GIT_ENOMEM; + } + if (buffer == NULL) + return result; + + if (len > (int)bufflen-1) { + len = (int)bufflen-1; + result = GIT_ENOMEM; + } + + if (len >= 0) { + memmove(buffer, path, len); + buffer[len] = 0; + } + return result; +} + + +char *git_path_dirname(const char *path) +{ + char *dname = NULL; + int len; + + len = (path ? strlen(path) : 0) + 2; + dname = (char *)git__malloc(len); + if (dname == NULL) + return NULL; + + if (git_path_dirname_r(dname, len, path) < GIT_SUCCESS) { + free(dname); + return NULL; + } + + return dname; +} + +char *git_path_basename(const char *path) +{ + char *bname = NULL; + int len; + + len = (path ? strlen(path) : 0) + 2; + bname = (char *)git__malloc(len); + if (bname == NULL) + return NULL; + + if (git_path_basename_r(bname, len, path) < GIT_SUCCESS) { + free(bname); + return NULL; + } + + return bname; +} + + +const char *git_path_topdir(const char *path) +{ + size_t len; + int i; + + assert(path); + len = strlen(path); + + if (!len || path[len - 1] != '/') + return NULL; + + for (i = len - 2; i >= 0; --i) + if (path[i] == '/') + break; + + return &path[i + 1]; +} + +void git_path_join_n(char *buffer_out, int count, ...) +{ + va_list ap; + int i; + char *buffer_start = buffer_out; + + va_start(ap, count); + for (i = 0; i < count; ++i) { + const char *path; + int len; + + path = va_arg(ap, const char *); + + assert((i == 0) || path != buffer_start); + + if (i > 0 && *path == '/' && buffer_out > buffer_start && buffer_out[-1] == '/') + path++; + + if (!*path) + continue; + + len = strlen(path); + memmove(buffer_out, path, len); + buffer_out = buffer_out + len; + + if (i < count - 1 && buffer_out[-1] != '/') + *buffer_out++ = '/'; + } + va_end(ap); + + *buffer_out = '\0'; +} + |