summaryrefslogtreecommitdiffstats
path: root/src/util/sane_basename.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/sane_basename.c')
-rw-r--r--src/util/sane_basename.c181
1 files changed, 181 insertions, 0 deletions
diff --git a/src/util/sane_basename.c b/src/util/sane_basename.c
new file mode 100644
index 0000000..6c3a4c1
--- /dev/null
+++ b/src/util/sane_basename.c
@@ -0,0 +1,181 @@
+/*++
+/* NAME
+/* sane_basename 3
+/* SUMMARY
+/* split pathname into last component and parent directory
+/* SYNOPSIS
+/* #include <stringops.h>
+/*
+/* char *sane_basename(buf, path)
+/* VSTRING *buf;
+/* const char *path;
+/*
+/* char *sane_dirname(buf, path)
+/* VSTRING *buf;
+/* const char *path;
+/* DESCRIPTION
+/* These functions split a pathname into its last component
+/* and its parent directory, excluding any trailing "/"
+/* characters from the input. The result is a pointer to "/"
+/* when the input is all "/" characters, or a pointer to "."
+/* when the input is a null pointer or zero-length string.
+/*
+/* sane_basename() and sane_dirname() differ as follows
+/* from standard basename() and dirname() implementations:
+/* .IP \(bu
+/* They can use caller-provided storage or private storage.
+/* .IP \(bu
+/* They never modify their input.
+/* .PP
+/* sane_basename() returns a pointer to string with the last
+/* pathname component.
+/*
+/* sane_dirname() returns a pointer to string with the parent
+/* directory. The result is a pointer to "." when the input
+/* contains no '/' character.
+/*
+/* Arguments:
+/* .IP buf
+/* Result storage. If a null pointer is specified, each function
+/* uses its own private memory that is overwritten upon each call.
+/* .IP path
+/* The input pathname.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this
+/* software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <vstring.h>
+#include <stringops.h>
+
+#define STR(x) vstring_str(x)
+
+/* sane_basename - skip directory prefix */
+
+char *sane_basename(VSTRING *bp, const char *path)
+{
+ static VSTRING *buf;
+ const char *first;
+ const char *last;
+
+ /*
+ * Your buffer or mine?
+ */
+ if (bp == 0) {
+ bp = buf;
+ if (bp == 0)
+ bp = buf = vstring_alloc(10);
+ }
+
+ /*
+ * Special case: return "." for null or zero-length input.
+ */
+ if (path == 0 || *path == 0)
+ return (STR(vstring_strcpy(bp, ".")));
+
+ /*
+ * Remove trailing '/' characters from input. Return "/" if input is all
+ * '/' characters.
+ */
+ last = path + strlen(path) - 1;
+ while (*last == '/') {
+ if (last == path)
+ return (STR(vstring_strcpy(bp, "/")));
+ last--;
+ }
+
+ /*
+ * The pathname does not end in '/'. Skip to last '/' character if any.
+ */
+ first = last - 1;
+ while (first >= path && *first != '/')
+ first--;
+
+ return (STR(vstring_strncpy(bp, first + 1, last - first)));
+}
+
+/* sane_dirname - keep directory prefix */
+
+char *sane_dirname(VSTRING *bp, const char *path)
+{
+ static VSTRING *buf;
+ const char *last;
+
+ /*
+ * Your buffer or mine?
+ */
+ if (bp == 0) {
+ bp = buf;
+ if (bp == 0)
+ bp = buf = vstring_alloc(10);
+ }
+
+ /*
+ * Special case: return "." for null or zero-length input.
+ */
+ if (path == 0 || *path == 0)
+ return (STR(vstring_strcpy(bp, ".")));
+
+ /*
+ * Remove trailing '/' characters from input. Return "/" if input is all
+ * '/' characters.
+ */
+ last = path + strlen(path) - 1;
+ while (*last == '/') {
+ if (last == path)
+ return (STR(vstring_strcpy(bp, "/")));
+ last--;
+ }
+
+ /*
+ * This pathname does not end in '/'. Skip to last '/' character if any.
+ */
+ while (last >= path && *last != '/')
+ last--;
+ if (last < path) /* no '/' */
+ return (STR(vstring_strcpy(bp, ".")));
+
+ /*
+ * Strip trailing '/' characters from dirname (not strictly needed).
+ */
+ while (last > path && *last == '/')
+ last--;
+
+ return (STR(vstring_strncpy(bp, path, last - path + 1)));
+}
+
+#ifdef TEST
+#include <vstring_vstream.h>
+
+int main(int argc, char **argv)
+{
+ VSTRING *buf = vstring_alloc(10);
+ char *dir;
+ char *base;
+
+ while (vstring_get_nonl(buf, VSTREAM_IN) > 0) {
+ dir = sane_dirname((VSTRING *) 0, STR(buf));
+ base = sane_basename((VSTRING *) 0, STR(buf));
+ vstream_printf("input=\"%s\" dir=\"%s\" base=\"%s\"\n",
+ STR(buf), dir, base);
+ }
+ vstream_fflush(VSTREAM_OUT);
+ vstring_free(buf);
+ return (0);
+}
+
+#endif