compat/basename.c: provide a dirname() compatibility function

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>

Johannes Schindelin committed Jan 12, 2016 at 08:57 UTC 824682ab51e3510817f7a7303decc9f9df38ee9a
2 files changed +46
compat/basename.c
+44
@@ -1,4 +1,5 @@
1 #include "../git-compat-util.h"
2 +#include "../strbuf.h"
3
4 /* Adapted from libiberty's basename.c. */
5 char *gitbasename (char *path)
@@ -25,3 +26,46 @@ char *gitbasename (char *path)
26 }
27 return (char *)base;
28 }
29 +
30 +char *gitdirname(char *path)
31 +{
32 + static struct strbuf buf = STRBUF_INIT;
33 + char *p = path, *slash = NULL, c;
34 + int dos_drive_prefix;
35 +
36 + if (!p)
37 + return ".";
38 +
39 + if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p)
40 + goto dot;
41 +
42 + /*
43 + * POSIX.1-2001 says dirname("/") should return "/", and dirname("//")
44 + * should return "//", but dirname("///") should return "/" again.
45 + */
46 + if (is_dir_sep(*p)) {
47 + if (!p[1] || (is_dir_sep(p[1]) && !p[2]))
48 + return path;
49 + slash = ++p;
50 + }
51 + while ((c = *(p++)))
52 + if (is_dir_sep(c)) {
53 + char *tentative = p - 1;
54 +
55 + /* POSIX.1-2001 says to ignore trailing slashes */
56 + while (is_dir_sep(*p))
57 + p++;
58 + if (*p)
59 + slash = tentative;
60 + }
61 +
62 + if (slash) {
63 + *slash = '\0';
64 + return path;
65 + }
66 +
67 +dot:
68 + strbuf_reset(&buf);
69 + strbuf_addf(&buf, "%.*s.", dos_drive_prefix, path);
70 + return buf.buf;
71 +}
git-compat-util.h
+2
@@ -253,6 +253,8 @@ struct itimerval {
253 #else
254 #define basename gitbasename
255 extern char *gitbasename(char *);
256 +#define dirname gitdirname
257 +extern char *gitdirname(char *);
258 #endif
259
260 #ifndef NO_ICONV