Skip to content

Commit 055ba7e

Browse files
committed
Merge branch 'libgen-win'
This topic branch squashes the annoying compiler warning claiming that `dirname()` was not declared. For some strange reason, changing `basename()` to conform to POSIX does not re-introduce #494. This developer assumes that the problem in the test suite were somehow fixed in the meantime, but lacks the time to verify that claim... Signed-off-by: Johannes Schindelin <[email protected]>
2 parents 5949708 + 662c605 commit 055ba7e

File tree

7 files changed

+261
-24
lines changed

7 files changed

+261
-24
lines changed

compat/basename.c

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,71 @@
11
#include "../git-compat-util.h"
2+
#include "../strbuf.h"
23

34
/* Adapted from libiberty's basename.c. */
45
char *gitbasename (char *path)
56
{
67
const char *base;
7-
/* Skip over the disk name in MSDOS pathnames. */
8-
if (has_dos_drive_prefix(path))
9-
path += 2;
8+
9+
if (path)
10+
skip_dos_drive_prefix(&path);
11+
12+
if (!path || !*path)
13+
return ".";
14+
1015
for (base = path; *path; path++) {
11-
if (is_dir_sep(*path))
12-
base = path + 1;
16+
if (!is_dir_sep(*path))
17+
continue;
18+
do {
19+
path++;
20+
} while (is_dir_sep(*path));
21+
if (*path)
22+
base = path;
23+
else
24+
while (--path != base && is_dir_sep(*path))
25+
*path = '\0';
1326
}
1427
return (char *)base;
1528
}
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+
}

compat/mingw.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2439,26 +2439,22 @@ pid_t waitpid(pid_t pid, int *status, int options)
24392439

24402440
int mingw_offset_1st_component(const char *path)
24412441
{
2442-
int offset = 0;
2443-
if (has_dos_drive_prefix(path))
2444-
offset = 2;
2442+
char *pos = (char *)path;
24452443

24462444
/* unc paths */
2447-
else if (is_dir_sep(path[0]) && is_dir_sep(path[1])) {
2448-
2445+
if (!skip_dos_drive_prefix(&pos) &&
2446+
is_dir_sep(pos[0]) && is_dir_sep(pos[1])) {
24492447
/* skip server name */
2450-
char *pos = strpbrk(path + 2, "\\/");
2448+
pos = strpbrk(pos + 2, "\\/");
24512449
if (!pos)
24522450
return 0; /* Error: malformed unc path */
24532451

24542452
do {
24552453
pos++;
24562454
} while (*pos && !is_dir_sep(*pos));
2457-
2458-
offset = pos - path;
24592455
}
24602456

2461-
return offset + is_dir_sep(path[offset]);
2457+
return pos + is_dir_sep(*pos) - path;
24622458
}
24632459

24642460
int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)

compat/mingw.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,15 @@ HANDLE winansi_get_osfhandle(int fd);
419419
* git specific compatibility
420420
*/
421421

