Skip to content

Commit ad66df2

Browse files
jiangxingitster
authored andcommitted
quote.c: substitute path_relative with relative_path
Substitute the function path_relative in quote.c with the function relative_path. Function relative_path can be treated as an enhanced and more robust version of path_relative. Outputs of path_relative and it's replacement (relative_path) are the same for the following cases: path prefix output of path_relative output of relative_path ======== ========= ======================= ======================= /a/b/c/ /a/b/ c/ c/ /a/b/c /a/b/ c c /a/ /a/b/ ../ ../ / /a/b/ ../../ ../../ /a/c /a/b/ ../c ../c /x/y /a/b/ ../../x/y ../../x/y a/b/c/ a/b/ c/ c/ a/ a/b/ ../ ../ x/y a/b/ ../../x/y ../../x/y /a/b (empty) /a/b /a/b /a/b (null) /a/b /a/b a/b (empty) a/b a/b a/b (null) a/b a/b But if both of the path and the prefix are the same, or the returned relative path should be the current directory, the outputs of both functions are different. Function relative_path returns "./", while function path_relative returns empty string. path prefix output of path_relative output of relative_path ======== ========= ======================= ======================= /a/b/ /a/b/ (empty) ./ a/b/ a/b/ (empty) ./ (empty) (null) (empty) ./ (empty) (empty) (empty) ./ But the callers of path_relative can handle such cases, or never encounter this issue at all, because: * In function quote_path_relative, if the output of path_relative is empty, append "./" to it, like: if (!out->len) strbuf_addstr(out, "./"); * Another caller is write_name_quoted_relative, which is only used by builtin/ls-files.c. git-ls-files only show files, so path of files will never be identical with the prefix of a directory. The following differences show that path_relative does not handle extra slashes properly: path prefix output of path_relative output of relative_path ======== ========= ======================= ======================= /a//b//c/ //a/b// ../../../../a//b//c/ c/ a/b//c a//b ../b//c c And if prefix has no trailing slash, path_relative does not work properly either. But since prefix always has a trailing slash, it's not a problem. path prefix output of path_relative output of relative_path ======== ========= ======================= ======================= /a/b/c/ /a/b b/c/ c/ /a/b /a/b b ./ /a/b/ /a/b b/ ./ /a /a/b/ ../../a ../ a/b/c/ a/b b/c/ c/ a/b/ a/b b/ ./ a a/b ../a ../ x/y a/b/ ../x/y ../../x/y a/c a/b c ../c /a/ /a/b (empty) ../ (empty) /a/b ../../ ./ One tricky part in this conversion is write_name() function in ls-files.c. It takes a counted string, <name, len>, that is to be made relative to <prefix, prefix_len> and then quoted. Because write_name_quoted_relative() still takes these two parameters as counted string, but ignores the count and treat these two as NUL-terminated strings, this conversion needs to be audited for its callers: - For <name, len>, all three callers of write_name() passes a NUL-terminated string and its true length, so this patch makes "len" unused. - For <prefix, prefix_len>, prefix could be a string that is longer than empty while prefix_len could be 0 when "--full-name" option is used. This is fixed by checking prefix_len in write_name() and calling write_name_quoted_relative() with NULL when prefix_len is set to 0. Again, this makes "prefix_len" given to write_name_quoted_relative() unused, without introducing a bug. Signed-off-by: Jiang Xin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e02ca72 commit ad66df2

File tree

2 files changed

+9
-55
lines changed

2 files changed

+9
-55
lines changed

builtin/ls-files.c

+7-2
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,13 @@ static const char *tag_resolve_undo = "";
4848

4949
static void write_name(const char* name, size_t len)
5050
{
51-
write_name_quoted_relative(name, len, prefix, prefix_len, stdout,
52-
line_terminator);
51+
/*
52+
* With "--full-name", prefix_len=0; write_name_quoted_relative()
53+
* ignores prefix_len, so this caller needs to pass empty string
54+
* in that case (a NULL is good for "").
55+
*/
56+
write_name_quoted_relative(name, len, prefix_len ? prefix : NULL,
57+
prefix_len, stdout, line_terminator);
5358
}
5459

5560
static void show_dir_entry(const char *tag, struct dir_entry *ent)

quote.c

+2-53
Original file line numberDiff line numberDiff line change
@@ -312,75 +312,24 @@ void write_name_quotedpfx(const char *pfx, size_t pfxlen,
312312
fputc(terminator, fp);
313313
}
314314

315-
static const char *path_relative(const char *in, int len,
316-
struct strbuf *sb, const char *prefix,
317-
int prefix_len);
318-
319315
void write_name_quoted_relative(const char *name, size_t len,
320316
const char *prefix, size_t prefix_len,
321317
FILE *fp, int terminator)
322318
{
323319
struct strbuf sb = STRBUF_INIT;
324320

325-
name = path_relative(name, len, &sb, prefix, prefix_len);
321+
name = relative_path(name, prefix, &sb);
326322
write_name_quoted(name, fp, terminator);
327323

328324
strbuf_release(&sb);
329325
}
330326

331-
/*
332-
* Give path as relative to prefix.
333-
*
334-
* The strbuf may or may not be used, so do not assume it contains the
335-
* returned path.
336-
*/
337-
static const char *path_relative(const char *in, int len,
338-
struct strbuf *sb, const char *prefix,
339-
int prefix_len)
340-
{
341-
int off, i;
342-
343-
if (len < 0)
344-
len = strlen(in);
345-
if (prefix_len < 0) {
346-
if (prefix)
347-
prefix_len = strlen(prefix);
348-
else
349-
prefix_len = 0;
350-
}
351-
352-
off = 0;
353-
i = 0;
354-
while (i < prefix_len && i < len && prefix[i] == in[i]) {
355-
if (prefix[i] == '/')
356-
off = i + 1;
357-
i++;
358-
}
359-
in += off;
360-
len -= off;
361-
362-
if (i >= prefix_len)
363-
return in;
364-
365-
strbuf_reset(sb);
366-
strbuf_grow(sb, len);
367-
368-
while (i < prefix_len) {
369-
if (prefix[i] == '/')
370-
strbuf_addstr(sb, "../");
371-
i++;
372-
}
373-
strbuf_add(sb, in, len);
374-
375-
return sb->buf;
376-
}
377-
378327
/* quote path as relative to the given prefix */
379328
char *quote_path_relative(const char *in, int len,
380329
struct strbuf *out, const char *prefix)
381330
{
382331
struct strbuf sb = STRBUF_INIT;
383-
const char *rel = path_relative(in, len, &sb, prefix, -1);
332+
const char *rel = relative_path(in, prefix, &sb);
384333
strbuf_reset(out);
385334
quote_c_style_counted(rel, strlen(rel), out, NULL, 0);
386335
strbuf_release(&sb);

0 commit comments

Comments
 (0)