standard C dictionary to store data associated with unique string keys
</td></tr>
+<tr><td><a
+href="/?p=oddbits.git;a=tree;f=mkdirp;hb=HEAD"><b>
+mkdirp
+</b></a></td><td>-</td><td>
+create a directory and missing parents
+</td></tr>
+
<tr><td><a
href="/?p=oddbits.git;a=tree;f=net;hb=HEAD"><b>
net
--- /dev/null
+#include <errno.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "mkdirp.h"
+
+
+/* mkdirp - create a directory and missing parents */
+
+int mkdirp(const char *pathname, mode_t mode) {
+ if (!pathname || !*pathname) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ int err = 0;
+ char *p;
+ char path[strlen(pathname) + 1];
+ struct stat sb;
+
+ if (stat(pathname, &sb) == 0 && S_ISDIR(sb.st_mode))
+ return 0;
+
+ mode |= S_IRWXU;
+ strcpy(path, pathname);
+ p = path + 1;
+ do {
+ p = strchr(p, '/');
+ if (p)
+ *p = '\0';
+ if (stat(path, &sb) != 0 || !S_ISDIR(sb.st_mode))
+ err = mkdir(path, mode);
+ if (p)
+ *p++ = '/';
+ } while (!err && p && *p);
+
+ return err;
+}
+
--- /dev/null
+/*
+ * mkdirp.h
+ *
+ * Copyright (c) 2019, Urban Wallasch
+ * BSD 3-Clause License, see LICENSE file for more details.
+ *
+ * Create a directory and its parents, if they do not already exist.
+ *
+ */
+
+
+#ifndef MKDIRP_H_INCLUDED
+#define MKDIRP_H_INCLUDED
+
+#ifdef cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+
+/*
+ * mkdirp - create a directory and missing parents
+ *
+ * The mkdirp() function creates the directory pathname with the specified
+ * mode, if it does not already exist. If necessary, any missing parent
+ * directories are created as part of the process. The file mode of each
+ * created directory is ((mode | 0700) & ~umask & 0777). The modes of
+ * already existing directories are left unchanged.
+ *
+ * The mkdirp() function returns 0, if the specified directory already
+ * exists or was successfully created, or -1 if an error occurred, in
+ * which case errno is set appropriately.
+ */
+extern int mkdirp(const char *pathname, mode_t mode);
+
+
+#ifdef cplusplus
+}
+#endif
+
+#endif /* ndef MKDIRP_H_INCLUDED */
--- /dev/null
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mkdirp.h"
+
+
+int main(void) {
+ struct {
+ const char *d;
+ int m;
+ int expect;
+ } t[] = {
+ { "", 0, -1 },
+ { "/", 0, 0 },
+ { "A_test", 0755, 0 },
+ { "A_test/a", 0644, 0 },
+ { "B_test/", 0, 0 },
+ { "B_test/b/", 0, 0 },
+ { "/C", 0, -1 },
+ { "/D/", 0, -1 },
+ { "C_test/E", 0, 0 },
+ { "C_test/F/", 0, 0 },
+ { "./C_test//////..///C_test//././././././//X///// ", 0777, 0 },
+ { "/tmp/G_test", 0, 0 },
+ { "/tmp/H_test/", 0, 0 },
+ { "/tmp/I_test/bar/baz/zonk/", 0, 0 },
+ { "/tmp/I_test/bar/baz/borg", 0, 0 },
+ { NULL, 0, -1 }
+ };
+ int i = 0, err;
+
+ do {
+ err = mkdirp(t[i].d, t[i].m);
+ assert( err == t[i].expect );
+ if (err)
+ fprintf(stderr, "mkdir_p(\"%s\", 0%03o) : %s\n", t[i].d, t[i].m, strerror(errno));
+ else
+ fprintf(stderr, "mkdir_p(\"%s\", 0%03o) : Ok\n", t[i].d, t[i].m);
+ } while (t[i++].d);
+
+ return 0;
+}
+
--- /dev/null
+#!/bin/bash
+EXEC=mkdirp_test
+SRC="mkdirp.c mkdirp_test.c"
+OPTS="-Wall -Wextra -Werror"
+
+CMD="gcc $OPTS -o $EXEC $SRC"
+echo $CMD
+$CMD && "./$EXEC"
+rm -rf [ABC]_test /tmp/[GHI]_test