diff options
Diffstat (limited to 'src/util/support/path.c')
-rw-r--r-- | src/util/support/path.c | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/util/support/path.c b/src/util/support/path.c new file mode 100644 index 0000000000..221fb4a6a1 --- /dev/null +++ b/src/util/support/path.c @@ -0,0 +1,161 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* util/support/path.c - Portable path manipulation functions */ +/* + * Copyright (C) 2011 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +#include <k5-platform.h> + +/* For testing purposes, use a different symbol for Windows path semantics. */ +#ifdef _WIN32 +#define WINDOWS_PATHS +#endif + +/* + * This file implements a limited set of portable path manipulation functions. + * When in doubt about edge cases, we follow the Python os.path semantics. + */ + +#ifdef WINDOWS_PATHS +#define SEP '\\' +#define IS_SEPARATOR(c) ((c) == '\\' || (c) == '/') +#else +#define SEP '/' +#define IS_SEPARATOR(c) ((c) == '/') +#endif + +/* Find the rightmost path separator in path, or NULL if there is none. */ +static inline const char * +find_sep(const char *path) +{ +#ifdef WINDOWS_PATHS + const char *slash, *backslash; + + slash = strrchr(path, '/'); + backslash = strrchr(path, '\\'); + if (slash != NULL && backslash != NULL) + return (slash > backslash) ? slash : backslash; + else + return (slash != NULL) ? slash : backslash; +#else + return strrchr(path, '/'); +#endif +} + +/* XXX drive letter prefixes */ +long +k5_path_split(const char *path, char **parent_out, char **basename_out) +{ + const char *pathstart, *sep, *pend, *bstart; + char *parent = NULL, *basename = NULL; + + if (parent_out != NULL) + *parent_out = NULL; + if (basename_out != NULL) + *basename_out = NULL; + + pathstart = path; +#ifdef WINDOWS_PATHS + if (*path != '\0' && path[1] == ':') + pathstart = path + 2; +#endif + + sep = find_sep(pathstart); + if (sep != NULL) { + bstart = sep + 1; + /* Strip off excess separators before the one we found. */ + pend = sep; + while (pend > pathstart && IS_SEPARATOR(pend[-1])) + pend--; + /* But if we hit the start, keep the whole separator sequence. */ + if (pend == pathstart) + pend = sep + 1; + } else { + bstart = pathstart; + pend = pathstart; + } + + if (parent_out) { + parent = malloc(pend - path + 1); + if (parent == NULL) + return ENOMEM; + memcpy(parent, path, pend - path); + parent[pend - path] = '\0'; + } + if (basename_out) { + basename = strdup(bstart); + if (basename == NULL) { + free(parent); + return ENOMEM; + } + } + + if (parent_out) + *parent_out = parent; + if (basename_out) + *basename_out = basename; + return 0; +} + +long +k5_path_join(const char *path1, const char *path2, char **path_out) +{ + char *path, c; + int ret; + + *path_out = NULL; + if (k5_path_isabs(path2) || *path1 == '\0') { + /* Discard path1 and return a copy of path2. */ + path = strdup(path2); + if (path == NULL) + return ENOMEM; + } else { + /* + * Compose path1 and path2, adding a separator if path1 is non-empty + * there's no separator between them already. (*path2 can be a + * separator in the weird case where it starts with /: or \: on + * Windows, and Python doesn't insert a separator in this case.) + */ + c = path1[strlen(path1) - 1]; + if (IS_SEPARATOR(c) || IS_SEPARATOR(*path2)) + ret = asprintf(&path, "%s%s", path1, path2); + else + ret = asprintf(&path, "%s%c%s", path1, SEP, path2); + if (ret < 0) + return ENOMEM; + } + *path_out = path; + return 0; +} + +int +k5_path_isabs(const char *path) +{ +#ifdef WINDOWS_PATHS + if (*path != '\0' && path[1] == ':') + path += 2; + return (*path == '/' || *path == '\\'); +#else + return (*path == '/'); +#endif +} |