summaryrefslogtreecommitdiffstats
path: root/src/util/support/path.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/support/path.c')
-rw-r--r--src/util/support/path.c161
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
+}