Thread (1 message) 1 message, 1 author, 2016-06-15

Re: [PATCH v2 3/4] Provide a dirname() function when NO_LIBGEN_H=YesPlease

From: Junio C Hamano <hidden>
Date: 2016-06-15 23:07:40

Johannes Schindelin [off-list ref] writes:
quoted hunk
When there is no `libgen.h` to our disposal, we miss the `dirname()`
function.

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 <redacted>
---
 compat/basename.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
 git-compat-util.h |  2 ++
 2 files changed, 46 insertions(+)
diff --git a/compat/basename.c b/compat/basename.c
index 0f1b0b0..0a2ed25 100644
--- a/compat/basename.c
+++ b/compat/basename.c
@@ -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)
+{
+	char *p = path, *slash = NULL, c;
+	int dos_drive_prefix;
+
+	if (!p)
+		return ".";
+
+	if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p) {
+		static struct strbuf buf = STRBUF_INIT;
+
+dot:
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%.*s.", dos_drive_prefix, path);
OK, so "Z:" becomes "Z:." (I missed the final '.' in my first reading),
which sounds sensible.
+		return buf.buf;
+	}
+
+	/*
+	 * 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;
+		}
OK, so we find the first slash in a run of slashes, unless that run
of slashes is at the very end of the path.  Either slash is left NUL
(when there is no dir-sep) in which case we want to say "current
directory", or that slash is at the end of the directory name we
want to return in which case we just stuff NUL and return the path.

Sounds sensible.
+
+	if (!slash)
+		goto dot;
;-) this is tricky.  I wondered what the value of dos_drive_prefix
at this point in my first reading, but this is correct.  We must
have done the skip_dos_drive_prefix() thing when we came into the
function already, so it is either 2 (when the original had Z: in
front) or 0 (for all other cases).

OK.
quoted hunk
+	*slash = '\0';
+	return path;
+}
diff --git a/git-compat-util.h b/git-compat-util.h
index 0d66f3a..94f311a 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help