422-
#define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':')
422+
#define has_dos_drive_prefix(path) \
423+
(isalpha(*(path)) && (path)[1] == ':' ? 2 : 0)
424+
static inline int mingw_skip_dos_drive_prefix(char **path)
425+
{
426+
int ret = has_dos_drive_prefix(*path);
427+
*path += ret;
428+
return ret;
429+
}
430+
#define skip_dos_drive_prefix mingw_skip_dos_drive_prefix
423431
#define is_dir_sep(c) ((c) == '/' || (c) == '\\')
424432
static inline char *mingw_find_last_dir_sep(const char *path)
425433
{

git-compat-util.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ struct itimerval {
255255
#else
256256
#define basename gitbasename
257257
extern char *gitbasename(char *);
258+
#define dirname gitdirname
259+
extern char *gitdirname(char *);
258260
#endif
259261

260262
#ifndef NO_ICONV
@@ -337,6 +339,14 @@ static inline int git_has_dos_drive_prefix(const char *path)
337339
#define has_dos_drive_prefix git_has_dos_drive_prefix
338340
#endif
339341

342+
#ifndef skip_dos_drive_prefix
343+
static inline int git_skip_dos_drive_prefix(const char **path)
344+
{
345+
return 0;
346+
}
347+
#define skip_dos_drive_prefix git_skip_dos_drive_prefix
348+
#endif
349+
340350
#ifndef is_dir_sep
341351
static inline int git_is_dir_sep(int c)
342352
{

path.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -787,13 +787,10 @@ const char *relative_path(const char *in, const char *prefix,
787787
else if (!prefix_len)
788788
return in;
789789

790-
if (have_same_root(in, prefix)) {
790+
if (have_same_root(in, prefix))
791791
/* bypass dos_drive, for "c:" is identical to "C:" */
792-
if (has_dos_drive_prefix(in)) {
793-
i = 2;
794-
j = 2;
795-
}
796-
} else {
792+
i = j = has_dos_drive_prefix(in);
793+
else {
797794
return in;
798795
}
799796

@@ -948,11 +945,10 @@ const char *remove_leading_path(const char *in, const char *prefix)
948945
int normalize_path_copy_len(char *dst, const char *src, int *prefix_len)
949946
{
950947
char *dst0;
948+
int i;
951949

952-
if (has_dos_drive_prefix(src)) {
950+
for (i = has_dos_drive_prefix(src); i > 0; i--)
953951
*dst++ = *src++;
954-
*dst++ = *src++;
955-
}
956952
dst0 = dst;
957953

958954
if (is_dir_sep(*src)) {

t/t0060-path-utils.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ case $(uname -s) in
6868
;;
6969
esac
7070

71+
test_expect_success basename 'test-path-utils basename'
72+
test_expect_success dirname 'test-path-utils dirname'
73+
7174
norm_path "" ""
7275
norm_path . ""
7376
norm_path ./ ""

test-path-utils.c

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,168 @@ static void normalize_argv_string(const char **var, const char *input)
3939
die("Bad value: %s\n", input);
4040
}
4141

42+
struct test_data {
43+
char *from; /* input: transform from this ... */
44+
char *to; /* output: ... to this. */
45+
};
46+
47+
static int test_function(struct test_data *data, char *(*func)(char *input),
48+
const char *funcname)
49+
{
50+
int failed = 0, i;
51+
static char buffer[1024];
52+
char *to;
53+
54+
for (i = 0; data[i].to; i++) {
55+
if (!data[i].from)
56+
to = func(NULL);
57+
else {
58+
strcpy(buffer, data[i].from);
59+
to = func(buffer);
60+
}
61+
if (strcmp(to, data[i].to)) {
62+
error("FAIL: %s(%s) => '%s' != '%s'\n",
63+
funcname, data[i].from, to, data[i].to);
64+
failed++;
65+
}
66+
}
67+
return !!failed;
68+
}
69+
70+
static struct test_data basename_data[] = {
71+
/* --- POSIX type paths --- */
72+
{ NULL, "." },
73+
{ "", "." },
74+
{ ".", "." },
75+
{ "..", ".." },
76+
{ "/", "/" },
77+
#if defined(__CYGWIN__) && !defined(NO_LIBGEN_H)
78+
{ "//", "//" },
79+
{ "///", "//" },
80+
{ "////", "//" },
81+
#else
82+
{ "//", "/" },
83+
{ "///", "/" },
84+
{ "////", "/" },
85+
#endif
86+
{ "usr", "usr" },
87+
{ "/usr", "usr" },
88+
{ "/usr/", "usr" },
89+
{ "/usr//", "usr" },
90+
{ "/usr/lib", "lib" },
91+
{ "usr/lib", "lib" },
92+
{ "usr/lib///", "lib" },
93+
94+
#if defined(__MINGW32__) || defined(_MSC_VER)
95+
96+
/* --- win32 type paths --- */
97+
{ "\\usr", "usr" },
98+
{ "\\usr\\", "usr" },
99+
{ "\\usr\\\\", "usr" },
100+
{ "\\usr\\lib", "lib" },
101+
{ "usr\\lib", "lib" },
102+
{ "usr\\lib\\\\\\", "lib" },
103+
{ "C:/usr", "usr" },
104+
{ "C:/usr", "usr" },
105+
{ "C:/usr/", "usr" },
106+
{ "C:/usr//", "usr" },
107+
{ "C:/usr/lib", "lib" },
108+
{ "C:usr/lib", "lib" },
109+
{ "C:usr/lib///", "lib" },
110+
{ "C:", "." },
111+
{ "C:a", "a" },
112+
{ "C:/", "/" },
113+
{ "C:///", "/" },
114+
#if defined(NO_LIBGEN_H)
115+
{ "\\", "\\" },
116+
{ "\\\\", "\\" },
117+
{ "\\\\\\", "\\" },
118+
#else
119+
120+
/* win32 platform variations: */
121+
#if defined(__MINGW32__)
122+
{ "\\", "/" },
123+
{ "\\\\", "/" },
124+
{ "\\\\\\", "/" },
125+
#endif
126+
127+
#if defined(_MSC_VER)
128+
{ "\\", "\\" },
129+
{ "\\\\", "\\" },
130+
{ "\\\\\\", "\\" },
131+
#endif
132+
133+
#endif
134+
#endif
135+
{ NULL, "." },
136+
{ NULL, NULL }
137+
};
138+
139+
static struct test_data dirname_data[] = {
140+
/* --- POSIX type paths --- */
141+
{ NULL, "." },
142+
{ "", "." },
143+
{ ".", "." },
144+
{ "..", "." },
145+
{ "/", "/" },
146+
{ "//", "//" },
147+
#if defined(__CYGWIN__) && !defined(NO_LIBGEN_H)
148+
{ "///", "//" },
149+
{ "////", "//" },
150+
#else
151+
{ "///", "/" },
152+
{ "////", "/" },
153+
#endif
154+
{ "usr", "." },
155+
{ "/usr", "/" },
156+
{ "/usr/", "/" },
157+
{ "/usr//", "/" },
158+
{ "/usr/lib", "/usr" },
159+
{ "usr/lib", "usr" },
160+
{ "usr/lib///", "usr" },
161+
162+
#if defined(__MINGW32__) || defined(_MSC_VER)
163+
164+
/* --- win32 type paths --- */
165+
{ "\\", "\\" },
166+
{ "\\\\", "\\\\" },
167+
{ "\\usr", "\\" },
168+
{ "\\usr\\", "\\" },
169+
{ "\\usr\\\\", "\\" },
170+
{ "\\usr\\lib", "\\usr" },
171+
{ "usr\\lib", "usr" },
172+
{ "usr\\lib\\\\\\", "usr" },
173+
{ "C:a", "C:." },
174+
{ "C:/", "C:/" },
175+
{ "C:///", "C:/" },
176+
{ "C:/usr", "C:/" },
177+
{ "C:/usr/", "C:/" },
178+
{ "C:/usr//", "C:/" },
179+
{ "C:/usr/lib", "C:/usr" },
180+
{ "C:usr/lib", "C:usr" },
181+
{ "C:usr/lib///", "C:usr" },
182+
{ "\\\\\\", "\\" },
183+
{ "\\\\\\\\", "\\" },
184+
#if defined(NO_LIBGEN_H)
185+
{ "C:", "C:." },
186+
#else
187+
188+
/* win32 platform variations: */
189+
#if defined(__MINGW32__)
190+
/* the following is clearly wrong ... */
191+
{ "C:", "." },
192+
#endif
193+
194+
#if defined(_MSC_VER)
195+
{ "C:", "C:." },
196+
#endif
197+
198+
#endif
199+
#endif
200+
{ NULL, "." },
201+
{ NULL, NULL }
202+
};
203+
42204
int main(int argc, char **argv)
43205
{
44206
if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
@@ -133,6 +295,12 @@ int main(int argc, char **argv)
133295
return 0;
134296
}
135297

298+
if (argc == 2 && !strcmp(argv[1], "basename"))
299+
return test_function(basename_data, basename, argv[1]);
300+
301+
if (argc == 2 && !strcmp(argv[1], "dirname"))
302+
return test_function(dirname_data, dirname, argv[1]);
303+
136304
fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
137305
argv[1] ? argv[1] : "(there was none)");
138306
return 1;

0 commit comments

Comments
 (0)