git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v15 03/16] quote.c: substitute path_relative with relative_path

From
Jiang Xin <worldhello.net@gmail.com>
Date
Jun 25, 2013, 15:53 UTC
Message-ID
<e1aa7e7d2e9ec1cd021ceffa7fd5cc4e858dd30b.1372175282.git.worldhello.net@gmail.com>
In-Reply-To
<cover.1372175282.git.worldhello.net@gmail.com>

Substitute the function path_relative in quote.c with the function relative_path. Function relative_path can be treated as an enhanced and 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 not panic, the callers of path_relative can handle such cases, or never encounter this issue at all. E.g.

 * 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 can 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 can not work properly either. But since prefix always has a trailing slash, so 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       ../../                   ./
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
---
 builtin/ls-files.c |  7 +++++--
 quote.c            | 55 ++----------------------------------------------------
 2 files changed, 7 insertions(+), 55 deletions(-)
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 3a410c..d100 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -48,8 +48,11 @@ static const char *tag_resolve_undo = "";
 
 static void write_name(const char* name, size_t len)
 {
-	write_name_quoted_relative(name, len, prefix, prefix_len, stdout,
-			line_terminator);
+	/* Since prefix_len is ignored in write_name_quoted_relative, we
+	 * should turn off prefix here in case of running "git ls-files"
+	 * with "--full-name" option */
+	write_name_quoted_relative(name, len, prefix_len ? prefix : NULL,
+			prefix_len, stdout, line_terminator);
 }
 
 static void show_dir_entry(const char *tag, struct dir_entry *ent)
diff --git a/quote.c b/quote.c
index 91122..64ff3 100644
--- a/quote.c
+++ b/quote.c
@@ -312,75 +312,24 @@ void write_name_quotedpfx(const char *pfx, size_t pfxlen,
 	fputc(terminator, fp);
 }
 
-static const char *path_relative(const char *in, int len,
-				 struct strbuf *sb, const char *prefix,
-				 int prefix_len);
-
 void write_name_quoted_relative(const char *name, size_t len,
 				const char *prefix, size_t prefix_len,
 				FILE *fp, int terminator)
 {
 	struct strbuf sb = STRBUF_INIT;
 
-	name = path_relative(name, len, &sb, prefix, prefix_len);
+	name = relative_path(name, prefix, &sb);
 	write_name_quoted(name, fp, terminator);
 
 	strbuf_release(&sb);
 }
 
-/*
- * Give path as relative to prefix.
- *
- * The strbuf may or may not be used, so do not assume it contains the
- * returned path.
- */
-static const char *path_relative(const char *in, int len,
-				 struct strbuf *sb, const char *prefix,
-				 int prefix_len)
-{
-	int off, i;
-
-	if (len < 0)
-		len = strlen(in);
-	if (prefix_len < 0) {
-		if (prefix)
-			prefix_len = strlen(prefix);
-		else
-			prefix_len = 0;
-	}
-
-	off = 0;
-	i = 0;
-	while (i < prefix_len && i < len && prefix[i] == in[i]) {
-		if (prefix[i] == '/')
-			off = i + 1;
-		i++;
-	}
-	in += off;
-	len -= off;
-
-	if (i >= prefix_len)
-		return in;
-
-	strbuf_reset(sb);
-	strbuf_grow(sb, len);
-
-	while (i < prefix_len) {
-		if (prefix[i] == '/')
-			strbuf_addstr(sb, "../");
-		i++;
-	}
-	strbuf_add(sb, in, len);
-
-	return sb->buf;
-}
-
 /* quote path as relative to the given prefix */
 char *quote_path_relative(const char *in, int len,
 			  struct strbuf *out, const char *prefix)
 {
 	struct strbuf sb = STRBUF_INIT;
-	const char *rel = path_relative(in, len, &sb, prefix, -1);
+	const char *rel = relative_path(in, prefix, &sb);
 	strbuf_reset(out);
 	quote_c_style_counted(rel, strlen(rel), out, NULL, 0);
 	strbuf_release(&sb);
-- 
1.8.3.1.756.g2e9b71f
Previous: Jiang XinNext: Junio C Hamano
Message 8 of 25 in “Interactive git clean”
  1. 00/16 Interactive git cleanJiang Xin, Jun 25, 2013
  2. 01/16 test: add test cases for relative_pathJiang Xin, Jun 25, 2013
  3. Junio C HamanoJun 26, 2013
  4. Jiang XinJun 27, 2013
  5. 02/16 path.c: refactor relative_path(), not only strip prefixJiang Xin, Jun 25, 2013
  6. Junio C HamanoJun 26, 2013
  7. Jiang XinJun 27, 2013
  8. 03/16 quote.c: substitute path_relative with relative_pathJiang Xin, Jun 25, 2013
  9. Junio C HamanoJun 26, 2013
  10. 04/16 Refactor quote_path_relative, remove unused paramsJiang Xin, Jun 25, 2013
  11. Junio C HamanoJun 26, 2013
  12. Jiang XinJun 27, 2013
  13. 05/16 Refactor write_name_quoted_relative, remove unused paramsJiang Xin, Jun 25, 2013
  14. 06/16 git-clean: refactor git-clean into two phasesJiang Xin, Jun 25, 2013
  15. 07/16 git-clean: add support for -i/--interactiveJiang Xin, Jun 25, 2013
  16. 08/16 git-clean: show items of del_list in columnsJiang Xin, Jun 25, 2013
  17. 09/16 git-clean: add colors to interactive git-cleanJiang Xin, Jun 25, 2013
  18. 10/16 git-clean: use a git-add-interactive compatible UIJiang Xin, Jun 25, 2013
  19. 11/16 git-clean: add filter by pattern interactive actionJiang Xin, Jun 25, 2013
  20. 12/16 git-clean: add select by numbers interactive actionJiang Xin, Jun 25, 2013
  21. 13/16 git-clean: add ask each interactive actionJiang Xin, Jun 25, 2013
  22. 14/16 git-clean: add documentation for interactive git-cleanJiang Xin, Jun 25, 2013
  23. 15/16 test: add t7301 for git-clean--interactiveJiang Xin, Jun 25, 2013
  24. 16/16 test: run testcases with POSIX absolute paths on WindowsJiang Xin, Jun 25, 2013
  25. Junio C HamanoJun 26, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.