diff mbox series

[v3,3/7] win32: override `fspathcmp()` with a directory separator-aware version

Message ID f46315ac0b24879283846682878139641203d4ae.1720904905.git.gitgitgadget@gmail.com (mailing list archive)
State Accepted
Commit 193eda7507d0ccb2fe6fd42b403c56ecc205e546
Headers show
Series var(win32): do report the GIT_SHELL_PATH that is actually used | expand

Commit Message

Johannes Schindelin July 13, 2024, 9:08 p.m. UTC
From: Johannes Schindelin <johannes.schindelin@gmx.de>

On Windows, the backslash is the directory separator, even if the
forward slash can be used, too, at least since Windows NT.

This means that the paths `a/b` and `a\b` are equivalent, and
`fspathcmp()` needs to be made aware of that fact.

Note that we have to override both `fspathcmp()` and `fspathncmp()`, and
the former cannot be a mere pre-processor constant that transforms calls
to `fspathcmp(a, b)` into `fspathncmp(a, b, (size_t)-1)` because the
function `report_collided_checkout()` in `unpack-trees.c` wants to
assign `list.cmp = fspathcmp`.

Also note that `fspatheq()` does _not_ need to be overridden because it
calls `fspathcmp()` internally.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/win32/path-utils.c | 37 +++++++++++++++++++++++++++++++++++++
 compat/win32/path-utils.h |  4 ++++
 dir.c                     |  4 ++--
 dir.h                     |  4 ++--
 git-compat-util.h         |  8 ++++++++
 5 files changed, 53 insertions(+), 4 deletions(-)
diff mbox series

Patch

diff --git a/compat/win32/path-utils.c b/compat/win32/path-utils.c
index ebf2f12eb66..b658ca3f811 100644
--- a/compat/win32/path-utils.c
+++ b/compat/win32/path-utils.c
@@ -1,4 +1,5 @@ 
 #include "../../git-compat-util.h"
+#include "../../environment.h"
 
 int win32_has_dos_drive_prefix(const char *path)
 {
@@ -50,3 +51,39 @@  int win32_offset_1st_component(const char *path)
 
 	return pos + is_dir_sep(*pos) - path;
 }
+
+int win32_fspathncmp(const char *a, const char *b, size_t count)
+{
+	int diff;
+
+	for (;;) {
+		if (!count--)
+			return 0;
+		if (!*a)
+			return *b ? -1 : 0;
+		if (!*b)
+			return +1;
+
+		if (is_dir_sep(*a)) {
+			if (!is_dir_sep(*b))
+				return -1;
+			a++;
+			b++;
+			continue;
+		} else if (is_dir_sep(*b))
+			return +1;
+
+		diff = ignore_case ?
+			(unsigned char)tolower(*a) - (int)(unsigned char)tolower(*b) :
+			(unsigned char)*a - (int)(unsigned char)*b;
+		if (diff)
+			return diff;
+		a++;
+		b++;
+	}
+}
+
+int win32_fspathcmp(const char *a, const char *b)
+{
+	return win32_fspathncmp(a, b, (size_t)-1);
+}
diff --git a/compat/win32/path-utils.h b/compat/win32/path-utils.h
index 65fa3b9263a..a561c700e75 100644
--- a/compat/win32/path-utils.h
+++ b/compat/win32/path-utils.h
@@ -29,5 +29,9 @@  static inline int win32_has_dir_sep(const char *path)
 #define has_dir_sep(path) win32_has_dir_sep(path)
 int win32_offset_1st_component(const char *path);
 #define offset_1st_component win32_offset_1st_component
+int win32_fspathcmp(const char *a, const char *b);
+#define fspathcmp win32_fspathcmp
+int win32_fspathncmp(const char *a, const char *b, size_t count);
+#define fspathncmp win32_fspathncmp
 
 #endif
diff --git a/dir.c b/dir.c
index b7a6625ebda..5a23376bdae 100644
--- a/dir.c
+++ b/dir.c
@@ -95,7 +95,7 @@  int count_slashes(const char *s)
 	return cnt;
 }
 
-int fspathcmp(const char *a, const char *b)
+int git_fspathcmp(const char *a, const char *b)
 {
 	return ignore_case ? strcasecmp(a, b) : strcmp(a, b);
 }
@@ -105,7 +105,7 @@  int fspatheq(const char *a, const char *b)
 	return !fspathcmp(a, b);
 }
 
-int fspathncmp(const char *a, const char *b, size_t count)
+int git_fspathncmp(const char *a, const char *b, size_t count)
 {
 	return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);
 }
diff --git a/dir.h b/dir.h
index 69a76d8bdd3..a3a2f00f5d9 100644
--- a/dir.h
+++ b/dir.h
@@ -541,9 +541,9 @@  int remove_dir_recursively(struct strbuf *path, int flag);
  */
 int remove_path(const char *path);
 
-int fspathcmp(const char *a, const char *b);
+int git_fspathcmp(const char *a, const char *b);
 int fspatheq(const char *a, const char *b);
-int fspathncmp(const char *a, const char *b, size_t count);
+int git_fspathncmp(const char *a, const char *b, size_t count);
 unsigned int fspathhash(const char *str);
 
 /*
diff --git a/git-compat-util.h b/git-compat-util.h
index ca7678a379d..71b4d23f038 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -506,6 +506,14 @@  static inline int git_offset_1st_component(const char *path)
 #define offset_1st_component git_offset_1st_component
 #endif
 
+#ifndef fspathcmp
+#define fspathcmp git_fspathcmp
+#endif
+
+#ifndef fspathncmp
+#define fspathncmp git_fspathncmp
+#endif
+
 #ifndef is_valid_path
 #define is_valid_path(path) 1
 #endif