summaryrefslogtreecommitdiffstats
path: root/src/util/support/path.c
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2011-08-07 01:12:28 +0000
committerGreg Hudson <ghudson@mit.edu>2011-08-07 01:12:28 +0000
commit62a276e55287a06d66373f02202ab39c7ba74c00 (patch)
treed164f07b2a965f318d739a356e90835ea6dafd60 /src/util/support/path.c
parentb0b94b9330fbf671da6c9dcd06d3b07eab4c63c6 (diff)
downloadkrb5-62a276e55287a06d66373f02202ab39c7ba74c00.tar.gz
krb5-62a276e55287a06d66373f02202ab39c7ba74c00.tar.xz
krb5-62a276e55287a06d66373f02202ab39c7ba74c00.zip
Add internal APIs for portable path manipulation
k5_path_split separates a path into dirname and basename. k5_path_join joins two paths. k5_path_isabs determines if a path is absolute. All three functions follow the Python path function semantics. Currently the test module doesn't run in the Windows build, but the Windows path semantics are tested in the Unix build using specially built objects. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25074 dc483132-0cff-0310-8789-dd5450dbe970
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
+}