compat/basename.c: provide a dirname() compatibility function
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Tue, 12 Jan 2016 07:57:36 +0000 (08:57 +0100)
committerJunio C Hamano <gitster@pobox.com>
Tue, 12 Jan 2016 18:40:54 +0000 (10:40 -0800)
When there is no `libgen.h` to our disposal, we miss the `dirname()`
function. Earlier we added basename() compatibility function for
the same reason at e1c06886 (compat: add a basename() compatibility
function, 2009-05-31).

So far, we only had one user of that function: credential-cache--daemon
(which was only compiled when Unix sockets are available, anyway). But
now we also have `builtin/am.c` as user, so we need it.

Since `dirname()` is a sibling of `basename()`, we simply put our very
own `gitdirname()` implementation next to `gitbasename()` and use it
if `NO_LIBGEN_H` has been set.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
compat/basename.c
git-compat-util.h
index 0f1b0b0930ebaaf1448ba6760addfc20635d2cce..96bd9533b448e56176a335a41e32f9bb2dd24d03 100644 (file)
@@ -1,4 +1,5 @@
 #include "../git-compat-util.h"
+#include "../strbuf.h"
 
 /* Adapted from libiberty's basename.c.  */
 char *gitbasename (char *path)
@@ -25,3 +26,46 @@ char *gitbasename (char *path)
        }
        return (char *)base;
 }
+
+char *gitdirname(char *path)
+{
+       static struct strbuf buf = STRBUF_INIT;
+       char *p = path, *slash = NULL, c;
+       int dos_drive_prefix;
+
+       if (!p)
+               return ".";
+
+       if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p)
+               goto dot;
+
+       /*
+        * POSIX.1-2001 says dirname("/") should return "/", and dirname("//")
+        * should return "//", but dirname("///") should return "/" again.
+        */
+       if (is_dir_sep(*p)) {
+               if (!p[1] || (is_dir_sep(p[1]) && !p[2]))
+                       return path;
+               slash = ++p;
+       }
+       while ((c = *(p++)))
+               if (is_dir_sep(c)) {
+                       char *tentative = p - 1;
+
+                       /* POSIX.1-2001 says to ignore trailing slashes */
+                       while (is_dir_sep(*p))
+                               p++;
+                       if (*p)
+                               slash = tentative;
+               }
+
+       if (slash) {
+               *slash = '\0';
+               return path;
+       }
+
+dot:
+       strbuf_reset(&buf);
+       strbuf_addf(&buf, "%.*s.", dos_drive_prefix, path);
+       return buf.buf;
+}
index 38397d7afb76a6842453876c4eb00d7c11bcde34..1cc6de194d98481368edbbcaa64c47aa1d333963 100644 (file)
@@ -253,6 +253,8 @@ struct itimerval {
 #else
 #define basename gitbasename
 extern char *gitbasename(char *);
+#define dirname gitdirname
+extern char *gitdirname(char *);
 #endif
 
 #ifndef NO_ICONV