{"thread":{"id":"59685","subject":"[PATCH 0/6] strbuf cleanups","startedAt":"2023-05-02T21:15:22Z","lastAt":"2023-06-06T19:49:10Z","messageCount":85,"participants":["Calvin Wan","Junio C Hamano","Felipe Contreras","Elijah Newren","Jeff King","Eric Sunshine","Phillip Wood"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"476460","messageId":"20230502211454.1673000-1-calvinwan@google.com","threadId":"59685","inReplyTo":null,"subject":"[PATCH 0/6] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-02T21:14:48Z","receivedAt":"2023-05-02T21:15:22Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Strbuf is a basic structure that should function as a low-level library\ndue to how generic it is. Over time certain functions inside of\nstrbuf.[ch] have been added with dependencies to higher level objects\nand functions. This series cleans up some of those higher level\ndependencies by moving the offending functions to the files they\ninteract with. With the goal of eventually being able to stand up strbuf\nas a libary, this series also removes the use of environment variables\nfrom strbuf.\n\nCalvin Wan (6):\n  abspath: move related functions to abspath\n  credential-store: move related functions to credential-store file\n  object-name: move related functions to object-name\n  path: move related function to path\n  strbuf: clarify dependency\n  strbuf: remove environment variables\n\n abspath.c                  |  36 +++++++++++++\n abspath.h                  |  21 ++++++++\n add-patch.c                |  12 +++--\n builtin/am.c               |   2 +-\n builtin/branch.c           |   4 +-\n builtin/commit.c           |   2 +-\n builtin/credential-store.c |  19 +++++++\n builtin/merge.c            |  10 ++--\n builtin/notes.c            |  16 +++---\n builtin/rebase.c           |   2 +-\n builtin/stripspace.c       |   6 ++-\n builtin/tag.c              |   9 ++--\n fmt-merge-msg.c            |   9 ++--\n gpg-interface.c            |   5 +-\n hook.c                     |   1 +\n object-name.c              |  15 ++++++\n object-name.h              |   9 ++++\n path.c                     |  20 +++++++\n path.h                     |   5 ++\n pretty.c                   |   1 +\n rebase-interactive.c       |  15 +++---\n sequencer.c                |  24 +++++----\n strbuf.c                   | 106 +++----------------------------------\n strbuf.h                   |  44 ++-------------\n tempfile.c                 |   1 +\n wt-status.c                |   6 +--\n 26 files changed, 213 insertions(+), 187 deletions(-)\n\n-- \n2.40.1.495.gc816e09b53d-goog\n\n"},{"id":"476462","messageId":"20230502211454.1673000-2-calvinwan@google.com","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"[PATCH 1/6] abspath: move related functions to abspath","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-02T21:14:49Z","receivedAt":"2023-05-02T21:15:23Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move abspath-related functions from strbuf.[ch] to abspath.[ch] since\nthey do not belong in a low-level library.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n abspath.c  | 36 ++++++++++++++++++++++++++++++++++++\n abspath.h  | 21 +++++++++++++++++++++\n hook.c     |  1 +\n strbuf.c   | 37 -------------------------------------\n strbuf.h   | 22 ----------------------\n tempfile.c |  1 +\n 6 files changed, 59 insertions(+), 59 deletions(-)\n\ndiff --git a/abspath.c b/abspath.c\nindex d032f5dce5..1202cde23d 100644\n--- a/abspath.c\n+++ b/abspath.c\n@@ -289,3 +289,39 @@ char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n \t\treturn xstrdup(arg);\n \treturn prefix_filename(pfx, arg);\n }\n+\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n+{\n+\tif (!*path)\n+\t\tdie(\"The empty string is not a valid path\");\n+\tif (!is_absolute_path(path)) {\n+\t\tstruct stat cwd_stat, pwd_stat;\n+\t\tsize_t orig_len = sb->len;\n+\t\tchar *cwd = xgetcwd();\n+\t\tchar *pwd = getenv(\"PWD\");\n+\t\tif (pwd && strcmp(pwd, cwd) &&\n+\t\t    !stat(cwd, &cwd_stat) &&\n+\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n+\t\t    !stat(pwd, &pwd_stat) &&\n+\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n+\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n+\t\t\tstrbuf_addstr(sb, pwd);\n+\t\telse\n+\t\t\tstrbuf_addstr(sb, cwd);\n+\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n+\t\t\tstrbuf_addch(sb, '/');\n+\t\tfree(cwd);\n+\t}\n+\tstrbuf_addstr(sb, path);\n+}\n+\n+void strbuf_add_real_path(struct strbuf *sb, const char *path)\n+{\n+\tif (sb->len) {\n+\t\tstruct strbuf resolved = STRBUF_INIT;\n+\t\tstrbuf_realpath(&resolved, path, 1);\n+\t\tstrbuf_addbuf(sb, &resolved);\n+\t\tstrbuf_release(&resolved);\n+\t} else\n+\t\tstrbuf_realpath(sb, path, 1);\n+}\ndiff --git a/abspath.h b/abspath.h\nindex 7cd3de5e9d..4653080d5e 100644\n--- a/abspath.h\n+++ b/abspath.h\n@@ -30,4 +30,25 @@ static inline int is_absolute_path(const char *path)\n \treturn is_dir_sep(path[0]) || has_dos_drive_prefix(path);\n }\n \n+/**\n+ * Add a path to a buffer, converting a relative path to an\n+ * absolute one in the process.  Symbolic links are not\n+ * resolved.\n+ */\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n+\n+/**\n+ * Canonize `path` (make it absolute, resolve symlinks, remove extra\n+ * slashes) and append it to `sb`.  Die with an informative error\n+ * message if there is a problem.\n+ *\n+ * The directory part of `path` (i.e., everything up to the last\n+ * dir_sep) must denote a valid, existing directory, but the last\n+ * component need not exist.\n+ *\n+ * Callers that don't mind links should use the more lightweight\n+ * strbuf_add_absolute_path() instead.\n+ */\n+void strbuf_add_real_path(struct strbuf *sb, const char *path);\n+\n #endif /* ABSPATH_H */\ndiff --git a/hook.c b/hook.c\nindex 76e322f580..2d8706371e 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -1,4 +1,5 @@\n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hook.h\"\ndiff --git a/strbuf.c b/strbuf.c\nindex 729378ec82..c3b6d48797 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,5 +1,4 @@\n #include \"git-compat-util.h\"\n-#include \"abspath.h\"\n #include \"alloc.h\"\n #include \"environment.h\"\n #include \"gettext.h\"\n@@ -899,42 +898,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)\n \tstrbuf_humanise(buf, bytes, 1);\n }\n \n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n-{\n-\tif (!*path)\n-\t\tdie(\"The empty string is not a valid path\");\n-\tif (!is_absolute_path(path)) {\n-\t\tstruct stat cwd_stat, pwd_stat;\n-\t\tsize_t orig_len = sb->len;\n-\t\tchar *cwd = xgetcwd();\n-\t\tchar *pwd = getenv(\"PWD\");\n-\t\tif (pwd && strcmp(pwd, cwd) &&\n-\t\t    !stat(cwd, &cwd_stat) &&\n-\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n-\t\t    !stat(pwd, &pwd_stat) &&\n-\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n-\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n-\t\t\tstrbuf_addstr(sb, pwd);\n-\t\telse\n-\t\t\tstrbuf_addstr(sb, cwd);\n-\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n-\t\t\tstrbuf_addch(sb, '/');\n-\t\tfree(cwd);\n-\t}\n-\tstrbuf_addstr(sb, path);\n-}\n-\n-void strbuf_add_real_path(struct strbuf *sb, const char *path)\n-{\n-\tif (sb->len) {\n-\t\tstruct strbuf resolved = STRBUF_INIT;\n-\t\tstrbuf_realpath(&resolved, path, 1);\n-\t\tstrbuf_addbuf(sb, &resolved);\n-\t\tstrbuf_release(&resolved);\n-\t} else\n-\t\tstrbuf_realpath(sb, path, 1);\n-}\n-\n int printf_ln(const char *fmt, ...)\n {\n \tint ret;\ndiff --git a/strbuf.h b/strbuf.h\nindex 3dfeadb44c..6b4ad63266 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -527,28 +527,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);\n  */\n int strbuf_getcwd(struct strbuf *sb);\n \n-/**\n- * Add a path to a buffer, converting a relative path to an\n- * absolute one in the process.  Symbolic links are not\n- * resolved.\n- */\n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n-\n-/**\n- * Canonize `path` (make it absolute, resolve symlinks, remove extra\n- * slashes) and append it to `sb`.  Die with an informative error\n- * message if there is a problem.\n- *\n- * The directory part of `path` (i.e., everything up to the last\n- * dir_sep) must denote a valid, existing directory, but the last\n- * component need not exist.\n- *\n- * Callers that don't mind links should use the more lightweight\n- * strbuf_add_absolute_path() instead.\n- */\n-void strbuf_add_real_path(struct strbuf *sb, const char *path);\n-\n-\n /**\n  * Normalize in-place the path contained in the strbuf. See\n  * normalize_path_copy() for details. If an error occurs, the contents of \"sb\"\ndiff --git a/tempfile.c b/tempfile.c\nindex 50c377134c..6c88a63b42 100644\n--- a/tempfile.c\n+++ b/tempfile.c\n@@ -43,6 +43,7 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"path.h\"\n #include \"tempfile.h\"\n #include \"sigchain.h\"\n-- \n2.40.1.495.gc816e09b53d-goog\n\n"},{"id":"476461","messageId":"20230502211454.1673000-3-calvinwan@google.com","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"[PATCH 2/6] credential-store: move related functions to credential-store file","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-02T21:14:50Z","receivedAt":"2023-05-02T21:15:24Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"is_rfc3986_unreserved() and is_rfc3986_reserved_or_unreserved() are only\ncalled from builtin/credential-store.c and they are only relevant to that\nfile so move those functions and make them static.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n builtin/credential-store.c | 19 +++++++++++++++++++\n strbuf.c                   | 19 -------------------\n strbuf.h                   |  3 ---\n 3 files changed, 19 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/credential-store.c b/builtin/credential-store.c\nindex 8977604eb9..4776118331 100644\n--- a/builtin/credential-store.c\n+++ b/builtin/credential-store.c\n@@ -73,6 +73,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,\n \t\tdie_errno(\"unable to write credential store\");\n }\n \n+static int is_rfc3986_unreserved(char ch)\n+{\n+\treturn isalnum(ch) ||\n+\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n+}\n+\n+static int is_rfc3986_reserved_or_unreserved(char ch)\n+{\n+\tif (is_rfc3986_unreserved(ch))\n+\t\treturn 1;\n+\tswitch (ch) {\n+\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n+\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n+\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static void store_credential_file(const char *fn, struct credential *c)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/strbuf.c b/strbuf.c\nindex c3b6d48797..da2693b21f 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -809,25 +809,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)\n \t}\n }\n \n-int is_rfc3986_reserved_or_unreserved(char ch)\n-{\n-\tif (is_rfc3986_unreserved(ch))\n-\t\treturn 1;\n-\tswitch (ch) {\n-\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n-\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n-\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-int is_rfc3986_unreserved(char ch)\n-{\n-\treturn isalnum(ch) ||\n-\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n-}\n-\n static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,\n \t\t\t\t char_predicate allow_unencoded_fn)\n {\ndiff --git a/strbuf.h b/strbuf.h\nindex 6b4ad63266..1a4c07a053 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -682,9 +682,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);\n \n typedef int (*char_predicate)(char ch);\n \n-int is_rfc3986_unreserved(char ch);\n-int is_rfc3986_reserved_or_unreserved(char ch);\n-\n void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,\n \t\t\t     char_predicate allow_unencoded_fn);\n \n-- \n2.40.1.495.gc816e09b53d-goog\n\n"},{"id":"476463","messageId":"20230502211454.1673000-4-calvinwan@google.com","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"[PATCH 3/6] object-name: move related functions to object-name","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-02T21:14:51Z","receivedAt":"2023-05-02T21:15:27Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move object-name-related functions from strbuf.[ch] to object-name.[ch]\nsince they do not belong in a low-level library.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n object-name.c | 15 +++++++++++++++\n object-name.h |  9 +++++++++\n pretty.c      |  1 +\n strbuf.c      | 16 ----------------\n strbuf.h      | 10 ----------\n 5 files changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 538e8a8f62..c2e82aceea 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -766,6 +766,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n \t\tfind_abbrev_len_for_pack(p, mad);\n }\n \n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len)\n+{\n+\tint r;\n+\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n+\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n+\tstrbuf_setlen(sb, sb->len + r);\n+}\n+\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len)\n+{\n+\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n+}\n+\n int repo_find_unique_abbrev_r(struct repository *r, char *hex,\n \t\t\t      const struct object_id *oid, int len)\n {\ndiff --git a/object-name.h b/object-name.h\nindex 1d63698f42..9ae5223071 100644\n--- a/object-name.h\n+++ b/object-name.h\n@@ -40,6 +40,15 @@ struct object_context {\n const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);\n int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);\n \n+/**\n+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n+ * the strbuf `sb`.\n+ */\n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len);\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len);\n+\n int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);\n __attribute__((format (printf, 2, 3)))\n int get_oidf(struct object_id *oid, const char *fmt, ...);\ndiff --git a/pretty.c b/pretty.c\nindex 0bb938021b..78bac2d818 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -18,6 +18,7 @@\n #include \"gpg-interface.h\"\n #include \"trailer.h\"\n #include \"run-command.h\"\n+#include \"object-name.h\"\n \n /*\n  * The limit for formatting directives, which enable the caller to append\ndiff --git a/strbuf.c b/strbuf.c\nindex da2693b21f..6533559e95 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,6 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"object-name.h\"\n #include \"refs.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n@@ -1023,21 +1022,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,\n \tstrbuf_setlen(sb, sb->len + len);\n }\n \n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len)\n-{\n-\tint r;\n-\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n-\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n-\tstrbuf_setlen(sb, sb->len + r);\n-}\n-\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len)\n-{\n-\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n-}\n-\n /*\n  * Returns the length of a line, without trailing spaces.\n  *\ndiff --git a/strbuf.h b/strbuf.h\nindex 1a4c07a053..b6d53c1cbe 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -608,16 +608,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,\n  */\n void strbuf_list_free(struct strbuf **list);\n \n-/**\n- * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n- * the strbuf `sb`.\n- */\n-struct repository;\n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len);\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len);\n-\n /*\n  * Remove the filename from the provided path string. If the path\n  * contains a trailing separator, then the path is considered a directory\n-- \n2.40.1.495.gc816e09b53d-goog\n\n"},{"id":"476464","messageId":"20230502211454.1673000-5-calvinwan@google.com","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"[PATCH 4/6] path: move related function to path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-02T21:14:52Z","receivedAt":"2023-05-02T21:15:28Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move path-related function from strbuf.[ch] to path.[ch] since it does\nnot belong in a low-level library.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n path.c   | 20 ++++++++++++++++++++\n path.h   |  5 +++++\n strbuf.c | 20 --------------------\n 3 files changed, 25 insertions(+), 20 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 7c1cd8182a..e17a2613c5 100644\n--- a/path.c\n+++ b/path.c\n@@ -1213,6 +1213,26 @@ int normalize_path_copy(char *dst, const char *src)\n \treturn normalize_path_copy_len(dst, src, NULL);\n }\n \n+int strbuf_normalize_path(struct strbuf *src)\n+{\n+\tstruct strbuf dst = STRBUF_INIT;\n+\n+\tstrbuf_grow(&dst, src->len);\n+\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n+\t\tstrbuf_release(&dst);\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * normalize_path does not tell us the new length, so we have to\n+\t * compute it by looking for the new NUL it placed\n+\t */\n+\tstrbuf_setlen(&dst, strlen(dst.buf));\n+\tstrbuf_swap(src, &dst);\n+\tstrbuf_release(&dst);\n+\treturn 0;\n+}\n+\n /*\n  * path = Canonical absolute path\n  * prefixes = string_list containing normalized, absolute paths without\ndiff --git a/path.h b/path.h\nindex 60e83a49a9..639372edd9 100644\n--- a/path.h\n+++ b/path.h\n@@ -191,6 +191,11 @@ const char *remove_leading_path(const char *in, const char *prefix);\n const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);\n int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);\n int normalize_path_copy(char *dst, const char *src);\n+/**\n+ * Normalize in-place the path contained in the strbuf. If an error occurs,\n+ * the contents of \"sb\" are left untouched, and -1 is returned.\n+ */\n+int strbuf_normalize_path(struct strbuf *src);\n int longest_ancestor_length(const char *path, struct string_list *prefixes);\n char *strip_path_suffix(const char *path, const char *suffix);\n int daemon_avoid_alias(const char *path);\ndiff --git a/strbuf.c b/strbuf.c\nindex 6533559e95..178d75f250 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1088,26 +1088,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \tstrbuf_setlen(sb, j);\n }\n \n-int strbuf_normalize_path(struct strbuf *src)\n-{\n-\tstruct strbuf dst = STRBUF_INIT;\n-\n-\tstrbuf_grow(&dst, src->len);\n-\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n-\t\tstrbuf_release(&dst);\n-\t\treturn -1;\n-\t}\n-\n-\t/*\n-\t * normalize_path does not tell us the new length, so we have to\n-\t * compute it by looking for the new NUL it placed\n-\t */\n-\tstrbuf_setlen(&dst, strlen(dst.buf));\n-\tstrbuf_swap(src, &dst);\n-\tstrbuf_release(&dst);\n-\treturn 0;\n-}\n-\n void strbuf_strip_file_from_path(struct strbuf *sb)\n {\n \tchar *path_sep = find_last_dir_sep(sb->buf);\n-- \n2.40.1.495.gc816e09b53d-goog\n\n"},{"id":"476465","messageId":"20230502211454.1673000-6-calvinwan@google.com","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"[PATCH 5/6] strbuf: clarify dependency","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-02T21:14:53Z","receivedAt":"2023-05-02T21:15:30Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Signed-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex 178d75f250..d5978fee4e 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,7 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"refs.h\"\n+#include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n #include \"date.h\"\n-- \n2.40.1.495.gc816e09b53d-goog\n\n"},{"id":"476466","messageId":"20230502211454.1673000-7-calvinwan@google.com","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"[PATCH 6/6] strbuf: remove environment variables","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-02T21:14:54Z","receivedAt":"2023-05-02T21:15:42Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"As a lower level library, strbuf should not directly access environment\nvariables within its functions. Therefore, add an additional variable to\nfunction signatures for functions that use an environment variable and\nrefactor callers to pass in the environment variable.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n add-patch.c          | 12 +++++++-----\n builtin/am.c         |  2 +-\n builtin/branch.c     |  4 ++--\n builtin/commit.c     |  2 +-\n builtin/merge.c      | 10 ++++++----\n builtin/notes.c      | 16 +++++++++-------\n builtin/rebase.c     |  2 +-\n builtin/stripspace.c |  6 ++++--\n builtin/tag.c        |  9 ++++++---\n fmt-merge-msg.c      |  9 ++++++---\n gpg-interface.c      |  5 +++--\n rebase-interactive.c | 15 ++++++++-------\n sequencer.c          | 24 +++++++++++++++---------\n strbuf.c             | 12 +++++++-----\n strbuf.h             |  9 +++++----\n wt-status.c          |  6 +++---\n 16 files changed, 84 insertions(+), 59 deletions(-)\n\ndiff --git a/add-patch.c b/add-patch.c\nindex 8d770d203f..9702c1aabd 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \tsize_t i;\n \n \tstrbuf_reset(&s->buf);\n-\tstrbuf_commented_addf(&s->buf, _(\"Manual hunk edit mode -- see bottom for \"\n-\t\t\t\t      \"a quick guide.\\n\"));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n+\t\t\t      _(\"Manual hunk edit mode -- see bottom for \"\n+\t\t\t\t\"a quick guide.\\n\"));\n \trender_hunk(s, hunk, 0, 0, &s->buf);\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"---\\n\"\n \t\t\t\t\"To remove '%c' lines, make them ' ' lines \"\n \t\t\t\t\"(context).\\n\"\n@@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \t\t\t      s->mode->is_reverse ? '+' : '-',\n \t\t\t      s->mode->is_reverse ? '-' : '+',\n \t\t\t      comment_line_char);\n-\tstrbuf_commented_addf(&s->buf, \"%s\", _(s->mode->edit_hunk_hint));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char, \"%s\",\n+\t\t\t      _(s->mode->edit_hunk_hint));\n \t/*\n \t * TRANSLATORS: 'it' refers to the patch mentioned in the previous\n \t * messages.\n \t */\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"If it does not apply cleanly, you will be \"\n \t\t\t\t\"given an opportunity to\\n\"\n \t\t\t\t\"edit again.  If all lines of the hunk are \"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5c83f2e003..306489db13 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n \tstrbuf_addbuf(&msg, &mi.log_message);\n-\tstrbuf_stripspace(&msg, 0);\n+\tstrbuf_stripspace(&msg, 0, comment_line_char);\n \n \tassert(!state->author_name);\n \tstate->author_name = strbuf_detach(&author_name, NULL);\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 501c47657c..e52afcf4d7 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -629,7 +629,7 @@ static int edit_branch_description(const char *branch_name)\n \texists = !read_branch_desc(&buf, branch_name);\n \tif (!buf.len || buf.buf[buf.len-1] != '\\n')\n \t\tstrbuf_addch(&buf, '\\n');\n-\tstrbuf_commented_addf(&buf,\n+\tstrbuf_commented_addf(&buf, comment_line_char,\n \t\t    _(\"Please edit the description for the branch\\n\"\n \t\t      \"  %s\\n\"\n \t\t      \"Lines starting with '%c' will be stripped.\\n\"),\n@@ -640,7 +640,7 @@ static int edit_branch_description(const char *branch_name)\n \t\tstrbuf_release(&buf);\n \t\treturn -1;\n \t}\n-\tstrbuf_stripspace(&buf, 1);\n+\tstrbuf_stripspace(&buf, 1, comment_line_char);\n \n \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n \tif (buf.len || exists)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex e67c4be221..6d3cc4d9fe 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \ts->hints = 0;\n \n \tif (clean_message_contents)\n-\t\tstrbuf_stripspace(&sb, 0);\n+\t\tstrbuf_stripspace(&sb, 0, comment_line_char);\n \n \tif (signoff)\n \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8da3e46abb..1d14767c0c 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)\n \t\tstrbuf_addch(&msg, '\\n');\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {\n \t\t\twt_status_append_cut_line(&msg);\n-\t\t\tstrbuf_commented_addf(&msg, \"\\n\");\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char, \"\\n\");\n \t\t}\n-\t\tstrbuf_commented_addf(&msg, _(merge_editor_comment));\n+\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t      _(merge_editor_comment));\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n-\t\t\tstrbuf_commented_addf(&msg, _(scissors_editor_comment));\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t\t      _(scissors_editor_comment));\n \t\telse\n-\t\t\tstrbuf_commented_addf(&msg,\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n \t\t\t\t_(no_scissors_editor_comment), comment_line_char);\n \t}\n \tif (signoff)\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex d5788352b6..0918b92752 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -11,6 +11,7 @@\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"editor.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"notes.h\"\n@@ -157,7 +158,7 @@ static void write_commented_object(int fd, const struct object_id *object)\n \n \tif (strbuf_read(&buf, show.out, 0) < 0)\n \t\tdie_errno(_(\"could not read 'show' output\"));\n-\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);\n \twrite_or_die(fd, cbuf.buf, cbuf.len);\n \n \tstrbuf_release(&cbuf);\n@@ -185,9 +186,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\t\tcopy_obj_to_fd(fd, old_note);\n \n \t\tstrbuf_addch(&buf, '\\n');\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n-\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),\n+\t\t\t\t\t   comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n \t\twrite_or_die(fd, buf.buf, buf.len);\n \n \t\twrite_commented_object(fd, object);\n@@ -199,7 +201,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\tif (launch_editor(d->edit_path, &d->buf, NULL)) {\n \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n \t\t}\n-\t\tstrbuf_stripspace(&d->buf, 1);\n+\t\tstrbuf_stripspace(&d->buf, 1, comment_line_char);\n \t}\n }\n \n@@ -225,7 +227,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \tstrbuf_addstr(&d->buf, arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n \n \td->given = 1;\n \treturn 0;\n@@ -244,7 +246,7 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n \t\t\tdie_errno(_(\"cannot read '%s'\"), arg);\n \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n \n \td->given = 1;\n \treturn 0;\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex ace1d5e8d1..d092e06dc7 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)\n \tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n \n-\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tstrbuf_stripspace(&todo_list.buf, 1, comment_line_char);\n \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 9451eb69ff..e182c2a14e 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"parse-options.h\"\n #include \"setup.h\"\n@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)\n \tsize_t len;\n \n \tmsg = strbuf_detach(buf, &len);\n-\tstrbuf_add_commented_lines(buf, msg, len);\n+\tstrbuf_add_commented_lines(buf, msg, len, comment_line_char);\n \tfree(msg);\n }\n \n@@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)\n \t\tdie_errno(\"could not read the input\");\n \n \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n-\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n+\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS,\n+\t\t\t\t  comment_line_char);\n \telse\n \t\tcomment_lines(&buf);\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1850a6a6fd..c713d14489 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n \t\t\tstrbuf_addch(&buf, '\\n');\n \t\t\tif (opt->cleanup_mode == CLEANUP_ALL)\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template), tag,comment_line_char);\n \t\t\telse\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template_nocleanup), tag, comment_line_char);\n \t\t\twrite_or_die(fd, buf.buf, buf.len);\n \t\t\tstrbuf_release(&buf);\n \t\t}\n@@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t}\n \n \tif (opt->cleanup_mode != CLEANUP_NONE)\n-\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n+\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n \n \tif (!opt->message_given && !buf->len)\n \t\tdie(_(\"no tag message?\"));\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 5af0d4715b..5d15e2387d 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,\n \tstrbuf_complete_line(tagbuf);\n \tif (sig->len) {\n \t\tstrbuf_addch(tagbuf, '\\n');\n-\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len);\n+\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len,\n+\t\t\t\t\t   comment_line_char);\n \t}\n }\n \n@@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\t\tstrbuf_addch(&tagline, '\\n');\n \t\t\t\tstrbuf_add_commented_lines(&tagline,\n \t\t\t\t\t\torigins.items[first_tag].string,\n-\t\t\t\t\t\tstrlen(origins.items[first_tag].string));\n+\t\t\t\t\t\tstrlen(origins.items[first_tag].string),\n+\t\t\t\t\t\tcomment_line_char);\n \t\t\t\tstrbuf_insert(&tagbuf, 0, tagline.buf,\n \t\t\t\t\t      tagline.len);\n \t\t\t\tstrbuf_release(&tagline);\n@@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\tstrbuf_addch(&tagbuf, '\\n');\n \t\t\tstrbuf_add_commented_lines(&tagbuf,\n \t\t\t\t\torigins.items[i].string,\n-\t\t\t\t\tstrlen(origins.items[i].string));\n+\t\t\t\t\tstrlen(origins.items[i].string),\n+\t\t\t\t\tcomment_line_char);\n \t\t\tfmt_tag_signature(&tagbuf, &sig, buf, len);\n \t\t}\n \t\tstrbuf_release(&payload);\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex f3ac5acdd9..b625f17460 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -11,6 +11,7 @@\n #include \"tempfile.h\"\n #include \"alias.h\"\n #include \"wrapper.h\"\n+#include \"environment.h\"\n \n static int git_gpg_config(const char *, const char *, void *);\n \n@@ -584,8 +585,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,\n \t\t}\n \t}\n \n-\tstrbuf_stripspace(&ssh_keygen_out, 0);\n-\tstrbuf_stripspace(&ssh_keygen_err, 0);\n+\tstrbuf_stripspace(&ssh_keygen_out, 0, comment_line_char);\n+\tstrbuf_stripspace(&ssh_keygen_err, 0, comment_line_char);\n \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 789f407361..c6027e73c1 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -71,13 +71,14 @@ void append_todo_help(int command_count,\n \n \tif (!edit_todo) {\n \t\tstrbuf_addch(buf, '\\n');\n-\t\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n-\t\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n-\t\t\t\t\t      command_count),\n+\t\tstrbuf_commented_addf(buf, comment_line_char,\n+\t\t\t\t      Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t\t \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t\t command_count),\n \t\t\t\t      shortrevisions, shortonto, command_count);\n \t}\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -86,7 +87,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -97,7 +98,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n }\n \n int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n@@ -129,7 +130,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n \tif (launch_sequence_editor(todo_file, &new_todo->buf, NULL))\n \t\treturn -2;\n \n-\tstrbuf_stripspace(&new_todo->buf, 1);\n+\tstrbuf_stripspace(&new_todo->buf, 1, comment_line_char);\n \tif (initial && new_todo->buf.len == 0)\n \t\treturn -3;\n \ndiff --git a/sequencer.c b/sequencer.c\nindex c88d1d9553..9675b62bcb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -659,11 +659,12 @@ void append_conflicts_hint(struct index_state *istate,\n \t}\n \n \tstrbuf_addch(msgbuf, '\\n');\n-\tstrbuf_commented_addf(msgbuf, \"Conflicts:\\n\");\n+\tstrbuf_commented_addf(msgbuf, comment_line_char, \"Conflicts:\\n\");\n \tfor (i = 0; i < istate->cache_nr;) {\n \t\tconst struct cache_entry *ce = istate->cache[i++];\n \t\tif (ce_stage(ce)) {\n-\t\t\tstrbuf_commented_addf(msgbuf, \"\\t%s\\n\", ce->name);\n+\t\t\tstrbuf_commented_addf(msgbuf, comment_line_char,\n+\t\t\t\t\t      \"\\t%s\\n\", ce->name);\n \t\t\twhile (i < istate->cache_nr &&\n \t\t\t       !strcmp(ce->name, istate->cache[i]->name))\n \t\t\t\ti++;\n@@ -1142,7 +1143,8 @@ void cleanup_message(struct strbuf *msgbuf,\n \t    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n }\n \n /*\n@@ -1173,7 +1175,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,\n \tif (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)\n \t\treturn 0;\n \n-\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t  comment_line_char);\n \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n \t\tstart = sb->buf;\n \tstrbuf_release(&tmpl);\n@@ -1545,7 +1548,8 @@ static int try_to_commit(struct repository *r,\n \t\tcleanup = opts->default_msg_cleanup;\n \n \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n \t\tres = 1; /* run 'git commit' to display error message */\n \t\tgoto out;\n@@ -1839,7 +1843,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n \t\ts += count;\n \t\tlen -= count;\n \t}\n-\tstrbuf_add_commented_lines(buf, s, len);\n+\tstrbuf_add_commented_lines(buf, s, len, comment_line_char);\n }\n \n /* Does the current fixup chain contain a squash command? */\n@@ -1938,7 +1942,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_add_commented_lines(buf, body, commented_len, comment_line_char);\n \t/* buf->buf may be reallocated so store an offset into the buffer */\n \tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n@@ -2028,7 +2032,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tif (is_fixup_flag(command, flag))\n-\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t\t   comment_line_char);\n \t\telse\n \t\t\tstrbuf_addstr(&buf, body);\n \n@@ -2047,7 +2052,8 @@ static int update_squash_messages(struct repository *r,\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t   comment_line_char);\n \t} else\n \t\treturn error(_(\"unknown command: %d\"), command);\n \trepo_unuse_commit_buffer(r, commit, message);\ndiff --git a/strbuf.c b/strbuf.c\nindex d5978fee4e..eba65ca421 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,6 +1,5 @@\n #include \"git-compat-util.h\"\n #include \"alloc.h\"\n-#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"strbuf.h\"\n@@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n \tstrbuf_complete_line(out);\n }\n \n-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n+\t\t\t\tsize_t size, char comment_line_char)\n {\n \tstatic char prefix1[3];\n \tstatic char prefix2[2];\n@@ -374,7 +374,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size\n \tadd_lines(out, prefix1, prefix2, buf, size);\n }\n \n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,\n+\t\t\t   const char *fmt, ...)\n {\n \tva_list params;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -384,7 +385,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n \tstrbuf_vaddf(&buf, fmt, params);\n \tva_end(params);\n \n-\tstrbuf_add_commented_lines(sb, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);\n \tif (incomplete_line)\n \t\tsb->buf[--sb->len] = '\\0';\n \n@@ -1054,7 +1055,8 @@ static size_t cleanup(char *line, size_t len)\n  * Enable skip_comments to skip every line starting with comment\n  * character.\n  */\n-void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n+void strbuf_stripspace(struct strbuf *sb, int skip_comments,\n+\t\t       char comment_line_char)\n {\n \tsize_t empties = 0;\n \tsize_t i, j, len, newlen;\ndiff --git a/strbuf.h b/strbuf.h\nindex b6d53c1cbe..f90da8859f 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -283,7 +283,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n  * by a comment character and a blank.\n  */\n void strbuf_add_commented_lines(struct strbuf *out,\n-\t\t\t\tconst char *buf, size_t size);\n+\t\t\t\tconst char *buf, size_t size,\n+\t\t\t\tchar comment_line_char);\n \n \n /**\n@@ -412,8 +413,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n  * Add a formatted string prepended by a comment character and a\n  * blank to the buffer.\n  */\n-__attribute__((format (printf, 2, 3)))\n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n+__attribute__((format (printf, 3, 4)))\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n \n __attribute__((format (printf,2,0)))\n void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n@@ -538,7 +539,7 @@ int strbuf_normalize_path(struct strbuf *sb);\n  * Strip whitespace from a buffer. The second parameter controls if\n  * comments are considered contents to be removed or not.\n  */\n-void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n+void strbuf_stripspace(struct strbuf *buf, int skip_comments, char comment_line_char);\n \n static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n {\ndiff --git a/wt-status.c b/wt-status.c\nindex 97b9c1c035..da7734866f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1023,7 +1023,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom\n \tif (s->display_comment_prefix) {\n \t\tsize_t len;\n \t\tsummary_content = strbuf_detach(&summary, &len);\n-\t\tstrbuf_add_commented_lines(&summary, summary_content, len);\n+\t\tstrbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);\n \t\tfree(summary_content);\n \t}\n \n@@ -1098,8 +1098,8 @@ void wt_status_append_cut_line(struct strbuf *buf)\n {\n \tconst char *explanation = _(\"Do not modify or remove the line above.\\nEverything below it will be ignored.\");\n \n-\tstrbuf_commented_addf(buf, \"%s\", cut_line);\n-\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation));\n+\tstrbuf_commented_addf(buf, comment_line_char, \"%s\", cut_line);\n+\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);\n }\n \n void wt_status_add_cut_line(FILE *fp)\n-- \n2.40.1.495.gc816e09b53d-goog\n\n"},{"id":"476468","messageId":"xmqq7ctqz9zq.fsf@gitster.g","threadId":"59685","inReplyTo":"20230502211454.1673000-2-calvinwan@google.com","subject":"Re: [PATCH 1/6] abspath: move related functions to abspath","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-02T21:42:01Z","receivedAt":"2023-05-02T21:42:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> Move abspath-related functions from strbuf.[ch] to abspath.[ch] since\n> they do not belong in a low-level library.\n\nGiven a relative path and turning it into absolute is still\nlow-level enough, but that apparently is not what you meant.\n\nIt would be nice to define what you mean by \"low-level\" here, and\nupdate the comments at the beginning of <strbuf.h> with that\ndefinition.\n\nI think what you are trying to do is to move anything that does more\nthan straight string manipulation out of \"strbuf.c\"; roughly, things\nthat have system dependencies that are more than malloc/realloc.\n\nFor this particular step, I think it is a natural thing to move a\nfunction that computes an absolute version of a given path to\nabspath.[ch] that already exists.  The same goes for its realpath\ncounterpart.\n"},{"id":"476470","messageId":"xmqq1qjyz9ib.fsf@gitster.g","threadId":"59685","inReplyTo":"20230502211454.1673000-3-calvinwan@google.com","subject":"Re: [PATCH 2/6] credential-store: move related functions to credential-store file","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-02T21:52:28Z","receivedAt":"2023-05-02T21:52:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> is_rfc3986_unreserved() and is_rfc3986_reserved_or_unreserved() are only\n> called from builtin/credential-store.c and they are only relevant to that\n> file so move those functions and make them static.\n>\n> Signed-off-by: Calvin Wan <calvinwan@google.com>\n> ---\n>  builtin/credential-store.c | 19 +++++++++++++++++++\n>  strbuf.c                   | 19 -------------------\n>  strbuf.h                   |  3 ---\n>  3 files changed, 19 insertions(+), 22 deletions(-)\n>\n> diff --git a/builtin/credential-store.c b/builtin/credential-store.c\n> index 8977604eb9..4776118331 100644\n> --- a/builtin/credential-store.c\n> +++ b/builtin/credential-store.c\n> @@ -73,6 +73,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,\n>  \t\tdie_errno(\"unable to write credential store\");\n>  }\n>  \n> +static int is_rfc3986_unreserved(char ch)\n> +{\n> +\treturn isalnum(ch) ||\n> +\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n> +}\n> +\n> +static int is_rfc3986_reserved_or_unreserved(char ch)\n> +{\n> +\tif (is_rfc3986_unreserved(ch))\n> +\t\treturn 1;\n> +\tswitch (ch) {\n> +\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n> +\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n> +\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n> +\t\t\treturn 1;\n> +\t}\n> +\treturn 0;\n> +}\n\nBoth the moved ones being static means we even lose the declarations\nin the header file.  Very nice.\n"},{"id":"476471","messageId":"xmqqttwuxtnz.fsf@gitster.g","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"Re: [PATCH 0/6] strbuf cleanups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-02T22:20:00Z","receivedAt":"2023-05-02T22:20:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> Strbuf is a basic structure that should function as a low-level library\n> due to how generic it is. Over time certain functions inside of\n> strbuf.[ch] have been added with dependencies to higher level objects\n> and functions. This series cleans up some of those higher level\n> dependencies by moving the offending functions to the files they\n> interact with. With the goal of eventually being able to stand up strbuf\n> as a libary, this series also removes the use of environment variables\n> from strbuf.\n\nI touched a bit of the same in my review for 1/6, but the main\nthrust of the series is that you want to make strbuf.[ch] mostly\nabout \"string processing primitives\".\n\nAny meaningful features relate to more than one conceptual things,\ne.g. pathname functions work on \"paths\" (that is one) and it may\nstore computed result in a \"strbuf\" (that is another).  We have\nhistorically called them strbuf_do_something() and gave the pointer\nto a strbuf that receives the result.  And this series wants to\nreverse the course and want to see strbuf that is more pure.\n\nThat's fine.  The strbuf has become so successful a data structure,\nits use has become as ubiquitous as a plain string or an integer in\nour codebase.\n\nBut if we were moving in that direction, I have to wonder if some of\nthese functions also need to be renamed to lose their strbuf_\nprefix.  A function that takes a pathname and creates a directory\nthere is not called string_mkdir() just because it takes a pathname\nas a string.  A function that takes a string buffer and a path, and\nreads the symbolic link content is not called string_readlink() just\nbecause it learns the symlink target in a string buffer.  What their\nparameters mean matters a lot more than what type these parameters\nare represented as.\n\nWith some other topics in flight, merging this to 'seen' and merging\nthis to 'next' may require different merge fixes, but I'll manage.\n\nThanks.\n\n"},{"id":"476472","messageId":"xmqqildaxt5l.fsf@gitster.g","threadId":"59685","inReplyTo":"xmqqttwuxtnz.fsf@gitster.g","subject":"Re: [PATCH 0/6] strbuf cleanups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-02T22:31:02Z","receivedAt":"2023-05-02T22:31:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> But if we were moving in that direction, I have to wonder if some of\n> these functions also need to be renamed to lose their strbuf_\n> prefix.\n\nJust to avoid misunderstanding.  I do not mean to suggest renaming\nthese inside this series.  It would make things too noisy and even\nmore distracting.  But in the longer term, as we treat strbuf more\nand more as one of our basic data structures, it would make sense to\nlose strbuf_ from functions that are thrown out of strbuf.[ch] with\nthis series, and reserve the prefix to functions that are left in\nstrbuf.[ch], i.e. those that are about string operations.\n\n"},{"id":"476473","messageId":"CAFySSZCz=ydmOZ+580Xhpp93NJbqyL21pPU=wfme_-zj6m8agw@mail.gmail.com","threadId":"59685","inReplyTo":"xmqqttwuxtnz.fsf@gitster.g","subject":"Re: [PATCH 0/6] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-02T22:36:13Z","receivedAt":"2023-05-02T22:36:29Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"On Tue, May 2, 2023 at 3:20 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> > Strbuf is a basic structure that should function as a low-level library\n> > due to how generic it is. Over time certain functions inside of\n> > strbuf.[ch] have been added with dependencies to higher level objects\n> > and functions. This series cleans up some of those higher level\n> > dependencies by moving the offending functions to the files they\n> > interact with. With the goal of eventually being able to stand up strbuf\n> > as a libary, this series also removes the use of environment variables\n> > from strbuf.\n>\n> I touched a bit of the same in my review for 1/6, but the main\n> thrust of the series is that you want to make strbuf.[ch] mostly\n> about \"string processing primitives\".\n\nThanks for clarifying the boundary I was attempting to explain in my\ncover letter, but unsuccessfully did so.\n\n>\n> Any meaningful features relate to more than one conceptual things,\n> e.g. pathname functions work on \"paths\" (that is one) and it may\n> store computed result in a \"strbuf\" (that is another).  We have\n> historically called them strbuf_do_something() and gave the pointer\n> to a strbuf that receives the result.  And this series wants to\n> reverse the course and want to see strbuf that is more pure.\n>\n> That's fine.  The strbuf has become so successful a data structure,\n> its use has become as ubiquitous as a plain string or an integer in\n> our codebase.\n>\n> But if we were moving in that direction, I have to wonder if some of\n> these functions also need to be renamed to lose their strbuf_\n> prefix.  A function that takes a pathname and creates a directory\n> there is not called string_mkdir() just because it takes a pathname\n> as a string.  A function that takes a string buffer and a path, and\n> reads the symbolic link content is not called string_readlink() just\n> because it learns the symlink target in a string buffer.  What their\n> parameters mean matters a lot more than what type these parameters\n> are represented as.\n\nI agree that with the functions that are moved out from strbuf, they\nshould be refactored in the future to the form, taking absolute path\nas an example, strbuf_addstr(sb, get_absolute_path(path)) or something\nsimilar.\n\n>\n> With some other topics in flight, merging this to 'seen' and merging\n> this to 'next' may require different merge fixes, but I'll manage.\n>\n> Thanks.\n>\n"},{"id":"476476","messageId":"6451a200e17d8_200ae294ed@chronos.notmuch","threadId":"59685","inReplyTo":"xmqqildaxt5l.fsf@gitster.g","subject":"Re: [PATCH 0/6] strbuf cleanups","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-05-02T23:51:28Z","receivedAt":"2023-05-02T23:51:39Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Junio C Hamano wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > But if we were moving in that direction, I have to wonder if some of\n> > these functions also need to be renamed to lose their strbuf_\n> > prefix.\n> \n> Just to avoid misunderstanding.  I do not mean to suggest renaming\n> these inside this series.  It would make things too noisy and even\n> more distracting.  But in the longer term, as we treat strbuf more\n> and more as one of our basic data structures, it would make sense to\n> lose strbuf_ from functions that are thrown out of strbuf.[ch] with\n> this series, and reserve the prefix to functions that are left in\n> strbuf.[ch], i.e. those that are about string operations.\n\nI thought precisely the same thing: 1) it's good to move them away, 2)\nthey should lose the \"strbuf_\" prefix, 3) that doesn't need to happen in\nthis series.\n\n-- \nFelipe Contreras\n"},{"id":"476482","messageId":"CABPp-BGLcUnqZvYNG_5pNOXSHCtryVyXoMJHdX5eXdkgYAS24Q@mail.gmail.com","threadId":"59685","inReplyTo":"20230502211454.1673000-6-calvinwan@google.com","subject":"Re: [PATCH 5/6] strbuf: clarify dependency","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-05-03T01:56:00Z","receivedAt":"2023-05-03T01:58:02Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, May 2, 2023 at 2:15 PM Calvin Wan <calvinwan@google.com> wrote:\n>\n> Signed-off-by: Calvin Wan <calvinwan@google.com>\n> ---\n>  strbuf.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/strbuf.c b/strbuf.c\n> index 178d75f250..d5978fee4e 100644\n> --- a/strbuf.c\n> +++ b/strbuf.c\n> @@ -3,7 +3,7 @@\n>  #include \"environment.h\"\n>  #include \"gettext.h\"\n>  #include \"hex.h\"\n> -#include \"refs.h\"\n> +#include \"strbuf.h\"\n>  #include \"string-list.h\"\n>  #include \"utf8.h\"\n>  #include \"date.h\"\n> --\n> 2.40.1.495.gc816e09b53d-goog\n\nThe commit message feels misleading.  A little digging shows that\nrefs.h was once upon a time needed, but no longer was as of\n6bab74e7fb8 (\"strbuf: move strbuf_branchname to sha1_name.c\",\n2010-11-06).  So, you're removing an unnecessary include, but adding\none back that was missing.  I guess that might count as \"clarifying\",\nbut maybe some of that extra context in the commit message would be\nuseful?\n"},{"id":"476483","messageId":"CABPp-BGgP50TV7Gc8bpu1vvR-6-EKKC8eM_j=o4imz7Y-55pMw@mail.gmail.com","threadId":"59685","inReplyTo":"20230502211454.1673000-7-calvinwan@google.com","subject":"Re: [PATCH 6/6] strbuf: remove environment variables","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-05-03T02:15:00Z","receivedAt":"2023-05-03T02:15:51Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, May 2, 2023 at 2:15 PM Calvin Wan <calvinwan@google.com> wrote:\n>\n> As a lower level library, strbuf should not directly access environment\n> variables within its functions. Therefore, add an additional variable to\n> function signatures for functions that use an environment variable and\n> refactor callers to pass in the environment variable.\n\nYaay!  I hate the pervasive implicit use of globals throughout the\ncodebase, and like seeing changes that at least make them less hidden.\n\nI might have split this patch into three, one for each of the\nfunctions you are changing.  The reason is just that it makes review\nso much easier; a simple --color-words view then becomes easy\nto rapidly scan through on each patch.  When one patch includes all\nthree, reviewers have to double check the position of the added\nparameter in the argument list against the name of the function.  But\nthat's a really minor point, and some might prefer as you have it here\nwith the three squashed together.\n\n[...]\n> diff --git a/strbuf.h b/strbuf.h\n> index b6d53c1cbe..f90da8859f 100644\n> --- a/strbuf.h\n> +++ b/strbuf.h\n> @@ -283,7 +283,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n>   * by a comment character and a blank.\n>   */\n>  void strbuf_add_commented_lines(struct strbuf *out,\n> -                               const char *buf, size_t size);\n> +                               const char *buf, size_t size,\n> +                               char comment_line_char);\n>\n>\n>  /**\n> @@ -412,8 +413,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n>   * Add a formatted string prepended by a comment character and a\n>   * blank to the buffer.\n>   */\n> -__attribute__((format (printf, 2, 3)))\n> -void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n> +__attribute__((format (printf, 3, 4)))\n> +void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n>\n>  __attribute__((format (printf,2,0)))\n>  void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n> @@ -538,7 +539,7 @@ int strbuf_normalize_path(struct strbuf *sb);\n>   * Strip whitespace from a buffer. The second parameter controls if\n>   * comments are considered contents to be removed or not.\n\nShould this documentation string be updated, given that it previously\ndocumented all arguments to the function?\n\n>   */\n> -void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n> +void strbuf_stripspace(struct strbuf *buf, int skip_comments, char comment_line_char);\n>\n>  static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n>  {\n[...]\n\nThe rest looks good to me.\n"},{"id":"476484","messageId":"CABPp-BFagTvBTe0XbEOM_hO-vDFwVvSSmGOii1q2=7amqerwtQ@mail.gmail.com","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"Re: [PATCH 0/6] strbuf cleanups","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-05-03T02:37:00Z","receivedAt":"2023-05-03T02:37:19Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Tue, May 2, 2023 at 2:15 PM Calvin Wan <calvinwan@google.com> wrote:\n>\n> Strbuf is a basic structure that should function as a low-level library\n> due to how generic it is. Over time certain functions inside of\n> strbuf.[ch] have been added with dependencies to higher level objects\n> and functions. This series cleans up some of those higher level\n> dependencies by moving the offending functions to the files they\n> interact with. With the goal of eventually being able to stand up strbuf\n> as a libary, this series also removes the use of environment variables\n> from strbuf.\n>\n> Calvin Wan (6):\n>   abspath: move related functions to abspath\n>   credential-store: move related functions to credential-store file\n>   object-name: move related functions to object-name\n>   path: move related function to path\n>   strbuf: clarify dependency\n>   strbuf: remove environment variables\n>\n>  abspath.c                  |  36 +++++++++++++\n>  abspath.h                  |  21 ++++++++\n>  add-patch.c                |  12 +++--\n>  builtin/am.c               |   2 +-\n>  builtin/branch.c           |   4 +-\n>  builtin/commit.c           |   2 +-\n>  builtin/credential-store.c |  19 +++++++\n>  builtin/merge.c            |  10 ++--\n>  builtin/notes.c            |  16 +++---\n>  builtin/rebase.c           |   2 +-\n>  builtin/stripspace.c       |   6 ++-\n>  builtin/tag.c              |   9 ++--\n>  fmt-merge-msg.c            |   9 ++--\n>  gpg-interface.c            |   5 +-\n>  hook.c                     |   1 +\n>  object-name.c              |  15 ++++++\n>  object-name.h              |   9 ++++\n>  path.c                     |  20 +++++++\n>  path.h                     |   5 ++\n>  pretty.c                   |   1 +\n>  rebase-interactive.c       |  15 +++---\n>  sequencer.c                |  24 +++++----\n>  strbuf.c                   | 106 +++----------------------------------\n>  strbuf.h                   |  44 ++-------------\n>  tempfile.c                 |   1 +\n>  wt-status.c                |   6 +--\n>  26 files changed, 213 insertions(+), 187 deletions(-)\n>\n> --\n> 2.40.1.495.gc816e09b53d-goog\n\nThe series looks pretty good to me.  I left a couple small comments on\n5/6 and 6/6.  One other high-level note:\n\nAs Ævar noted over at\nhttps://lore.kernel.org/git/230501.86a5yohsme.gmgdl@evledraar.gmail.com/,\nstrbuf_add_separated_string_list() is currently only used by\nmerge-ort.c and merge-recursive.c (both of which include\nmerge-recursive.h).  It may make sense to move that function, and that\nwould permit you to drop the forward declaration of 'struct\nstring_list;' from strbuf.c as well.\n"},{"id":"476516","messageId":"20230503162858.GA1789686@coredump.intra.peff.net","threadId":"59685","inReplyTo":"20230502211454.1673000-3-calvinwan@google.com","subject":"Re: [PATCH 2/6] credential-store: move related functions to credential-store file","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2023-05-03T16:28:58Z","receivedAt":"2023-05-03T16:29:07Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, May 02, 2023 at 09:14:50PM +0000, Calvin Wan wrote:\n\n> is_rfc3986_unreserved() and is_rfc3986_reserved_or_unreserved() are only\n> called from builtin/credential-store.c and they are only relevant to that\n> file so move those functions and make them static.\n\nThis is probably OK to do, though I think \"and they are only relevant to\nthat file\" is overstating things a bit.\n\nThey are callbacks to be used with strbuf_add_urlencode(). Originally\nthey were static-locals next to that function, with a flag bit to\ntrigger which was used.\n\nLater, c2694952e3 (strbuf: give URL-encoding API a char predicate fn,\n2019-06-27) replaced the flag with a callback mechanism, which meant the\nfunctions had to be public. But all callers except the new one added in\nthat series still needed them (that other caller is not encoding a URL,\nso it wants different rules).\n\nAnd then finally, 644de29e22 (http: drop support for curl < 7.19.4,\n2021-07-30) dropped the http.c callers, leaving only the ones in\ncredential-store.\n\nSo yes, it's true that only credential-store.c needs them right now. But\nseparating them from strbuf_add_urlencode() is making that function next\nto useless for any future callers, as they'd have to reimplement the\nlogic about which characters are reserved. I say \"next to useless\",\nbecause that one \"not a URL\" caller doesn't need that logic.\n\nSo I dunno. It's largely academic until somebody else needs to encode\nbits of a URL. But when they do, the first thing they'd need to do is\nmake these functions public again.\n\nI think the main reason we do not have other callers is that urlmatch.c\nimplements its own percent-encoding code, and that's where we do most of\nour URL handling. It does make me wonder if credential-store could\nsimply switch to using that, but that is probably out of scope for your\nseries.\n\n-Peff\n"},{"id":"476517","messageId":"20230503163446.GB1789686@coredump.intra.peff.net","threadId":"59685","inReplyTo":"20230503162858.GA1789686@coredump.intra.peff.net","subject":"Re: [PATCH 2/6] credential-store: move related functions to credential-store file","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2023-05-03T16:34:46Z","receivedAt":"2023-05-03T16:34:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, May 03, 2023 at 12:28:58PM -0400, Jeff King wrote:\n\n> I think the main reason we do not have other callers is that urlmatch.c\n> implements its own percent-encoding code, and that's where we do most of\n> our URL handling. It does make me wonder if credential-store could\n> simply switch to using that, but that is probably out of scope for your\n> series.\n\nPoking at it a bit, I think the answer is \"not easily\". credential-store\nhas broken-out elements of a URL, and wants to turn them back into one.\nAnd urlmatch.c's url_normalize() always takes a URL string as input.\nEven though it finds the broken-out fields as part of its work, the\nparsing and reconstruction of the URL are inter-mingled in a complex\nway (i.e., it's not just \"parse it, then turn the fields back into a\nnormalized string).\n\nI'm sure it could be refactored, but it's probably not worth it (and\nagain, this tangent is somewhat orthogonal to your series, except that\nit would make these is_rfc3986 functions go away entirely).\n\n-Peff\n"},{"id":"476533","messageId":"CAFySSZAOqX0pESfJ-7bYg9iR2RDB9PL6sC4Kcvr_zitdQ1kD_g@mail.gmail.com","threadId":"59685","inReplyTo":"CABPp-BFagTvBTe0XbEOM_hO-vDFwVvSSmGOii1q2=7amqerwtQ@mail.gmail.com","subject":"Re: [PATCH 0/6] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:00:07Z","receivedAt":"2023-05-03T18:00:22Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"While moving strbuf_add_separated_string_list() to a separate file\nwould mean that strbuf would no longer have a dependency on\nstring-list, I don't think that dependency is problematic to begin\nwith. Widening the boundary for strbuf as a string manipulation\nlibrary to a string and string list manipulation library seems\nreasonable to me.\n\n\nOn Tue, May 2, 2023 at 7:37 PM Elijah Newren <newren@gmail.com> wrote:\n>\n> On Tue, May 2, 2023 at 2:15 PM Calvin Wan <calvinwan@google.com> wrote:\n> >\n> > Strbuf is a basic structure that should function as a low-level library\n> > due to how generic it is. Over time certain functions inside of\n> > strbuf.[ch] have been added with dependencies to higher level objects\n> > and functions. This series cleans up some of those higher level\n> > dependencies by moving the offending functions to the files they\n> > interact with. With the goal of eventually being able to stand up strbuf\n> > as a libary, this series also removes the use of environment variables\n> > from strbuf.\n> >\n> > Calvin Wan (6):\n> >   abspath: move related functions to abspath\n> >   credential-store: move related functions to credential-store file\n> >   object-name: move related functions to object-name\n> >   path: move related function to path\n> >   strbuf: clarify dependency\n> >   strbuf: remove environment variables\n> >\n> >  abspath.c                  |  36 +++++++++++++\n> >  abspath.h                  |  21 ++++++++\n> >  add-patch.c                |  12 +++--\n> >  builtin/am.c               |   2 +-\n> >  builtin/branch.c           |   4 +-\n> >  builtin/commit.c           |   2 +-\n> >  builtin/credential-store.c |  19 +++++++\n> >  builtin/merge.c            |  10 ++--\n> >  builtin/notes.c            |  16 +++---\n> >  builtin/rebase.c           |   2 +-\n> >  builtin/stripspace.c       |   6 ++-\n> >  builtin/tag.c              |   9 ++--\n> >  fmt-merge-msg.c            |   9 ++--\n> >  gpg-interface.c            |   5 +-\n> >  hook.c                     |   1 +\n> >  object-name.c              |  15 ++++++\n> >  object-name.h              |   9 ++++\n> >  path.c                     |  20 +++++++\n> >  path.h                     |   5 ++\n> >  pretty.c                   |   1 +\n> >  rebase-interactive.c       |  15 +++---\n> >  sequencer.c                |  24 +++++----\n> >  strbuf.c                   | 106 +++----------------------------------\n> >  strbuf.h                   |  44 ++-------------\n> >  tempfile.c                 |   1 +\n> >  wt-status.c                |   6 +--\n> >  26 files changed, 213 insertions(+), 187 deletions(-)\n> >\n> > --\n> > 2.40.1.495.gc816e09b53d-goog\n>\n> The series looks pretty good to me.  I left a couple small comments on\n> 5/6 and 6/6.  One other high-level note:\n>\n> As Ævar noted over at\n> https://lore.kernel.org/git/230501.86a5yohsme.gmgdl@evledraar.gmail.com/,\n> strbuf_add_separated_string_list() is currently only used by\n> merge-ort.c and merge-recursive.c (both of which include\n> merge-recursive.h).  It may make sense to move that function, and that\n> would permit you to drop the forward declaration of 'struct\n> string_list;' from strbuf.c as well.\n"},{"id":"476537","messageId":"CAFySSZCAmgw=f81Jb2f45_nN4hL-k6vct2hb7rhqfHkdOOBVLQ@mail.gmail.com","threadId":"59685","inReplyTo":"20230503163446.GB1789686@coredump.intra.peff.net","subject":"Re: [PATCH 2/6] credential-store: move related functions to credential-store file","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:38:02Z","receivedAt":"2023-05-03T18:38:17Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Thanks for digging up the history and context for these functions. I\nagree that refactoring these functions right now is not worth it and\ncan be saved for when there would be new callers to them.\n\nOn Wed, May 3, 2023 at 9:34 AM Jeff King <peff@peff.net> wrote:\n>\n> On Wed, May 03, 2023 at 12:28:58PM -0400, Jeff King wrote:\n>\n> > I think the main reason we do not have other callers is that urlmatch.c\n> > implements its own percent-encoding code, and that's where we do most of\n> > our URL handling. It does make me wonder if credential-store could\n> > simply switch to using that, but that is probably out of scope for your\n> > series.\n>\n> Poking at it a bit, I think the answer is \"not easily\". credential-store\n> has broken-out elements of a URL, and wants to turn them back into one.\n> And urlmatch.c's url_normalize() always takes a URL string as input.\n> Even though it finds the broken-out fields as part of its work, the\n> parsing and reconstruction of the URL are inter-mingled in a complex\n> way (i.e., it's not just \"parse it, then turn the fields back into a\n> normalized string).\n>\n> I'm sure it could be refactored, but it's probably not worth it (and\n> again, this tangent is somewhat orthogonal to your series, except that\n> it would make these is_rfc3986 functions go away entirely).\n>\n> -Peff\n"},{"id":"476539","messageId":"20230503184849.1809304-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230502211454.1673000-1-calvinwan@google.com","subject":"[PATCH v2 0/7] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:48:49Z","receivedAt":"2023-05-03T18:49:21Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Strbuf is a widely used basic structure that should only interact with\nother primitives in strbuf.[ch]. Over time certain functions inside of\nstrbuf.[ch] have been added to interact with higher level objects and\nfunctions. This series cleans up some of those higher level interactions\nby moving the offending functions to the files they interact with and\nadding documentation to strbuf.h. With the goal of eventually being able\nto stand up strbuf as a libary, this series also removes the use of\nenvironment variables from strbuf.\n\nCalvin Wan (7):\n  strbuf: clarify API boundary\n  abspath: move related functions to abspath\n  credential-store: move related functions to credential-store file\n  object-name: move related functions to object-name\n  path: move related function to path\n  strbuf: clarify dependency\n  strbuf: remove environment variables\n\n abspath.c                  |  36 +++++++++++++\n abspath.h                  |  21 ++++++++\n add-patch.c                |  12 +++--\n builtin/am.c               |   2 +-\n builtin/branch.c           |   4 +-\n builtin/commit.c           |   2 +-\n builtin/credential-store.c |  19 +++++++\n builtin/merge.c            |  10 ++--\n builtin/notes.c            |  16 +++---\n builtin/rebase.c           |   2 +-\n builtin/stripspace.c       |   6 ++-\n builtin/tag.c              |   9 ++--\n fmt-merge-msg.c            |   9 ++--\n gpg-interface.c            |   5 +-\n hook.c                     |   1 +\n object-name.c              |  15 ++++++\n object-name.h              |   9 ++++\n path.c                     |  20 +++++++\n path.h                     |   5 ++\n pretty.c                   |   1 +\n rebase-interactive.c       |  15 +++---\n sequencer.c                |  24 +++++----\n strbuf.c                   | 106 +++----------------------------------\n strbuf.h                   |  53 +++++--------------\n tempfile.c                 |   1 +\n wt-status.c                |   6 +--\n 26 files changed, 220 insertions(+), 189 deletions(-)\n\nRange-diff against v1:\n-:  ---------- > 1:  e0dd3f5295 strbuf: clarify API boundary\n1:  283771c088 ! 2:  ec1ea6ae4f abspath: move related functions to abspath\n    @@ Commit message\n         abspath: move related functions to abspath\n     \n         Move abspath-related functions from strbuf.[ch] to abspath.[ch] since\n    -    they do not belong in a low-level library.\n    +    paths are not primitive objects and therefore strbuf should not interact\n    +    with them.\n     \n      ## abspath.c ##\n     @@ abspath.c: char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n2:  58f78b8ae0 = 3:  2d74561b91 credential-store: move related functions to credential-store file\n3:  88ab90c079 ! 4:  30b5e635cb object-name: move related functions to object-name\n    @@ Commit message\n         object-name: move related functions to object-name\n     \n         Move object-name-related functions from strbuf.[ch] to object-name.[ch]\n    -    since they do not belong in a low-level library.\n    +    since paths are not a primitive object that strbuf should directly\n    +    interact with.\n     \n      ## object-name.c ##\n     @@ object-name.c: static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n4:  30b7de5a81 ! 5:  6905618470 path: move related function to path\n    @@ Metadata\n      ## Commit message ##\n         path: move related function to path\n     \n    -    Move path-related function from strbuf.[ch] to path.[ch] since it does\n    -    not belong in a low-level library.\n    +    Move path-related function from strbuf.[ch] to path.[ch] since path is\n    +    not a primitive object and therefore strbuf should not directly interact\n    +    with it.\n     \n      ## path.c ##\n     @@ path.c: int normalize_path_copy(char *dst, const char *src)\n5:  7b6d6353de ! 6:  caf3482bf7 strbuf: clarify dependency\n    @@ Metadata\n      ## Commit message ##\n         strbuf: clarify dependency\n     \n    +    refs.h was once needed but is no longer so as of 6bab74e7fb8 (\"strbuf:\n    +    move strbuf_branchname to sha1_name.c\", 2010-11-06). strbuf.h was\n    +    included thru refs.h, so removing refs.h requires strbuf.h to be added\n    +    back.\n    +\n      ## strbuf.c ##\n     @@\n      #include \"environment.h\"\n6:  ffacd1cbe5 ! 7:  a7f23488f8 strbuf: remove enviroment variables\n    @@ Metadata\n     Author: Calvin Wan <calvinwan@google.com>\n     \n      ## Commit message ##\n    -    strbuf: remove enviroment variables\n    +    strbuf: remove environment variables\n     \n    -    As a lower level library, strbuf should not directly access environment\n    -    variables within its functions. Therefore, add an additional variable to\n    -    function signatures for functions that use an environment variable and\n    -    refactor callers to pass in the environment variable.\n    +    As a library that only interacts with other primitives, strbuf should\n    +    not directly access environment variables within its\n    +    functions. Therefore, add an additional variable to function signatures\n    +    for functions that use an environment variable and refactor callers to\n    +    pass in the environment variable.\n     \n      ## add-patch.c ##\n     @@ add-patch.c: static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n    @@ strbuf.h: void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n      __attribute__((format (printf,2,0)))\n      void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n     @@ strbuf.h: int strbuf_normalize_path(struct strbuf *sb);\n    + \n    + /**\n       * Strip whitespace from a buffer. The second parameter controls if\n    -  * comments are considered contents to be removed or not.\n    +- * comments are considered contents to be removed or not.\n    ++ * comments are considered contents to be removed or not. The third parameter\n    ++ * is the comment character that determines whether a line is a comment or not.\n       */\n     -void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n     +void strbuf_stripspace(struct strbuf *buf, int skip_comments, char comment_line_char);\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476540","messageId":"20230503185031.1810078-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"[PATCH v2 1/7] strbuf: clarify API boundary","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:50:25Z","receivedAt":"2023-05-03T18:51:07Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"strbuf, as a generic and widely used structure across the codebase,\nshould be limited as a libary to only interact with primitives. Add\ndocumentation so future functions can be appropriately be placed. Older\nfunctions that do not follow this boundary should eventually be moved or\nrefactored.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.h | 6 +++++-\n 1 file changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/strbuf.h b/strbuf.h\nindex 3dfeadb44c..c856253216 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -5,7 +5,11 @@ struct string_list;\n \n /**\n  * strbuf's are meant to be used with all the usual C string and memory\n- * APIs. Given that the length of the buffer is known, it's often better to\n+ * APIs. The objects that this API interacts with in this file should be \n+ * limited to other primitives, however, there are older functions in here \n+ * that should eventually be moved out or refactored. \n+ * \n+ * Given that the length of the buffer is known, it's often better to\n  * use the mem* functions than a str* one (memchr vs. strchr e.g.).\n  * Though, one has to be careful about the fact that str* functions often\n  * stop on NULs and that strbufs may have embedded NULs.\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476541","messageId":"20230503185031.1810078-2-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"[PATCH v2 2/7] abspath: move related functions to abspath","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:50:26Z","receivedAt":"2023-05-03T18:51:08Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move abspath-related functions from strbuf.[ch] to abspath.[ch] since\npaths are not primitive objects and therefore strbuf should not interact\nwith them.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n abspath.c  | 36 ++++++++++++++++++++++++++++++++++++\n abspath.h  | 21 +++++++++++++++++++++\n hook.c     |  1 +\n strbuf.c   | 37 -------------------------------------\n strbuf.h   | 22 ----------------------\n tempfile.c |  1 +\n 6 files changed, 59 insertions(+), 59 deletions(-)\n\ndiff --git a/abspath.c b/abspath.c\nindex d032f5dce5..1202cde23d 100644\n--- a/abspath.c\n+++ b/abspath.c\n@@ -289,3 +289,39 @@ char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n \t\treturn xstrdup(arg);\n \treturn prefix_filename(pfx, arg);\n }\n+\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n+{\n+\tif (!*path)\n+\t\tdie(\"The empty string is not a valid path\");\n+\tif (!is_absolute_path(path)) {\n+\t\tstruct stat cwd_stat, pwd_stat;\n+\t\tsize_t orig_len = sb->len;\n+\t\tchar *cwd = xgetcwd();\n+\t\tchar *pwd = getenv(\"PWD\");\n+\t\tif (pwd && strcmp(pwd, cwd) &&\n+\t\t    !stat(cwd, &cwd_stat) &&\n+\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n+\t\t    !stat(pwd, &pwd_stat) &&\n+\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n+\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n+\t\t\tstrbuf_addstr(sb, pwd);\n+\t\telse\n+\t\t\tstrbuf_addstr(sb, cwd);\n+\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n+\t\t\tstrbuf_addch(sb, '/');\n+\t\tfree(cwd);\n+\t}\n+\tstrbuf_addstr(sb, path);\n+}\n+\n+void strbuf_add_real_path(struct strbuf *sb, const char *path)\n+{\n+\tif (sb->len) {\n+\t\tstruct strbuf resolved = STRBUF_INIT;\n+\t\tstrbuf_realpath(&resolved, path, 1);\n+\t\tstrbuf_addbuf(sb, &resolved);\n+\t\tstrbuf_release(&resolved);\n+\t} else\n+\t\tstrbuf_realpath(sb, path, 1);\n+}\ndiff --git a/abspath.h b/abspath.h\nindex 7cd3de5e9d..4653080d5e 100644\n--- a/abspath.h\n+++ b/abspath.h\n@@ -30,4 +30,25 @@ static inline int is_absolute_path(const char *path)\n \treturn is_dir_sep(path[0]) || has_dos_drive_prefix(path);\n }\n \n+/**\n+ * Add a path to a buffer, converting a relative path to an\n+ * absolute one in the process.  Symbolic links are not\n+ * resolved.\n+ */\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n+\n+/**\n+ * Canonize `path` (make it absolute, resolve symlinks, remove extra\n+ * slashes) and append it to `sb`.  Die with an informative error\n+ * message if there is a problem.\n+ *\n+ * The directory part of `path` (i.e., everything up to the last\n+ * dir_sep) must denote a valid, existing directory, but the last\n+ * component need not exist.\n+ *\n+ * Callers that don't mind links should use the more lightweight\n+ * strbuf_add_absolute_path() instead.\n+ */\n+void strbuf_add_real_path(struct strbuf *sb, const char *path);\n+\n #endif /* ABSPATH_H */\ndiff --git a/hook.c b/hook.c\nindex 76e322f580..2d8706371e 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -1,4 +1,5 @@\n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hook.h\"\ndiff --git a/strbuf.c b/strbuf.c\nindex 729378ec82..c3b6d48797 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,5 +1,4 @@\n #include \"git-compat-util.h\"\n-#include \"abspath.h\"\n #include \"alloc.h\"\n #include \"environment.h\"\n #include \"gettext.h\"\n@@ -899,42 +898,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)\n \tstrbuf_humanise(buf, bytes, 1);\n }\n \n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n-{\n-\tif (!*path)\n-\t\tdie(\"The empty string is not a valid path\");\n-\tif (!is_absolute_path(path)) {\n-\t\tstruct stat cwd_stat, pwd_stat;\n-\t\tsize_t orig_len = sb->len;\n-\t\tchar *cwd = xgetcwd();\n-\t\tchar *pwd = getenv(\"PWD\");\n-\t\tif (pwd && strcmp(pwd, cwd) &&\n-\t\t    !stat(cwd, &cwd_stat) &&\n-\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n-\t\t    !stat(pwd, &pwd_stat) &&\n-\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n-\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n-\t\t\tstrbuf_addstr(sb, pwd);\n-\t\telse\n-\t\t\tstrbuf_addstr(sb, cwd);\n-\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n-\t\t\tstrbuf_addch(sb, '/');\n-\t\tfree(cwd);\n-\t}\n-\tstrbuf_addstr(sb, path);\n-}\n-\n-void strbuf_add_real_path(struct strbuf *sb, const char *path)\n-{\n-\tif (sb->len) {\n-\t\tstruct strbuf resolved = STRBUF_INIT;\n-\t\tstrbuf_realpath(&resolved, path, 1);\n-\t\tstrbuf_addbuf(sb, &resolved);\n-\t\tstrbuf_release(&resolved);\n-\t} else\n-\t\tstrbuf_realpath(sb, path, 1);\n-}\n-\n int printf_ln(const char *fmt, ...)\n {\n \tint ret;\ndiff --git a/strbuf.h b/strbuf.h\nindex c856253216..20d0e37d9c 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -531,28 +531,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);\n  */\n int strbuf_getcwd(struct strbuf *sb);\n \n-/**\n- * Add a path to a buffer, converting a relative path to an\n- * absolute one in the process.  Symbolic links are not\n- * resolved.\n- */\n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n-\n-/**\n- * Canonize `path` (make it absolute, resolve symlinks, remove extra\n- * slashes) and append it to `sb`.  Die with an informative error\n- * message if there is a problem.\n- *\n- * The directory part of `path` (i.e., everything up to the last\n- * dir_sep) must denote a valid, existing directory, but the last\n- * component need not exist.\n- *\n- * Callers that don't mind links should use the more lightweight\n- * strbuf_add_absolute_path() instead.\n- */\n-void strbuf_add_real_path(struct strbuf *sb, const char *path);\n-\n-\n /**\n  * Normalize in-place the path contained in the strbuf. See\n  * normalize_path_copy() for details. If an error occurs, the contents of \"sb\"\ndiff --git a/tempfile.c b/tempfile.c\nindex 50c377134c..6c88a63b42 100644\n--- a/tempfile.c\n+++ b/tempfile.c\n@@ -43,6 +43,7 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"path.h\"\n #include \"tempfile.h\"\n #include \"sigchain.h\"\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476542","messageId":"20230503185031.1810078-3-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"[PATCH v2 3/7] credential-store: move related functions to credential-store file","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:50:27Z","receivedAt":"2023-05-03T18:51:10Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"is_rfc3986_unreserved() and is_rfc3986_reserved_or_unreserved() are only\ncalled from builtin/credential-store.c and they are only relevant to that\nfile so move those functions and make them static.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n builtin/credential-store.c | 19 +++++++++++++++++++\n strbuf.c                   | 19 -------------------\n strbuf.h                   |  3 ---\n 3 files changed, 19 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/credential-store.c b/builtin/credential-store.c\nindex 8977604eb9..4776118331 100644\n--- a/builtin/credential-store.c\n+++ b/builtin/credential-store.c\n@@ -73,6 +73,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,\n \t\tdie_errno(\"unable to write credential store\");\n }\n \n+static int is_rfc3986_unreserved(char ch)\n+{\n+\treturn isalnum(ch) ||\n+\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n+}\n+\n+static int is_rfc3986_reserved_or_unreserved(char ch)\n+{\n+\tif (is_rfc3986_unreserved(ch))\n+\t\treturn 1;\n+\tswitch (ch) {\n+\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n+\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n+\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static void store_credential_file(const char *fn, struct credential *c)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/strbuf.c b/strbuf.c\nindex c3b6d48797..da2693b21f 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -809,25 +809,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)\n \t}\n }\n \n-int is_rfc3986_reserved_or_unreserved(char ch)\n-{\n-\tif (is_rfc3986_unreserved(ch))\n-\t\treturn 1;\n-\tswitch (ch) {\n-\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n-\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n-\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-int is_rfc3986_unreserved(char ch)\n-{\n-\treturn isalnum(ch) ||\n-\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n-}\n-\n static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,\n \t\t\t\t char_predicate allow_unencoded_fn)\n {\ndiff --git a/strbuf.h b/strbuf.h\nindex 20d0e37d9c..9e52fe7706 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -686,9 +686,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);\n \n typedef int (*char_predicate)(char ch);\n \n-int is_rfc3986_unreserved(char ch);\n-int is_rfc3986_reserved_or_unreserved(char ch);\n-\n void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,\n \t\t\t     char_predicate allow_unencoded_fn);\n \n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476543","messageId":"20230503185031.1810078-5-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"[PATCH v2 5/7] path: move related function to path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:50:29Z","receivedAt":"2023-05-03T18:51:13Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move path-related function from strbuf.[ch] to path.[ch] since path is\nnot a primitive object and therefore strbuf should not directly interact\nwith it.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n path.c   | 20 ++++++++++++++++++++\n path.h   |  5 +++++\n strbuf.c | 20 --------------------\n 3 files changed, 25 insertions(+), 20 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 7c1cd8182a..e17a2613c5 100644\n--- a/path.c\n+++ b/path.c\n@@ -1213,6 +1213,26 @@ int normalize_path_copy(char *dst, const char *src)\n \treturn normalize_path_copy_len(dst, src, NULL);\n }\n \n+int strbuf_normalize_path(struct strbuf *src)\n+{\n+\tstruct strbuf dst = STRBUF_INIT;\n+\n+\tstrbuf_grow(&dst, src->len);\n+\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n+\t\tstrbuf_release(&dst);\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * normalize_path does not tell us the new length, so we have to\n+\t * compute it by looking for the new NUL it placed\n+\t */\n+\tstrbuf_setlen(&dst, strlen(dst.buf));\n+\tstrbuf_swap(src, &dst);\n+\tstrbuf_release(&dst);\n+\treturn 0;\n+}\n+\n /*\n  * path = Canonical absolute path\n  * prefixes = string_list containing normalized, absolute paths without\ndiff --git a/path.h b/path.h\nindex 60e83a49a9..639372edd9 100644\n--- a/path.h\n+++ b/path.h\n@@ -191,6 +191,11 @@ const char *remove_leading_path(const char *in, const char *prefix);\n const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);\n int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);\n int normalize_path_copy(char *dst, const char *src);\n+/**\n+ * Normalize in-place the path contained in the strbuf. If an error occurs,\n+ * the contents of \"sb\" are left untouched, and -1 is returned.\n+ */\n+int strbuf_normalize_path(struct strbuf *src);\n int longest_ancestor_length(const char *path, struct string_list *prefixes);\n char *strip_path_suffix(const char *path, const char *suffix);\n int daemon_avoid_alias(const char *path);\ndiff --git a/strbuf.c b/strbuf.c\nindex 6533559e95..178d75f250 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1088,26 +1088,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \tstrbuf_setlen(sb, j);\n }\n \n-int strbuf_normalize_path(struct strbuf *src)\n-{\n-\tstruct strbuf dst = STRBUF_INIT;\n-\n-\tstrbuf_grow(&dst, src->len);\n-\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n-\t\tstrbuf_release(&dst);\n-\t\treturn -1;\n-\t}\n-\n-\t/*\n-\t * normalize_path does not tell us the new length, so we have to\n-\t * compute it by looking for the new NUL it placed\n-\t */\n-\tstrbuf_setlen(&dst, strlen(dst.buf));\n-\tstrbuf_swap(src, &dst);\n-\tstrbuf_release(&dst);\n-\treturn 0;\n-}\n-\n void strbuf_strip_file_from_path(struct strbuf *sb)\n {\n \tchar *path_sep = find_last_dir_sep(sb->buf);\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476544","messageId":"20230503185031.1810078-4-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"[PATCH v2 4/7] object-name: move related functions to object-name","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:50:28Z","receivedAt":"2023-05-03T18:51:14Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move object-name-related functions from strbuf.[ch] to object-name.[ch]\nsince paths are not a primitive object that strbuf should directly\ninteract with.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n object-name.c | 15 +++++++++++++++\n object-name.h |  9 +++++++++\n pretty.c      |  1 +\n strbuf.c      | 16 ----------------\n strbuf.h      | 10 ----------\n 5 files changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 538e8a8f62..c2e82aceea 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -766,6 +766,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n \t\tfind_abbrev_len_for_pack(p, mad);\n }\n \n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len)\n+{\n+\tint r;\n+\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n+\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n+\tstrbuf_setlen(sb, sb->len + r);\n+}\n+\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len)\n+{\n+\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n+}\n+\n int repo_find_unique_abbrev_r(struct repository *r, char *hex,\n \t\t\t      const struct object_id *oid, int len)\n {\ndiff --git a/object-name.h b/object-name.h\nindex 1d63698f42..9ae5223071 100644\n--- a/object-name.h\n+++ b/object-name.h\n@@ -40,6 +40,15 @@ struct object_context {\n const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);\n int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);\n \n+/**\n+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n+ * the strbuf `sb`.\n+ */\n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len);\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len);\n+\n int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);\n __attribute__((format (printf, 2, 3)))\n int get_oidf(struct object_id *oid, const char *fmt, ...);\ndiff --git a/pretty.c b/pretty.c\nindex 0bb938021b..78bac2d818 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -18,6 +18,7 @@\n #include \"gpg-interface.h\"\n #include \"trailer.h\"\n #include \"run-command.h\"\n+#include \"object-name.h\"\n \n /*\n  * The limit for formatting directives, which enable the caller to append\ndiff --git a/strbuf.c b/strbuf.c\nindex da2693b21f..6533559e95 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,6 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"object-name.h\"\n #include \"refs.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n@@ -1023,21 +1022,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,\n \tstrbuf_setlen(sb, sb->len + len);\n }\n \n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len)\n-{\n-\tint r;\n-\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n-\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n-\tstrbuf_setlen(sb, sb->len + r);\n-}\n-\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len)\n-{\n-\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n-}\n-\n /*\n  * Returns the length of a line, without trailing spaces.\n  *\ndiff --git a/strbuf.h b/strbuf.h\nindex 9e52fe7706..1bae7e0f47 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -612,16 +612,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,\n  */\n void strbuf_list_free(struct strbuf **list);\n \n-/**\n- * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n- * the strbuf `sb`.\n- */\n-struct repository;\n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len);\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len);\n-\n /*\n  * Remove the filename from the provided path string. If the path\n  * contains a trailing separator, then the path is considered a directory\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476545","messageId":"20230503185031.1810078-6-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"[PATCH v2 6/7] strbuf: clarify dependency","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:50:30Z","receivedAt":"2023-05-03T18:51:22Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"refs.h was once needed but is no longer so as of 6bab74e7fb8 (\"strbuf:\nmove strbuf_branchname to sha1_name.c\", 2010-11-06). strbuf.h was\nincluded thru refs.h, so removing refs.h requires strbuf.h to be added\nback.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex 178d75f250..d5978fee4e 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,7 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"refs.h\"\n+#include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n #include \"date.h\"\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476546","messageId":"20230503185031.1810078-7-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"[PATCH v2 7/7] strbuf: remove environment variables","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T18:50:31Z","receivedAt":"2023-05-03T18:51:24Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"As a library that only interacts with other primitives, strbuf should\nnot directly access environment variables within its\nfunctions. Therefore, add an additional variable to function signatures\nfor functions that use an environment variable and refactor callers to\npass in the environment variable.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n add-patch.c          | 12 +++++++-----\n builtin/am.c         |  2 +-\n builtin/branch.c     |  4 ++--\n builtin/commit.c     |  2 +-\n builtin/merge.c      | 10 ++++++----\n builtin/notes.c      | 16 +++++++++-------\n builtin/rebase.c     |  2 +-\n builtin/stripspace.c |  6 ++++--\n builtin/tag.c        |  9 ++++++---\n fmt-merge-msg.c      |  9 ++++++---\n gpg-interface.c      |  5 +++--\n rebase-interactive.c | 15 ++++++++-------\n sequencer.c          | 24 +++++++++++++++---------\n strbuf.c             | 12 +++++++-----\n strbuf.h             | 12 +++++++-----\n wt-status.c          |  6 +++---\n 16 files changed, 86 insertions(+), 60 deletions(-)\n\ndiff --git a/add-patch.c b/add-patch.c\nindex 8d770d203f..9702c1aabd 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \tsize_t i;\n \n \tstrbuf_reset(&s->buf);\n-\tstrbuf_commented_addf(&s->buf, _(\"Manual hunk edit mode -- see bottom for \"\n-\t\t\t\t      \"a quick guide.\\n\"));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n+\t\t\t      _(\"Manual hunk edit mode -- see bottom for \"\n+\t\t\t\t\"a quick guide.\\n\"));\n \trender_hunk(s, hunk, 0, 0, &s->buf);\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"---\\n\"\n \t\t\t\t\"To remove '%c' lines, make them ' ' lines \"\n \t\t\t\t\"(context).\\n\"\n@@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \t\t\t      s->mode->is_reverse ? '+' : '-',\n \t\t\t      s->mode->is_reverse ? '-' : '+',\n \t\t\t      comment_line_char);\n-\tstrbuf_commented_addf(&s->buf, \"%s\", _(s->mode->edit_hunk_hint));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char, \"%s\",\n+\t\t\t      _(s->mode->edit_hunk_hint));\n \t/*\n \t * TRANSLATORS: 'it' refers to the patch mentioned in the previous\n \t * messages.\n \t */\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"If it does not apply cleanly, you will be \"\n \t\t\t\t\"given an opportunity to\\n\"\n \t\t\t\t\"edit again.  If all lines of the hunk are \"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5c83f2e003..306489db13 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n \tstrbuf_addbuf(&msg, &mi.log_message);\n-\tstrbuf_stripspace(&msg, 0);\n+\tstrbuf_stripspace(&msg, 0, comment_line_char);\n \n \tassert(!state->author_name);\n \tstate->author_name = strbuf_detach(&author_name, NULL);\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 501c47657c..e52afcf4d7 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -629,7 +629,7 @@ static int edit_branch_description(const char *branch_name)\n \texists = !read_branch_desc(&buf, branch_name);\n \tif (!buf.len || buf.buf[buf.len-1] != '\\n')\n \t\tstrbuf_addch(&buf, '\\n');\n-\tstrbuf_commented_addf(&buf,\n+\tstrbuf_commented_addf(&buf, comment_line_char,\n \t\t    _(\"Please edit the description for the branch\\n\"\n \t\t      \"  %s\\n\"\n \t\t      \"Lines starting with '%c' will be stripped.\\n\"),\n@@ -640,7 +640,7 @@ static int edit_branch_description(const char *branch_name)\n \t\tstrbuf_release(&buf);\n \t\treturn -1;\n \t}\n-\tstrbuf_stripspace(&buf, 1);\n+\tstrbuf_stripspace(&buf, 1, comment_line_char);\n \n \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n \tif (buf.len || exists)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex e67c4be221..6d3cc4d9fe 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \ts->hints = 0;\n \n \tif (clean_message_contents)\n-\t\tstrbuf_stripspace(&sb, 0);\n+\t\tstrbuf_stripspace(&sb, 0, comment_line_char);\n \n \tif (signoff)\n \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8da3e46abb..1d14767c0c 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)\n \t\tstrbuf_addch(&msg, '\\n');\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {\n \t\t\twt_status_append_cut_line(&msg);\n-\t\t\tstrbuf_commented_addf(&msg, \"\\n\");\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char, \"\\n\");\n \t\t}\n-\t\tstrbuf_commented_addf(&msg, _(merge_editor_comment));\n+\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t      _(merge_editor_comment));\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n-\t\t\tstrbuf_commented_addf(&msg, _(scissors_editor_comment));\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t\t      _(scissors_editor_comment));\n \t\telse\n-\t\t\tstrbuf_commented_addf(&msg,\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n \t\t\t\t_(no_scissors_editor_comment), comment_line_char);\n \t}\n \tif (signoff)\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex d5788352b6..0918b92752 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -11,6 +11,7 @@\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"editor.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"notes.h\"\n@@ -157,7 +158,7 @@ static void write_commented_object(int fd, const struct object_id *object)\n \n \tif (strbuf_read(&buf, show.out, 0) < 0)\n \t\tdie_errno(_(\"could not read 'show' output\"));\n-\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);\n \twrite_or_die(fd, cbuf.buf, cbuf.len);\n \n \tstrbuf_release(&cbuf);\n@@ -185,9 +186,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\t\tcopy_obj_to_fd(fd, old_note);\n \n \t\tstrbuf_addch(&buf, '\\n');\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n-\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),\n+\t\t\t\t\t   comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n \t\twrite_or_die(fd, buf.buf, buf.len);\n \n \t\twrite_commented_object(fd, object);\n@@ -199,7 +201,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\tif (launch_editor(d->edit_path, &d->buf, NULL)) {\n \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n \t\t}\n-\t\tstrbuf_stripspace(&d->buf, 1);\n+\t\tstrbuf_stripspace(&d->buf, 1, comment_line_char);\n \t}\n }\n \n@@ -225,7 +227,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \tstrbuf_addstr(&d->buf, arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n \n \td->given = 1;\n \treturn 0;\n@@ -244,7 +246,7 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n \t\t\tdie_errno(_(\"cannot read '%s'\"), arg);\n \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n \n \td->given = 1;\n \treturn 0;\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex ace1d5e8d1..d092e06dc7 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)\n \tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n \n-\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tstrbuf_stripspace(&todo_list.buf, 1, comment_line_char);\n \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 9451eb69ff..e182c2a14e 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"parse-options.h\"\n #include \"setup.h\"\n@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)\n \tsize_t len;\n \n \tmsg = strbuf_detach(buf, &len);\n-\tstrbuf_add_commented_lines(buf, msg, len);\n+\tstrbuf_add_commented_lines(buf, msg, len, comment_line_char);\n \tfree(msg);\n }\n \n@@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)\n \t\tdie_errno(\"could not read the input\");\n \n \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n-\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n+\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS,\n+\t\t\t\t  comment_line_char);\n \telse\n \t\tcomment_lines(&buf);\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1850a6a6fd..c713d14489 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n \t\t\tstrbuf_addch(&buf, '\\n');\n \t\t\tif (opt->cleanup_mode == CLEANUP_ALL)\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template), tag,comment_line_char);\n \t\t\telse\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template_nocleanup), tag, comment_line_char);\n \t\t\twrite_or_die(fd, buf.buf, buf.len);\n \t\t\tstrbuf_release(&buf);\n \t\t}\n@@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t}\n \n \tif (opt->cleanup_mode != CLEANUP_NONE)\n-\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n+\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n \n \tif (!opt->message_given && !buf->len)\n \t\tdie(_(\"no tag message?\"));\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 5af0d4715b..5d15e2387d 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,\n \tstrbuf_complete_line(tagbuf);\n \tif (sig->len) {\n \t\tstrbuf_addch(tagbuf, '\\n');\n-\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len);\n+\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len,\n+\t\t\t\t\t   comment_line_char);\n \t}\n }\n \n@@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\t\tstrbuf_addch(&tagline, '\\n');\n \t\t\t\tstrbuf_add_commented_lines(&tagline,\n \t\t\t\t\t\torigins.items[first_tag].string,\n-\t\t\t\t\t\tstrlen(origins.items[first_tag].string));\n+\t\t\t\t\t\tstrlen(origins.items[first_tag].string),\n+\t\t\t\t\t\tcomment_line_char);\n \t\t\t\tstrbuf_insert(&tagbuf, 0, tagline.buf,\n \t\t\t\t\t      tagline.len);\n \t\t\t\tstrbuf_release(&tagline);\n@@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\tstrbuf_addch(&tagbuf, '\\n');\n \t\t\tstrbuf_add_commented_lines(&tagbuf,\n \t\t\t\t\torigins.items[i].string,\n-\t\t\t\t\tstrlen(origins.items[i].string));\n+\t\t\t\t\tstrlen(origins.items[i].string),\n+\t\t\t\t\tcomment_line_char);\n \t\t\tfmt_tag_signature(&tagbuf, &sig, buf, len);\n \t\t}\n \t\tstrbuf_release(&payload);\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex f3ac5acdd9..b625f17460 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -11,6 +11,7 @@\n #include \"tempfile.h\"\n #include \"alias.h\"\n #include \"wrapper.h\"\n+#include \"environment.h\"\n \n static int git_gpg_config(const char *, const char *, void *);\n \n@@ -584,8 +585,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,\n \t\t}\n \t}\n \n-\tstrbuf_stripspace(&ssh_keygen_out, 0);\n-\tstrbuf_stripspace(&ssh_keygen_err, 0);\n+\tstrbuf_stripspace(&ssh_keygen_out, 0, comment_line_char);\n+\tstrbuf_stripspace(&ssh_keygen_err, 0, comment_line_char);\n \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 789f407361..c6027e73c1 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -71,13 +71,14 @@ void append_todo_help(int command_count,\n \n \tif (!edit_todo) {\n \t\tstrbuf_addch(buf, '\\n');\n-\t\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n-\t\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n-\t\t\t\t\t      command_count),\n+\t\tstrbuf_commented_addf(buf, comment_line_char,\n+\t\t\t\t      Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t\t \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t\t command_count),\n \t\t\t\t      shortrevisions, shortonto, command_count);\n \t}\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -86,7 +87,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -97,7 +98,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n }\n \n int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n@@ -129,7 +130,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n \tif (launch_sequence_editor(todo_file, &new_todo->buf, NULL))\n \t\treturn -2;\n \n-\tstrbuf_stripspace(&new_todo->buf, 1);\n+\tstrbuf_stripspace(&new_todo->buf, 1, comment_line_char);\n \tif (initial && new_todo->buf.len == 0)\n \t\treturn -3;\n \ndiff --git a/sequencer.c b/sequencer.c\nindex c88d1d9553..9675b62bcb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -659,11 +659,12 @@ void append_conflicts_hint(struct index_state *istate,\n \t}\n \n \tstrbuf_addch(msgbuf, '\\n');\n-\tstrbuf_commented_addf(msgbuf, \"Conflicts:\\n\");\n+\tstrbuf_commented_addf(msgbuf, comment_line_char, \"Conflicts:\\n\");\n \tfor (i = 0; i < istate->cache_nr;) {\n \t\tconst struct cache_entry *ce = istate->cache[i++];\n \t\tif (ce_stage(ce)) {\n-\t\t\tstrbuf_commented_addf(msgbuf, \"\\t%s\\n\", ce->name);\n+\t\t\tstrbuf_commented_addf(msgbuf, comment_line_char,\n+\t\t\t\t\t      \"\\t%s\\n\", ce->name);\n \t\t\twhile (i < istate->cache_nr &&\n \t\t\t       !strcmp(ce->name, istate->cache[i]->name))\n \t\t\t\ti++;\n@@ -1142,7 +1143,8 @@ void cleanup_message(struct strbuf *msgbuf,\n \t    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n }\n \n /*\n@@ -1173,7 +1175,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,\n \tif (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)\n \t\treturn 0;\n \n-\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t  comment_line_char);\n \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n \t\tstart = sb->buf;\n \tstrbuf_release(&tmpl);\n@@ -1545,7 +1548,8 @@ static int try_to_commit(struct repository *r,\n \t\tcleanup = opts->default_msg_cleanup;\n \n \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n \t\tres = 1; /* run 'git commit' to display error message */\n \t\tgoto out;\n@@ -1839,7 +1843,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n \t\ts += count;\n \t\tlen -= count;\n \t}\n-\tstrbuf_add_commented_lines(buf, s, len);\n+\tstrbuf_add_commented_lines(buf, s, len, comment_line_char);\n }\n \n /* Does the current fixup chain contain a squash command? */\n@@ -1938,7 +1942,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_add_commented_lines(buf, body, commented_len, comment_line_char);\n \t/* buf->buf may be reallocated so store an offset into the buffer */\n \tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n@@ -2028,7 +2032,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tif (is_fixup_flag(command, flag))\n-\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t\t   comment_line_char);\n \t\telse\n \t\t\tstrbuf_addstr(&buf, body);\n \n@@ -2047,7 +2052,8 @@ static int update_squash_messages(struct repository *r,\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t   comment_line_char);\n \t} else\n \t\treturn error(_(\"unknown command: %d\"), command);\n \trepo_unuse_commit_buffer(r, commit, message);\ndiff --git a/strbuf.c b/strbuf.c\nindex d5978fee4e..eba65ca421 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,6 +1,5 @@\n #include \"git-compat-util.h\"\n #include \"alloc.h\"\n-#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"strbuf.h\"\n@@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n \tstrbuf_complete_line(out);\n }\n \n-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n+\t\t\t\tsize_t size, char comment_line_char)\n {\n \tstatic char prefix1[3];\n \tstatic char prefix2[2];\n@@ -374,7 +374,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size\n \tadd_lines(out, prefix1, prefix2, buf, size);\n }\n \n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,\n+\t\t\t   const char *fmt, ...)\n {\n \tva_list params;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -384,7 +385,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n \tstrbuf_vaddf(&buf, fmt, params);\n \tva_end(params);\n \n-\tstrbuf_add_commented_lines(sb, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);\n \tif (incomplete_line)\n \t\tsb->buf[--sb->len] = '\\0';\n \n@@ -1054,7 +1055,8 @@ static size_t cleanup(char *line, size_t len)\n  * Enable skip_comments to skip every line starting with comment\n  * character.\n  */\n-void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n+void strbuf_stripspace(struct strbuf *sb, int skip_comments,\n+\t\t       char comment_line_char)\n {\n \tsize_t empties = 0;\n \tsize_t i, j, len, newlen;\ndiff --git a/strbuf.h b/strbuf.h\nindex 1bae7e0f47..bc16fa4ef9 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -287,7 +287,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n  * by a comment character and a blank.\n  */\n void strbuf_add_commented_lines(struct strbuf *out,\n-\t\t\t\tconst char *buf, size_t size);\n+\t\t\t\tconst char *buf, size_t size,\n+\t\t\t\tchar comment_line_char);\n \n \n /**\n@@ -416,8 +417,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n  * Add a formatted string prepended by a comment character and a\n  * blank to the buffer.\n  */\n-__attribute__((format (printf, 2, 3)))\n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n+__attribute__((format (printf, 3, 4)))\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n \n __attribute__((format (printf,2,0)))\n void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n@@ -540,9 +541,10 @@ int strbuf_normalize_path(struct strbuf *sb);\n \n /**\n  * Strip whitespace from a buffer. The second parameter controls if\n- * comments are considered contents to be removed or not.\n+ * comments are considered contents to be removed or not. The third parameter\n+ * is the comment character that determines whether a line is a comment or not.\n  */\n-void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n+void strbuf_stripspace(struct strbuf *buf, int skip_comments, char comment_line_char);\n \n static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n {\ndiff --git a/wt-status.c b/wt-status.c\nindex 97b9c1c035..da7734866f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1023,7 +1023,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom\n \tif (s->display_comment_prefix) {\n \t\tsize_t len;\n \t\tsummary_content = strbuf_detach(&summary, &len);\n-\t\tstrbuf_add_commented_lines(&summary, summary_content, len);\n+\t\tstrbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);\n \t\tfree(summary_content);\n \t}\n \n@@ -1098,8 +1098,8 @@ void wt_status_append_cut_line(struct strbuf *buf)\n {\n \tconst char *explanation = _(\"Do not modify or remove the line above.\\nEverything below it will be ignored.\");\n \n-\tstrbuf_commented_addf(buf, \"%s\", cut_line);\n-\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation));\n+\tstrbuf_commented_addf(buf, comment_line_char, \"%s\", cut_line);\n+\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);\n }\n \n void wt_status_add_cut_line(FILE *fp)\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476549","messageId":"xmqqednxqkun.fsf@gitster.g","threadId":"59685","inReplyTo":"20230503185031.1810078-7-calvinwan@google.com","subject":"Re: [PATCH v2 7/7] strbuf: remove environment variables","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-03T19:24:32Z","receivedAt":"2023-05-03T19:24:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> As a library that only interacts with other primitives, strbuf should\n> not directly access environment variables within its\n\n\"environment variables\" is a misnomer, as there is no getenv()\nremoved by this patch.\n\n    strbuf: stop depending on global 'comment_line_char'\n\nor something is what you meant, I think.  This patch is about only\none single variable, not about many environment variables, right?\n\n> functions. Therefore, add an additional variable to function signatures\n\nThese things that are enclosed in a pair of () after the function\ndefinition are usually called parameters.\n\n> for functions that use an environment variable and refactor callers to\n> pass in the environment variable.\n\nLikewise.\n\n> -\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n> +\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n> +\t\t\t\t      _(tag_template), tag,comment_line_char);\n\nStyle?\n"},{"id":"476550","messageId":"xmqqa5ylqkri.fsf@gitster.g","threadId":"59685","inReplyTo":"20230503185031.1810078-6-calvinwan@google.com","subject":"Re: [PATCH v2 6/7] strbuf: clarify dependency","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-03T19:26:25Z","receivedAt":"2023-05-03T19:26:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> refs.h was once needed but is no longer so as of 6bab74e7fb8 (\"strbuf:\n> move strbuf_branchname to sha1_name.c\", 2010-11-06). strbuf.h was\n> included thru refs.h, so removing refs.h requires strbuf.h to be added\n> back.\n\nOK.  Will queue.  Thanks.\n\n>\n> Signed-off-by: Calvin Wan <calvinwan@google.com>\n> ---\n>  strbuf.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/strbuf.c b/strbuf.c\n> index 178d75f250..d5978fee4e 100644\n> --- a/strbuf.c\n> +++ b/strbuf.c\n> @@ -3,7 +3,7 @@\n>  #include \"environment.h\"\n>  #include \"gettext.h\"\n>  #include \"hex.h\"\n> -#include \"refs.h\"\n> +#include \"strbuf.h\"\n>  #include \"string-list.h\"\n>  #include \"utf8.h\"\n>  #include \"date.h\"\n"},{"id":"476553","messageId":"CAFySSZDiQe+VRgc3wRk4gTwNxWiF_VmKjOu-UEop+D34+5JUXg@mail.gmail.com","threadId":"59685","inReplyTo":"xmqqednxqkun.fsf@gitster.g","subject":"Re: [PATCH v2 7/7] strbuf: remove environment variables","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T19:41:12Z","receivedAt":"2023-05-03T19:41:29Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"I'll reword and reroll just this patch real quick.\n\n\nOn Wed, May 3, 2023 at 12:24 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> > As a library that only interacts with other primitives, strbuf should\n> > not directly access environment variables within its\n>\n> \"environment variables\" is a misnomer, as there is no getenv()\n> removed by this patch.\n>\n>     strbuf: stop depending on global 'comment_line_char'\n>\n> or something is what you meant, I think.  This patch is about only\n> one single variable, not about many environment variables, right?\n>\n> > functions. Therefore, add an additional variable to function signatures\n>\n> These things that are enclosed in a pair of () after the function\n> definition are usually called parameters.\n>\n> > for functions that use an environment variable and refactor callers to\n> > pass in the environment variable.\n>\n> Likewise.\n>\n> > -                             strbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n> > +                             strbuf_commented_addf(&buf, comment_line_char,\n> > +                                   _(tag_template), tag,comment_line_char);\n>\n> Style?\n"},{"id":"476554","messageId":"20230503194201.2360016-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503185031.1810078-7-calvinwan@google.com","subject":"[PATCH v3 7/7] strbuf: remove environment variable","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-03T19:42:01Z","receivedAt":"2023-05-03T19:42:40Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"As a library that only interacts with other primitives, strbuf should\nnot utilize the comment_line_char environment variable within its\nfunctions. Therefore, add an additional parameter for functions that use\ncomment_line_char and refactor callers to pass it in instead.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n add-patch.c          | 12 +++++++-----\n builtin/am.c         |  2 +-\n builtin/branch.c     |  4 ++--\n builtin/commit.c     |  2 +-\n builtin/merge.c      | 10 ++++++----\n builtin/notes.c      | 16 +++++++++-------\n builtin/rebase.c     |  2 +-\n builtin/stripspace.c |  6 ++++--\n builtin/tag.c        |  9 ++++++---\n fmt-merge-msg.c      |  9 ++++++---\n gpg-interface.c      |  5 +++--\n rebase-interactive.c | 15 ++++++++-------\n sequencer.c          | 24 +++++++++++++++---------\n strbuf.c             | 12 +++++++-----\n strbuf.h             | 12 +++++++-----\n wt-status.c          |  6 +++---\n 16 files changed, 86 insertions(+), 60 deletions(-)\n\ndiff --git a/add-patch.c b/add-patch.c\nindex 8d770d203f..9702c1aabd 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \tsize_t i;\n \n \tstrbuf_reset(&s->buf);\n-\tstrbuf_commented_addf(&s->buf, _(\"Manual hunk edit mode -- see bottom for \"\n-\t\t\t\t      \"a quick guide.\\n\"));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n+\t\t\t      _(\"Manual hunk edit mode -- see bottom for \"\n+\t\t\t\t\"a quick guide.\\n\"));\n \trender_hunk(s, hunk, 0, 0, &s->buf);\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"---\\n\"\n \t\t\t\t\"To remove '%c' lines, make them ' ' lines \"\n \t\t\t\t\"(context).\\n\"\n@@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \t\t\t      s->mode->is_reverse ? '+' : '-',\n \t\t\t      s->mode->is_reverse ? '-' : '+',\n \t\t\t      comment_line_char);\n-\tstrbuf_commented_addf(&s->buf, \"%s\", _(s->mode->edit_hunk_hint));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char, \"%s\",\n+\t\t\t      _(s->mode->edit_hunk_hint));\n \t/*\n \t * TRANSLATORS: 'it' refers to the patch mentioned in the previous\n \t * messages.\n \t */\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"If it does not apply cleanly, you will be \"\n \t\t\t\t\"given an opportunity to\\n\"\n \t\t\t\t\"edit again.  If all lines of the hunk are \"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5c83f2e003..306489db13 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n \tstrbuf_addbuf(&msg, &mi.log_message);\n-\tstrbuf_stripspace(&msg, 0);\n+\tstrbuf_stripspace(&msg, 0, comment_line_char);\n \n \tassert(!state->author_name);\n \tstate->author_name = strbuf_detach(&author_name, NULL);\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 501c47657c..e52afcf4d7 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -629,7 +629,7 @@ static int edit_branch_description(const char *branch_name)\n \texists = !read_branch_desc(&buf, branch_name);\n \tif (!buf.len || buf.buf[buf.len-1] != '\\n')\n \t\tstrbuf_addch(&buf, '\\n');\n-\tstrbuf_commented_addf(&buf,\n+\tstrbuf_commented_addf(&buf, comment_line_char,\n \t\t    _(\"Please edit the description for the branch\\n\"\n \t\t      \"  %s\\n\"\n \t\t      \"Lines starting with '%c' will be stripped.\\n\"),\n@@ -640,7 +640,7 @@ static int edit_branch_description(const char *branch_name)\n \t\tstrbuf_release(&buf);\n \t\treturn -1;\n \t}\n-\tstrbuf_stripspace(&buf, 1);\n+\tstrbuf_stripspace(&buf, 1, comment_line_char);\n \n \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n \tif (buf.len || exists)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex e67c4be221..6d3cc4d9fe 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \ts->hints = 0;\n \n \tif (clean_message_contents)\n-\t\tstrbuf_stripspace(&sb, 0);\n+\t\tstrbuf_stripspace(&sb, 0, comment_line_char);\n \n \tif (signoff)\n \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8da3e46abb..1d14767c0c 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)\n \t\tstrbuf_addch(&msg, '\\n');\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {\n \t\t\twt_status_append_cut_line(&msg);\n-\t\t\tstrbuf_commented_addf(&msg, \"\\n\");\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char, \"\\n\");\n \t\t}\n-\t\tstrbuf_commented_addf(&msg, _(merge_editor_comment));\n+\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t      _(merge_editor_comment));\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n-\t\t\tstrbuf_commented_addf(&msg, _(scissors_editor_comment));\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t\t      _(scissors_editor_comment));\n \t\telse\n-\t\t\tstrbuf_commented_addf(&msg,\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n \t\t\t\t_(no_scissors_editor_comment), comment_line_char);\n \t}\n \tif (signoff)\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex d5788352b6..0918b92752 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -11,6 +11,7 @@\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"editor.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"notes.h\"\n@@ -157,7 +158,7 @@ static void write_commented_object(int fd, const struct object_id *object)\n \n \tif (strbuf_read(&buf, show.out, 0) < 0)\n \t\tdie_errno(_(\"could not read 'show' output\"));\n-\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);\n \twrite_or_die(fd, cbuf.buf, cbuf.len);\n \n \tstrbuf_release(&cbuf);\n@@ -185,9 +186,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\t\tcopy_obj_to_fd(fd, old_note);\n \n \t\tstrbuf_addch(&buf, '\\n');\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n-\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),\n+\t\t\t\t\t   comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n \t\twrite_or_die(fd, buf.buf, buf.len);\n \n \t\twrite_commented_object(fd, object);\n@@ -199,7 +201,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\tif (launch_editor(d->edit_path, &d->buf, NULL)) {\n \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n \t\t}\n-\t\tstrbuf_stripspace(&d->buf, 1);\n+\t\tstrbuf_stripspace(&d->buf, 1, comment_line_char);\n \t}\n }\n \n@@ -225,7 +227,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \tstrbuf_addstr(&d->buf, arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n \n \td->given = 1;\n \treturn 0;\n@@ -244,7 +246,7 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n \t\t\tdie_errno(_(\"cannot read '%s'\"), arg);\n \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n \n \td->given = 1;\n \treturn 0;\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex ace1d5e8d1..d092e06dc7 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)\n \tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n \n-\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tstrbuf_stripspace(&todo_list.buf, 1, comment_line_char);\n \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 9451eb69ff..e182c2a14e 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"parse-options.h\"\n #include \"setup.h\"\n@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)\n \tsize_t len;\n \n \tmsg = strbuf_detach(buf, &len);\n-\tstrbuf_add_commented_lines(buf, msg, len);\n+\tstrbuf_add_commented_lines(buf, msg, len, comment_line_char);\n \tfree(msg);\n }\n \n@@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)\n \t\tdie_errno(\"could not read the input\");\n \n \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n-\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n+\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS,\n+\t\t\t\t  comment_line_char);\n \telse\n \t\tcomment_lines(&buf);\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1850a6a6fd..e7e2511f0c 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n \t\t\tstrbuf_addch(&buf, '\\n');\n \t\t\tif (opt->cleanup_mode == CLEANUP_ALL)\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template), tag, comment_line_char);\n \t\t\telse\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template_nocleanup), tag, comment_line_char);\n \t\t\twrite_or_die(fd, buf.buf, buf.len);\n \t\t\tstrbuf_release(&buf);\n \t\t}\n@@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t}\n \n \tif (opt->cleanup_mode != CLEANUP_NONE)\n-\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n+\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n \n \tif (!opt->message_given && !buf->len)\n \t\tdie(_(\"no tag message?\"));\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 5af0d4715b..5d15e2387d 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,\n \tstrbuf_complete_line(tagbuf);\n \tif (sig->len) {\n \t\tstrbuf_addch(tagbuf, '\\n');\n-\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len);\n+\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len,\n+\t\t\t\t\t   comment_line_char);\n \t}\n }\n \n@@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\t\tstrbuf_addch(&tagline, '\\n');\n \t\t\t\tstrbuf_add_commented_lines(&tagline,\n \t\t\t\t\t\torigins.items[first_tag].string,\n-\t\t\t\t\t\tstrlen(origins.items[first_tag].string));\n+\t\t\t\t\t\tstrlen(origins.items[first_tag].string),\n+\t\t\t\t\t\tcomment_line_char);\n \t\t\t\tstrbuf_insert(&tagbuf, 0, tagline.buf,\n \t\t\t\t\t      tagline.len);\n \t\t\t\tstrbuf_release(&tagline);\n@@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\tstrbuf_addch(&tagbuf, '\\n');\n \t\t\tstrbuf_add_commented_lines(&tagbuf,\n \t\t\t\t\torigins.items[i].string,\n-\t\t\t\t\tstrlen(origins.items[i].string));\n+\t\t\t\t\tstrlen(origins.items[i].string),\n+\t\t\t\t\tcomment_line_char);\n \t\t\tfmt_tag_signature(&tagbuf, &sig, buf, len);\n \t\t}\n \t\tstrbuf_release(&payload);\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex f3ac5acdd9..b625f17460 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -11,6 +11,7 @@\n #include \"tempfile.h\"\n #include \"alias.h\"\n #include \"wrapper.h\"\n+#include \"environment.h\"\n \n static int git_gpg_config(const char *, const char *, void *);\n \n@@ -584,8 +585,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,\n \t\t}\n \t}\n \n-\tstrbuf_stripspace(&ssh_keygen_out, 0);\n-\tstrbuf_stripspace(&ssh_keygen_err, 0);\n+\tstrbuf_stripspace(&ssh_keygen_out, 0, comment_line_char);\n+\tstrbuf_stripspace(&ssh_keygen_err, 0, comment_line_char);\n \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 789f407361..c6027e73c1 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -71,13 +71,14 @@ void append_todo_help(int command_count,\n \n \tif (!edit_todo) {\n \t\tstrbuf_addch(buf, '\\n');\n-\t\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n-\t\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n-\t\t\t\t\t      command_count),\n+\t\tstrbuf_commented_addf(buf, comment_line_char,\n+\t\t\t\t      Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t\t \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t\t command_count),\n \t\t\t\t      shortrevisions, shortonto, command_count);\n \t}\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -86,7 +87,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -97,7 +98,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n }\n \n int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n@@ -129,7 +130,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n \tif (launch_sequence_editor(todo_file, &new_todo->buf, NULL))\n \t\treturn -2;\n \n-\tstrbuf_stripspace(&new_todo->buf, 1);\n+\tstrbuf_stripspace(&new_todo->buf, 1, comment_line_char);\n \tif (initial && new_todo->buf.len == 0)\n \t\treturn -3;\n \ndiff --git a/sequencer.c b/sequencer.c\nindex c88d1d9553..9675b62bcb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -659,11 +659,12 @@ void append_conflicts_hint(struct index_state *istate,\n \t}\n \n \tstrbuf_addch(msgbuf, '\\n');\n-\tstrbuf_commented_addf(msgbuf, \"Conflicts:\\n\");\n+\tstrbuf_commented_addf(msgbuf, comment_line_char, \"Conflicts:\\n\");\n \tfor (i = 0; i < istate->cache_nr;) {\n \t\tconst struct cache_entry *ce = istate->cache[i++];\n \t\tif (ce_stage(ce)) {\n-\t\t\tstrbuf_commented_addf(msgbuf, \"\\t%s\\n\", ce->name);\n+\t\t\tstrbuf_commented_addf(msgbuf, comment_line_char,\n+\t\t\t\t\t      \"\\t%s\\n\", ce->name);\n \t\t\twhile (i < istate->cache_nr &&\n \t\t\t       !strcmp(ce->name, istate->cache[i]->name))\n \t\t\t\ti++;\n@@ -1142,7 +1143,8 @@ void cleanup_message(struct strbuf *msgbuf,\n \t    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n }\n \n /*\n@@ -1173,7 +1175,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,\n \tif (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)\n \t\treturn 0;\n \n-\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t  comment_line_char);\n \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n \t\tstart = sb->buf;\n \tstrbuf_release(&tmpl);\n@@ -1545,7 +1548,8 @@ static int try_to_commit(struct repository *r,\n \t\tcleanup = opts->default_msg_cleanup;\n \n \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n \t\tres = 1; /* run 'git commit' to display error message */\n \t\tgoto out;\n@@ -1839,7 +1843,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n \t\ts += count;\n \t\tlen -= count;\n \t}\n-\tstrbuf_add_commented_lines(buf, s, len);\n+\tstrbuf_add_commented_lines(buf, s, len, comment_line_char);\n }\n \n /* Does the current fixup chain contain a squash command? */\n@@ -1938,7 +1942,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_add_commented_lines(buf, body, commented_len, comment_line_char);\n \t/* buf->buf may be reallocated so store an offset into the buffer */\n \tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n@@ -2028,7 +2032,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tif (is_fixup_flag(command, flag))\n-\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t\t   comment_line_char);\n \t\telse\n \t\t\tstrbuf_addstr(&buf, body);\n \n@@ -2047,7 +2052,8 @@ static int update_squash_messages(struct repository *r,\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t   comment_line_char);\n \t} else\n \t\treturn error(_(\"unknown command: %d\"), command);\n \trepo_unuse_commit_buffer(r, commit, message);\ndiff --git a/strbuf.c b/strbuf.c\nindex d5978fee4e..eba65ca421 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,6 +1,5 @@\n #include \"git-compat-util.h\"\n #include \"alloc.h\"\n-#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"strbuf.h\"\n@@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n \tstrbuf_complete_line(out);\n }\n \n-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n+\t\t\t\tsize_t size, char comment_line_char)\n {\n \tstatic char prefix1[3];\n \tstatic char prefix2[2];\n@@ -374,7 +374,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size\n \tadd_lines(out, prefix1, prefix2, buf, size);\n }\n \n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,\n+\t\t\t   const char *fmt, ...)\n {\n \tva_list params;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -384,7 +385,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n \tstrbuf_vaddf(&buf, fmt, params);\n \tva_end(params);\n \n-\tstrbuf_add_commented_lines(sb, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);\n \tif (incomplete_line)\n \t\tsb->buf[--sb->len] = '\\0';\n \n@@ -1054,7 +1055,8 @@ static size_t cleanup(char *line, size_t len)\n  * Enable skip_comments to skip every line starting with comment\n  * character.\n  */\n-void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n+void strbuf_stripspace(struct strbuf *sb, int skip_comments,\n+\t\t       char comment_line_char)\n {\n \tsize_t empties = 0;\n \tsize_t i, j, len, newlen;\ndiff --git a/strbuf.h b/strbuf.h\nindex 1bae7e0f47..bc16fa4ef9 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -287,7 +287,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n  * by a comment character and a blank.\n  */\n void strbuf_add_commented_lines(struct strbuf *out,\n-\t\t\t\tconst char *buf, size_t size);\n+\t\t\t\tconst char *buf, size_t size,\n+\t\t\t\tchar comment_line_char);\n \n \n /**\n@@ -416,8 +417,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n  * Add a formatted string prepended by a comment character and a\n  * blank to the buffer.\n  */\n-__attribute__((format (printf, 2, 3)))\n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n+__attribute__((format (printf, 3, 4)))\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n \n __attribute__((format (printf,2,0)))\n void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n@@ -540,9 +541,10 @@ int strbuf_normalize_path(struct strbuf *sb);\n \n /**\n  * Strip whitespace from a buffer. The second parameter controls if\n- * comments are considered contents to be removed or not.\n+ * comments are considered contents to be removed or not. The third parameter\n+ * is the comment character that determines whether a line is a comment or not.\n  */\n-void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n+void strbuf_stripspace(struct strbuf *buf, int skip_comments, char comment_line_char);\n \n static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n {\ndiff --git a/wt-status.c b/wt-status.c\nindex 97b9c1c035..da7734866f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1023,7 +1023,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom\n \tif (s->display_comment_prefix) {\n \t\tsize_t len;\n \t\tsummary_content = strbuf_detach(&summary, &len);\n-\t\tstrbuf_add_commented_lines(&summary, summary_content, len);\n+\t\tstrbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);\n \t\tfree(summary_content);\n \t}\n \n@@ -1098,8 +1098,8 @@ void wt_status_append_cut_line(struct strbuf *buf)\n {\n \tconst char *explanation = _(\"Do not modify or remove the line above.\\nEverything below it will be ignored.\");\n \n-\tstrbuf_commented_addf(buf, \"%s\", cut_line);\n-\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation));\n+\tstrbuf_commented_addf(buf, comment_line_char, \"%s\", cut_line);\n+\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);\n }\n \n void wt_status_add_cut_line(FILE *fp)\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476555","messageId":"xmqqwn1pp5bg.fsf@gitster.g","threadId":"59685","inReplyTo":"CAFySSZDiQe+VRgc3wRk4gTwNxWiF_VmKjOu-UEop+D34+5JUXg@mail.gmail.com","subject":"Re: [PATCH v2 7/7] strbuf: remove environment variables","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-03T19:45:23Z","receivedAt":"2023-05-03T19:45:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> I'll reword and reroll just this patch real quick.\n\nNo need to be \"real quick\".  Other patches looked like they were\nreasonably well proofread before they were sent, but I somehow got\nan impression that this one (and possibly your v3---I saw its\npresence but haven't read it yet) was rushed.\n\nThanks.\n"},{"id":"476659","messageId":"xmqq5y96csso.fsf@gitster.g","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"Re: [PATCH v2 0/7] strbuf cleanups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-05T22:33:27Z","receivedAt":"2023-05-05T22:33:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> Strbuf is a widely used basic structure that should only interact with\n> other primitives in strbuf.[ch]. Over time certain functions inside of\n> strbuf.[ch] have been added to interact with higher level objects and\n> functions. This series cleans up some of those higher level interactions\n> by moving the offending functions to the files they interact with and\n> adding documentation to strbuf.h. With the goal of eventually being able\n> to stand up strbuf as a libary, this series also removes the use of\n> environment variables from strbuf.\n\nThis round hasn't seen any comments (mine does not count ;-).  The\n7/7-only v3 still says \"environment variable\" to refer to a global\nvariable, so I am not sure where we stand.  Is this back-burnered?\n\n"},{"id":"476685","messageId":"CABPp-BGc6ZK919rEH7-fOVg-nYs2wtvFP-XeQ7V9dEBEJvBYsQ@mail.gmail.com","threadId":"59685","inReplyTo":"CAFySSZAOqX0pESfJ-7bYg9iR2RDB9PL6sC4Kcvr_zitdQ1kD_g@mail.gmail.com","subject":"Re: [PATCH 0/6] strbuf cleanups","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-05-07T00:14:55Z","receivedAt":"2023-05-07T00:15:13Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, May 3, 2023 at 11:00 AM Calvin Wan <calvinwan@google.com> wrote:\n>\n> While moving strbuf_add_separated_string_list() to a separate file\n> would mean that strbuf would no longer have a dependency on\n> string-list, I don't think that dependency is problematic to begin\n> with. Widening the boundary for strbuf as a string manipulation\n> library to a string and string list manipulation library seems\n> reasonable to me.\n\nOh, the high level idea behind string-list might make sense at this\nlevel, but I was assuming Peff would show up at some point and\nhighlight the evils of the current string-list API[1][2][3] and how we\nshould avoid using, depending on, or implementing something that acts\nlike it.  :-)\n\nOf course, you're explicitly not trying to make any API or ABI\nguarantees, so it's certainly fine to shelve or defer such cleanups\nfor later.\n\n[1] https://lore.kernel.org/git/Y7lx1hUpZ7zOP1Lo@coredump.intra.peff.net/\n[2] https://lore.kernel.org/git/20180906191203.GA26184@sigill.intra.peff.net/\n[3] https://lore.kernel.org/git/20200821200121.GF1165@coredump.intra.peff.net/\n"},{"id":"476686","messageId":"CABPp-BGk-s+4b+OHi9FDXjwz5BeZPS8qb4XiJ8CVwkt8Siaq8A@mail.gmail.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"Re: [PATCH v2 0/7] strbuf cleanups","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-05-07T00:40:47Z","receivedAt":"2023-05-07T00:56:57Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Wed, May 3, 2023 at 11:48 AM Calvin Wan <calvinwan@google.com> wrote:\n>\n> Strbuf is a widely used basic structure that should only interact with\n> other primitives in strbuf.[ch].\n\n\"should\"?  I agree with moving things in this direction, but the\nwording here suggests there's a pre-existing directive or guideline;\nbut if so, I'm unfamiliar with it.  Maybe this should be reworded to\n\"This series modifies strbuf to focus on string manipulation with\nminimal other dependencies\"?\n\n> Over time certain functions inside of\n> strbuf.[ch] have been added to interact with higher level objects and\n> functions. This series cleans up some of those higher level interactions\n> by moving the offending functions to the files they interact with and\n> adding documentation to strbuf.h. With the goal of eventually being able\n> to stand up strbuf as a libary, this series also removes the use of\n> environment variables from strbuf.\n\nAs Junio pointed out, \"environment variables\" is misleading; see below.\n\n> Range-diff against v1:\n> -:  ---------- > 1:  e0dd3f5295 strbuf: clarify API boundary\n\nI read this separately; this patch looks good to me.\n\n> 1:  283771c088 ! 2:  ec1ea6ae4f abspath: move related functions to abspath\n>     @@ Commit message\n>          abspath: move related functions to abspath\n>\n>          Move abspath-related functions from strbuf.[ch] to abspath.[ch] since\n>     -    they do not belong in a low-level library.\n>     +    paths are not primitive objects and therefore strbuf should not interact\n>     +    with them.\n\nThis applies to patches 4 & 5 as well:\n\nWould this perhaps be better worded as:\n\n    Move abspath-related functions from strbuf.[ch] to abspath.[ch] so that\n    strbuf is focused on string manipulation routines with minimal dependencies.\n\n?\n\n>       ## abspath.c ##\n>      @@ abspath.c: char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n> 2:  58f78b8ae0 = 3:  2d74561b91 credential-store: move related functions to credential-store file\n> 3:  88ab90c079 ! 4:  30b5e635cb object-name: move related functions to object-name\n>     @@ Commit message\n>          object-name: move related functions to object-name\n>\n>          Move object-name-related functions from strbuf.[ch] to object-name.[ch]\n>     -    since they do not belong in a low-level library.\n>     +    since paths are not a primitive object that strbuf should directly\n>     +    interact with.\n>\n>       ## object-name.c ##\n>      @@ object-name.c: static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n> 4:  30b7de5a81 ! 5:  6905618470 path: move related function to path\n>     @@ Metadata\n>       ## Commit message ##\n>          path: move related function to path\n>\n>     -    Move path-related function from strbuf.[ch] to path.[ch] since it does\n>     -    not belong in a low-level library.\n>     +    Move path-related function from strbuf.[ch] to path.[ch] since path is\n>     +    not a primitive object and therefore strbuf should not directly interact\n>     +    with it.\n>\n>       ## path.c ##\n>      @@ path.c: int normalize_path_copy(char *dst, const char *src)\n> 5:  7b6d6353de ! 6:  caf3482bf7 strbuf: clarify dependency\n>     @@ Metadata\n>       ## Commit message ##\n>          strbuf: clarify dependency\n>\n>     +    refs.h was once needed but is no longer so as of 6bab74e7fb8 (\"strbuf:\n>     +    move strbuf_branchname to sha1_name.c\", 2010-11-06). strbuf.h was\n>     +    included thru refs.h, so removing refs.h requires strbuf.h to be added\n>     +    back.\n>     +\n\nThanks.\n\n> 6:  ffacd1cbe5 ! 7:  a7f23488f8 strbuf: remove enviroment variables\n>     @@ Metadata\n>      Author: Calvin Wan <calvinwan@google.com>\n>\n>       ## Commit message ##\n>     -    strbuf: remove enviroment variables\n>     +    strbuf: remove environment variables\n>\n>     -    As a lower level library, strbuf should not directly access environment\n>     -    variables within its functions. Therefore, add an additional variable to\n>     -    function signatures for functions that use an environment variable and\n>     -    refactor callers to pass in the environment variable.\n>     +    As a library that only interacts with other primitives, strbuf should\n>     +    not directly access environment variables within its\n>     +    functions. Therefore, add an additional variable to function signatures\n>     +    for functions that use an environment variable and refactor callers to\n>     +    pass in the environment variable.\n\n\"environment variable\" makes one think not of \"variable from\nenvironment.c [that happens to be a global]\" but of\nhttps://en.wikipedia.org/wiki/Environment_variable.  The fact that the\nvariable is defined in environment.c isn't even relevant here, though,\nwhile the fact that it is a global is relevant.  I'd just\ns/environment variable/global variable/ in all 4 places (er, 5 if you\ninclude the cover letter).\n\nYour v3 7/7 has an important correction, but you didn't send out a\nrange diff for v3 so I'm putting my comments on your v2 range-diff.\n:-)\n\n>     + /**\n>        * Strip whitespace from a buffer. The second parameter controls if\n>     -  * comments are considered contents to be removed or not.\n>     +- * comments are considered contents to be removed or not.\n>     ++ * comments are considered contents to be removed or not. The third parameter\n>     ++ * is the comment character that determines whether a line is a comment or not.\n>        */\n\nThanks.\n\n\nThis series fixes two of my comments on v1, and the other was just\n\"here's another cleanup that could be added\" -- it's fine to punt on.\n\nI only had a couple minor comments on this v2/v3 that should be easy\nto fix up, all included in this response to the cover letter.\n"},{"id":"476727","messageId":"20230507131427.GA1852750@coredump.intra.peff.net","threadId":"59685","inReplyTo":"CABPp-BGc6ZK919rEH7-fOVg-nYs2wtvFP-XeQ7V9dEBEJvBYsQ@mail.gmail.com","subject":"Re: [PATCH 0/6] strbuf cleanups","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2023-05-07T13:14:27Z","receivedAt":"2023-05-07T13:14:50Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, May 06, 2023 at 05:14:55PM -0700, Elijah Newren wrote:\n\n> On Wed, May 3, 2023 at 11:00 AM Calvin Wan <calvinwan@google.com> wrote:\n> >\n> > While moving strbuf_add_separated_string_list() to a separate file\n> > would mean that strbuf would no longer have a dependency on\n> > string-list, I don't think that dependency is problematic to begin\n> > with. Widening the boundary for strbuf as a string manipulation\n> > library to a string and string list manipulation library seems\n> > reasonable to me.\n> \n> Oh, the high level idea behind string-list might make sense at this\n> level, but I was assuming Peff would show up at some point and\n> highlight the evils of the current string-list API[1][2][3] and how we\n> should avoid using, depending on, or implementing something that acts\n> like it.  :-)\n\nYou rang? :)\n\nYes, IMHO this strbuf_add_separated_string_list() is another example of\nwhy string-list sucks: it doesn't degrade to a natural array type\n(because the \"util\" magic requires a struct). If it were a strvec or\nsimilar, we could just pass \"const char **str, size_t len\", which would\nmake the helper function simpler and more generally useful.\n\nI know there may be other reasons to use a string-list in the caller\nhere, though (looks like it uses \"nodup\"). So as usual, the situation is\nnot so simple as \"we should just switch types\".\n\n-Peff\n"},{"id":"476730","messageId":"64581c7d6d085_4e61294e0@chronos.notmuch","threadId":"59685","inReplyTo":"CABPp-BGk-s+4b+OHi9FDXjwz5BeZPS8qb4XiJ8CVwkt8Siaq8A@mail.gmail.com","subject":"Re: [PATCH v2 0/7] strbuf cleanups","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-05-07T21:47:41Z","receivedAt":"2023-05-07T21:47:48Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Elijah Newren wrote:\n> On Wed, May 3, 2023 at 11:48 AM Calvin Wan <calvinwan@google.com> wrote:\n> >\n> > Strbuf is a widely used basic structure that should only interact with\n> > other primitives in strbuf.[ch].\n> \n> \"should\"?  I agree with moving things in this direction, but the\n> wording here suggests there's a pre-existing directive or guideline;\n\nNo, it doesn't.\n\n\"You should see a doctor about that cough\" is not a directive, it's merely an\nadvice.\n\n> Maybe this should be reworded to \"This series modifies strbuf to focus on\n> string manipulation with minimal other dependencies\"?\n\nAnd ironoically you use the word \"should\" to provide your own advice on how to\navoid using \"should\" as an advice.\n\nI agree it would be ideal if strbuf interacted only with other primitives in\nstrbuf.[ch], so I agree \"should\" is a perfectly fine word to describe such a\nnormative statement.\n\n-- \nFelipe Contreras"},{"id":"476751","messageId":"CAFySSZBUdVT3KJ-RQ_98v2iLuTN=NMUo1xBq5ZEqHhwPjV47NA@mail.gmail.com","threadId":"59685","inReplyTo":"xmqq5y96csso.fsf@gitster.g","subject":"Re: [PATCH v2 0/7] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:38:22Z","receivedAt":"2023-05-08T16:39:51Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"I intend to reroll it, as well as rewording the commit patches 4 and 5\nas per Elijah's suggestions. I didn't originally realize you were\nreferring to s/environment variable/global variable as the misnomer\n(since the dependency I was removing was from environment.h)\n\nOn Fri, May 5, 2023 at 3:33 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> > Strbuf is a widely used basic structure that should only interact with\n> > other primitives in strbuf.[ch]. Over time certain functions inside of\n> > strbuf.[ch] have been added to interact with higher level objects and\n> > functions. This series cleans up some of those higher level interactions\n> > by moving the offending functions to the files they interact with and\n> > adding documentation to strbuf.h. With the goal of eventually being able\n> > to stand up strbuf as a libary, this series also removes the use of\n> > environment variables from strbuf.\n>\n> This round hasn't seen any comments (mine does not count ;-).  The\n> 7/7-only v3 still says \"environment variable\" to refer to a global\n> variable, so I am not sure where we stand.  Is this back-burnered?\n>\n"},{"id":"476754","messageId":"20230508165728.525603-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230503184849.1809304-1-calvinwan@google.com","subject":"[PATCH v4 0/7] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:57:28Z","receivedAt":"2023-05-08T16:57:41Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"This reroll include suggestions made by Elijah and Junio, clarifying\ncommit messages in patches 2/4/5 and s/environment variable/global\nvariable in patch 7. \n\nCalvin Wan (7):\n  strbuf: clarify API boundary\n  abspath: move related functions to abspath\n  credential-store: move related functions to credential-store file\n  object-name: move related functions to object-name\n  path: move related function to path\n  strbuf: clarify dependency\n  strbuf: remove global variable\n\n abspath.c                  |  36 +++++++++++++\n abspath.h                  |  21 ++++++++\n add-patch.c                |  12 +++--\n builtin/am.c               |   2 +-\n builtin/branch.c           |   4 +-\n builtin/commit.c           |   2 +-\n builtin/credential-store.c |  19 +++++++\n builtin/merge.c            |  10 ++--\n builtin/notes.c            |  16 +++---\n builtin/rebase.c           |   2 +-\n builtin/stripspace.c       |   6 ++-\n builtin/tag.c              |   9 ++--\n fmt-merge-msg.c            |   9 ++--\n gpg-interface.c            |   5 +-\n hook.c                     |   1 +\n object-name.c              |  15 ++++++\n object-name.h              |   9 ++++\n path.c                     |  20 +++++++\n path.h                     |   5 ++\n pretty.c                   |   1 +\n rebase-interactive.c       |  15 +++---\n sequencer.c                |  24 +++++----\n strbuf.c                   | 106 +++----------------------------------\n strbuf.h                   |  53 +++++--------------\n tempfile.c                 |   1 +\n wt-status.c                |   6 +--\n 26 files changed, 220 insertions(+), 189 deletions(-)\n\nRange-diff against v3:\n-:  ---------- > 1:  e0dd3f5295 strbuf: clarify API boundary\n1:  ec1ea6ae4f ! 2:  48fb5db28b abspath: move related functions to abspath\n    @@ Metadata\n      ## Commit message ##\n         abspath: move related functions to abspath\n     \n    -    Move abspath-related functions from strbuf.[ch] to abspath.[ch] since\n    -    paths are not primitive objects and therefore strbuf should not interact\n    -    with them.\n    +    Move abspath-related functions from strbuf.[ch] to abspath.[ch] so that\n    +    strbuf is focused on string manipulation routines with minimal\n    +    dependencies.\n     \n      ## abspath.c ##\n     @@ abspath.c: char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n2:  2d74561b91 = 3:  a663f91819 credential-store: move related functions to credential-store file\n3:  30b5e635cb ! 4:  ccef9dd5f2 object-name: move related functions to object-name\n    @@ Commit message\n         object-name: move related functions to object-name\n     \n         Move object-name-related functions from strbuf.[ch] to object-name.[ch]\n    -    since paths are not a primitive object that strbuf should directly\n    -    interact with.\n    +    so that strbuf is focused on string manipulation routines with minimal\n    +    dependencies.\n     \n      ## object-name.c ##\n     @@ object-name.c: static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n4:  6905618470 ! 5:  0d6b9cf0f7 path: move related function to path\n    @@ Metadata\n      ## Commit message ##\n         path: move related function to path\n     \n    -    Move path-related function from strbuf.[ch] to path.[ch] since path is\n    -    not a primitive object and therefore strbuf should not directly interact\n    -    with it.\n    +    Move path-related function from strbuf.[ch] to path.[ch] so that strbuf\n    +    is focused on string manipulation routines with minimal dependencies.\n     \n      ## path.c ##\n     @@ path.c: int normalize_path_copy(char *dst, const char *src)\n5:  caf3482bf7 = 6:  5655c56a6d strbuf: clarify dependency\n6:  3bbaebf292 ! 7:  874d0efac3 strbuf: remove environment variable\n    @@ Metadata\n     Author: Calvin Wan <calvinwan@google.com>\n     \n      ## Commit message ##\n    -    strbuf: remove environment variable\n    +    strbuf: remove global variable\n     \n         As a library that only interacts with other primitives, strbuf should\n    -    not utilize the comment_line_char environment variable within its\n    +    not utilize the comment_line_char global variable within its\n         functions. Therefore, add an additional parameter for functions that use\n         comment_line_char and refactor callers to pass it in instead.\n     \n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476756","messageId":"20230508165908.526247-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"[PATCH v4 1/7] strbuf: clarify API boundary","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:59:02Z","receivedAt":"2023-05-08T16:59:48Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"strbuf, as a generic and widely used structure across the codebase,\nshould be limited as a libary to only interact with primitives. Add\ndocumentation so future functions can be appropriately be placed. Older\nfunctions that do not follow this boundary should eventually be moved or\nrefactored.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.h | 6 +++++-\n 1 file changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/strbuf.h b/strbuf.h\nindex 3dfeadb44c..c856253216 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -5,7 +5,11 @@ struct string_list;\n \n /**\n  * strbuf's are meant to be used with all the usual C string and memory\n- * APIs. Given that the length of the buffer is known, it's often better to\n+ * APIs. The objects that this API interacts with in this file should be \n+ * limited to other primitives, however, there are older functions in here \n+ * that should eventually be moved out or refactored. \n+ * \n+ * Given that the length of the buffer is known, it's often better to\n  * use the mem* functions than a str* one (memchr vs. strchr e.g.).\n  * Though, one has to be careful about the fact that str* functions often\n  * stop on NULs and that strbufs may have embedded NULs.\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476757","messageId":"20230508165908.526247-3-calvinwan@google.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"[PATCH v4 3/7] credential-store: move related functions to credential-store file","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:59:04Z","receivedAt":"2023-05-08T16:59:54Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"is_rfc3986_unreserved() and is_rfc3986_reserved_or_unreserved() are only\ncalled from builtin/credential-store.c and they are only relevant to that\nfile so move those functions and make them static.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n builtin/credential-store.c | 19 +++++++++++++++++++\n strbuf.c                   | 19 -------------------\n strbuf.h                   |  3 ---\n 3 files changed, 19 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/credential-store.c b/builtin/credential-store.c\nindex 8977604eb9..4776118331 100644\n--- a/builtin/credential-store.c\n+++ b/builtin/credential-store.c\n@@ -73,6 +73,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,\n \t\tdie_errno(\"unable to write credential store\");\n }\n \n+static int is_rfc3986_unreserved(char ch)\n+{\n+\treturn isalnum(ch) ||\n+\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n+}\n+\n+static int is_rfc3986_reserved_or_unreserved(char ch)\n+{\n+\tif (is_rfc3986_unreserved(ch))\n+\t\treturn 1;\n+\tswitch (ch) {\n+\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n+\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n+\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static void store_credential_file(const char *fn, struct credential *c)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/strbuf.c b/strbuf.c\nindex c3b6d48797..da2693b21f 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -809,25 +809,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)\n \t}\n }\n \n-int is_rfc3986_reserved_or_unreserved(char ch)\n-{\n-\tif (is_rfc3986_unreserved(ch))\n-\t\treturn 1;\n-\tswitch (ch) {\n-\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n-\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n-\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-int is_rfc3986_unreserved(char ch)\n-{\n-\treturn isalnum(ch) ||\n-\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n-}\n-\n static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,\n \t\t\t\t char_predicate allow_unencoded_fn)\n {\ndiff --git a/strbuf.h b/strbuf.h\nindex 20d0e37d9c..9e52fe7706 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -686,9 +686,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);\n \n typedef int (*char_predicate)(char ch);\n \n-int is_rfc3986_unreserved(char ch);\n-int is_rfc3986_reserved_or_unreserved(char ch);\n-\n void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,\n \t\t\t     char_predicate allow_unencoded_fn);\n \n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476758","messageId":"20230508165908.526247-5-calvinwan@google.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"[PATCH v4 5/7] path: move related function to path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:59:06Z","receivedAt":"2023-05-08T16:59:55Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move path-related function from strbuf.[ch] to path.[ch] so that strbuf\nis focused on string manipulation routines with minimal dependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n path.c   | 20 ++++++++++++++++++++\n path.h   |  5 +++++\n strbuf.c | 20 --------------------\n 3 files changed, 25 insertions(+), 20 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 7c1cd8182a..e17a2613c5 100644\n--- a/path.c\n+++ b/path.c\n@@ -1213,6 +1213,26 @@ int normalize_path_copy(char *dst, const char *src)\n \treturn normalize_path_copy_len(dst, src, NULL);\n }\n \n+int strbuf_normalize_path(struct strbuf *src)\n+{\n+\tstruct strbuf dst = STRBUF_INIT;\n+\n+\tstrbuf_grow(&dst, src->len);\n+\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n+\t\tstrbuf_release(&dst);\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * normalize_path does not tell us the new length, so we have to\n+\t * compute it by looking for the new NUL it placed\n+\t */\n+\tstrbuf_setlen(&dst, strlen(dst.buf));\n+\tstrbuf_swap(src, &dst);\n+\tstrbuf_release(&dst);\n+\treturn 0;\n+}\n+\n /*\n  * path = Canonical absolute path\n  * prefixes = string_list containing normalized, absolute paths without\ndiff --git a/path.h b/path.h\nindex 60e83a49a9..639372edd9 100644\n--- a/path.h\n+++ b/path.h\n@@ -191,6 +191,11 @@ const char *remove_leading_path(const char *in, const char *prefix);\n const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);\n int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);\n int normalize_path_copy(char *dst, const char *src);\n+/**\n+ * Normalize in-place the path contained in the strbuf. If an error occurs,\n+ * the contents of \"sb\" are left untouched, and -1 is returned.\n+ */\n+int strbuf_normalize_path(struct strbuf *src);\n int longest_ancestor_length(const char *path, struct string_list *prefixes);\n char *strip_path_suffix(const char *path, const char *suffix);\n int daemon_avoid_alias(const char *path);\ndiff --git a/strbuf.c b/strbuf.c\nindex 6533559e95..178d75f250 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1088,26 +1088,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \tstrbuf_setlen(sb, j);\n }\n \n-int strbuf_normalize_path(struct strbuf *src)\n-{\n-\tstruct strbuf dst = STRBUF_INIT;\n-\n-\tstrbuf_grow(&dst, src->len);\n-\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n-\t\tstrbuf_release(&dst);\n-\t\treturn -1;\n-\t}\n-\n-\t/*\n-\t * normalize_path does not tell us the new length, so we have to\n-\t * compute it by looking for the new NUL it placed\n-\t */\n-\tstrbuf_setlen(&dst, strlen(dst.buf));\n-\tstrbuf_swap(src, &dst);\n-\tstrbuf_release(&dst);\n-\treturn 0;\n-}\n-\n void strbuf_strip_file_from_path(struct strbuf *sb)\n {\n \tchar *path_sep = find_last_dir_sep(sb->buf);\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476759","messageId":"20230508165908.526247-2-calvinwan@google.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"[PATCH v4 2/7] abspath: move related functions to abspath","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:59:03Z","receivedAt":"2023-05-08T16:59:56Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move abspath-related functions from strbuf.[ch] to abspath.[ch] so that\nstrbuf is focused on string manipulation routines with minimal\ndependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n abspath.c  | 36 ++++++++++++++++++++++++++++++++++++\n abspath.h  | 21 +++++++++++++++++++++\n hook.c     |  1 +\n strbuf.c   | 37 -------------------------------------\n strbuf.h   | 22 ----------------------\n tempfile.c |  1 +\n 6 files changed, 59 insertions(+), 59 deletions(-)\n\ndiff --git a/abspath.c b/abspath.c\nindex d032f5dce5..1202cde23d 100644\n--- a/abspath.c\n+++ b/abspath.c\n@@ -289,3 +289,39 @@ char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n \t\treturn xstrdup(arg);\n \treturn prefix_filename(pfx, arg);\n }\n+\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n+{\n+\tif (!*path)\n+\t\tdie(\"The empty string is not a valid path\");\n+\tif (!is_absolute_path(path)) {\n+\t\tstruct stat cwd_stat, pwd_stat;\n+\t\tsize_t orig_len = sb->len;\n+\t\tchar *cwd = xgetcwd();\n+\t\tchar *pwd = getenv(\"PWD\");\n+\t\tif (pwd && strcmp(pwd, cwd) &&\n+\t\t    !stat(cwd, &cwd_stat) &&\n+\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n+\t\t    !stat(pwd, &pwd_stat) &&\n+\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n+\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n+\t\t\tstrbuf_addstr(sb, pwd);\n+\t\telse\n+\t\t\tstrbuf_addstr(sb, cwd);\n+\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n+\t\t\tstrbuf_addch(sb, '/');\n+\t\tfree(cwd);\n+\t}\n+\tstrbuf_addstr(sb, path);\n+}\n+\n+void strbuf_add_real_path(struct strbuf *sb, const char *path)\n+{\n+\tif (sb->len) {\n+\t\tstruct strbuf resolved = STRBUF_INIT;\n+\t\tstrbuf_realpath(&resolved, path, 1);\n+\t\tstrbuf_addbuf(sb, &resolved);\n+\t\tstrbuf_release(&resolved);\n+\t} else\n+\t\tstrbuf_realpath(sb, path, 1);\n+}\ndiff --git a/abspath.h b/abspath.h\nindex 7cd3de5e9d..4653080d5e 100644\n--- a/abspath.h\n+++ b/abspath.h\n@@ -30,4 +30,25 @@ static inline int is_absolute_path(const char *path)\n \treturn is_dir_sep(path[0]) || has_dos_drive_prefix(path);\n }\n \n+/**\n+ * Add a path to a buffer, converting a relative path to an\n+ * absolute one in the process.  Symbolic links are not\n+ * resolved.\n+ */\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n+\n+/**\n+ * Canonize `path` (make it absolute, resolve symlinks, remove extra\n+ * slashes) and append it to `sb`.  Die with an informative error\n+ * message if there is a problem.\n+ *\n+ * The directory part of `path` (i.e., everything up to the last\n+ * dir_sep) must denote a valid, existing directory, but the last\n+ * component need not exist.\n+ *\n+ * Callers that don't mind links should use the more lightweight\n+ * strbuf_add_absolute_path() instead.\n+ */\n+void strbuf_add_real_path(struct strbuf *sb, const char *path);\n+\n #endif /* ABSPATH_H */\ndiff --git a/hook.c b/hook.c\nindex 76e322f580..2d8706371e 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -1,4 +1,5 @@\n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hook.h\"\ndiff --git a/strbuf.c b/strbuf.c\nindex 729378ec82..c3b6d48797 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,5 +1,4 @@\n #include \"git-compat-util.h\"\n-#include \"abspath.h\"\n #include \"alloc.h\"\n #include \"environment.h\"\n #include \"gettext.h\"\n@@ -899,42 +898,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)\n \tstrbuf_humanise(buf, bytes, 1);\n }\n \n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n-{\n-\tif (!*path)\n-\t\tdie(\"The empty string is not a valid path\");\n-\tif (!is_absolute_path(path)) {\n-\t\tstruct stat cwd_stat, pwd_stat;\n-\t\tsize_t orig_len = sb->len;\n-\t\tchar *cwd = xgetcwd();\n-\t\tchar *pwd = getenv(\"PWD\");\n-\t\tif (pwd && strcmp(pwd, cwd) &&\n-\t\t    !stat(cwd, &cwd_stat) &&\n-\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n-\t\t    !stat(pwd, &pwd_stat) &&\n-\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n-\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n-\t\t\tstrbuf_addstr(sb, pwd);\n-\t\telse\n-\t\t\tstrbuf_addstr(sb, cwd);\n-\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n-\t\t\tstrbuf_addch(sb, '/');\n-\t\tfree(cwd);\n-\t}\n-\tstrbuf_addstr(sb, path);\n-}\n-\n-void strbuf_add_real_path(struct strbuf *sb, const char *path)\n-{\n-\tif (sb->len) {\n-\t\tstruct strbuf resolved = STRBUF_INIT;\n-\t\tstrbuf_realpath(&resolved, path, 1);\n-\t\tstrbuf_addbuf(sb, &resolved);\n-\t\tstrbuf_release(&resolved);\n-\t} else\n-\t\tstrbuf_realpath(sb, path, 1);\n-}\n-\n int printf_ln(const char *fmt, ...)\n {\n \tint ret;\ndiff --git a/strbuf.h b/strbuf.h\nindex c856253216..20d0e37d9c 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -531,28 +531,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);\n  */\n int strbuf_getcwd(struct strbuf *sb);\n \n-/**\n- * Add a path to a buffer, converting a relative path to an\n- * absolute one in the process.  Symbolic links are not\n- * resolved.\n- */\n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n-\n-/**\n- * Canonize `path` (make it absolute, resolve symlinks, remove extra\n- * slashes) and append it to `sb`.  Die with an informative error\n- * message if there is a problem.\n- *\n- * The directory part of `path` (i.e., everything up to the last\n- * dir_sep) must denote a valid, existing directory, but the last\n- * component need not exist.\n- *\n- * Callers that don't mind links should use the more lightweight\n- * strbuf_add_absolute_path() instead.\n- */\n-void strbuf_add_real_path(struct strbuf *sb, const char *path);\n-\n-\n /**\n  * Normalize in-place the path contained in the strbuf. See\n  * normalize_path_copy() for details. If an error occurs, the contents of \"sb\"\ndiff --git a/tempfile.c b/tempfile.c\nindex 50c377134c..6c88a63b42 100644\n--- a/tempfile.c\n+++ b/tempfile.c\n@@ -43,6 +43,7 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"path.h\"\n #include \"tempfile.h\"\n #include \"sigchain.h\"\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476760","messageId":"20230508165908.526247-4-calvinwan@google.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"[PATCH v4 4/7] object-name: move related functions to object-name","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:59:05Z","receivedAt":"2023-05-08T16:59:59Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move object-name-related functions from strbuf.[ch] to object-name.[ch]\nso that strbuf is focused on string manipulation routines with minimal\ndependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n object-name.c | 15 +++++++++++++++\n object-name.h |  9 +++++++++\n pretty.c      |  1 +\n strbuf.c      | 16 ----------------\n strbuf.h      | 10 ----------\n 5 files changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 538e8a8f62..c2e82aceea 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -766,6 +766,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n \t\tfind_abbrev_len_for_pack(p, mad);\n }\n \n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len)\n+{\n+\tint r;\n+\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n+\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n+\tstrbuf_setlen(sb, sb->len + r);\n+}\n+\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len)\n+{\n+\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n+}\n+\n int repo_find_unique_abbrev_r(struct repository *r, char *hex,\n \t\t\t      const struct object_id *oid, int len)\n {\ndiff --git a/object-name.h b/object-name.h\nindex 1d63698f42..9ae5223071 100644\n--- a/object-name.h\n+++ b/object-name.h\n@@ -40,6 +40,15 @@ struct object_context {\n const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);\n int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);\n \n+/**\n+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n+ * the strbuf `sb`.\n+ */\n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len);\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len);\n+\n int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);\n __attribute__((format (printf, 2, 3)))\n int get_oidf(struct object_id *oid, const char *fmt, ...);\ndiff --git a/pretty.c b/pretty.c\nindex 0bb938021b..78bac2d818 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -18,6 +18,7 @@\n #include \"gpg-interface.h\"\n #include \"trailer.h\"\n #include \"run-command.h\"\n+#include \"object-name.h\"\n \n /*\n  * The limit for formatting directives, which enable the caller to append\ndiff --git a/strbuf.c b/strbuf.c\nindex da2693b21f..6533559e95 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,6 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"object-name.h\"\n #include \"refs.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n@@ -1023,21 +1022,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,\n \tstrbuf_setlen(sb, sb->len + len);\n }\n \n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len)\n-{\n-\tint r;\n-\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n-\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n-\tstrbuf_setlen(sb, sb->len + r);\n-}\n-\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len)\n-{\n-\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n-}\n-\n /*\n  * Returns the length of a line, without trailing spaces.\n  *\ndiff --git a/strbuf.h b/strbuf.h\nindex 9e52fe7706..1bae7e0f47 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -612,16 +612,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,\n  */\n void strbuf_list_free(struct strbuf **list);\n \n-/**\n- * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n- * the strbuf `sb`.\n- */\n-struct repository;\n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len);\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len);\n-\n /*\n  * Remove the filename from the provided path string. If the path\n  * contains a trailing separator, then the path is considered a directory\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476761","messageId":"20230508165908.526247-6-calvinwan@google.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"[PATCH v4 6/7] strbuf: clarify dependency","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:59:07Z","receivedAt":"2023-05-08T17:00:02Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"refs.h was once needed but is no longer so as of 6bab74e7fb8 (\"strbuf:\nmove strbuf_branchname to sha1_name.c\", 2010-11-06). strbuf.h was\nincluded thru refs.h, so removing refs.h requires strbuf.h to be added\nback.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex 178d75f250..d5978fee4e 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,7 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"refs.h\"\n+#include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n #include \"date.h\"\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476762","messageId":"20230508165908.526247-7-calvinwan@google.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"[PATCH v4 7/7] strbuf: remove global variable","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-08T16:59:08Z","receivedAt":"2023-05-08T17:00:04Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"As a library that only interacts with other primitives, strbuf should\nnot utilize the comment_line_char global variable within its\nfunctions. Therefore, add an additional parameter for functions that use\ncomment_line_char and refactor callers to pass it in instead.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n add-patch.c          | 12 +++++++-----\n builtin/am.c         |  2 +-\n builtin/branch.c     |  4 ++--\n builtin/commit.c     |  2 +-\n builtin/merge.c      | 10 ++++++----\n builtin/notes.c      | 16 +++++++++-------\n builtin/rebase.c     |  2 +-\n builtin/stripspace.c |  6 ++++--\n builtin/tag.c        |  9 ++++++---\n fmt-merge-msg.c      |  9 ++++++---\n gpg-interface.c      |  5 +++--\n rebase-interactive.c | 15 ++++++++-------\n sequencer.c          | 24 +++++++++++++++---------\n strbuf.c             | 12 +++++++-----\n strbuf.h             | 12 +++++++-----\n wt-status.c          |  6 +++---\n 16 files changed, 86 insertions(+), 60 deletions(-)\n\ndiff --git a/add-patch.c b/add-patch.c\nindex 8d770d203f..9702c1aabd 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \tsize_t i;\n \n \tstrbuf_reset(&s->buf);\n-\tstrbuf_commented_addf(&s->buf, _(\"Manual hunk edit mode -- see bottom for \"\n-\t\t\t\t      \"a quick guide.\\n\"));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n+\t\t\t      _(\"Manual hunk edit mode -- see bottom for \"\n+\t\t\t\t\"a quick guide.\\n\"));\n \trender_hunk(s, hunk, 0, 0, &s->buf);\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"---\\n\"\n \t\t\t\t\"To remove '%c' lines, make them ' ' lines \"\n \t\t\t\t\"(context).\\n\"\n@@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \t\t\t      s->mode->is_reverse ? '+' : '-',\n \t\t\t      s->mode->is_reverse ? '-' : '+',\n \t\t\t      comment_line_char);\n-\tstrbuf_commented_addf(&s->buf, \"%s\", _(s->mode->edit_hunk_hint));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char, \"%s\",\n+\t\t\t      _(s->mode->edit_hunk_hint));\n \t/*\n \t * TRANSLATORS: 'it' refers to the patch mentioned in the previous\n \t * messages.\n \t */\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"If it does not apply cleanly, you will be \"\n \t\t\t\t\"given an opportunity to\\n\"\n \t\t\t\t\"edit again.  If all lines of the hunk are \"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5c83f2e003..306489db13 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n \tstrbuf_addbuf(&msg, &mi.log_message);\n-\tstrbuf_stripspace(&msg, 0);\n+\tstrbuf_stripspace(&msg, 0, comment_line_char);\n \n \tassert(!state->author_name);\n \tstate->author_name = strbuf_detach(&author_name, NULL);\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 501c47657c..e52afcf4d7 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -629,7 +629,7 @@ static int edit_branch_description(const char *branch_name)\n \texists = !read_branch_desc(&buf, branch_name);\n \tif (!buf.len || buf.buf[buf.len-1] != '\\n')\n \t\tstrbuf_addch(&buf, '\\n');\n-\tstrbuf_commented_addf(&buf,\n+\tstrbuf_commented_addf(&buf, comment_line_char,\n \t\t    _(\"Please edit the description for the branch\\n\"\n \t\t      \"  %s\\n\"\n \t\t      \"Lines starting with '%c' will be stripped.\\n\"),\n@@ -640,7 +640,7 @@ static int edit_branch_description(const char *branch_name)\n \t\tstrbuf_release(&buf);\n \t\treturn -1;\n \t}\n-\tstrbuf_stripspace(&buf, 1);\n+\tstrbuf_stripspace(&buf, 1, comment_line_char);\n \n \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n \tif (buf.len || exists)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex e67c4be221..6d3cc4d9fe 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \ts->hints = 0;\n \n \tif (clean_message_contents)\n-\t\tstrbuf_stripspace(&sb, 0);\n+\t\tstrbuf_stripspace(&sb, 0, comment_line_char);\n \n \tif (signoff)\n \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8da3e46abb..1d14767c0c 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)\n \t\tstrbuf_addch(&msg, '\\n');\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {\n \t\t\twt_status_append_cut_line(&msg);\n-\t\t\tstrbuf_commented_addf(&msg, \"\\n\");\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char, \"\\n\");\n \t\t}\n-\t\tstrbuf_commented_addf(&msg, _(merge_editor_comment));\n+\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t      _(merge_editor_comment));\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n-\t\t\tstrbuf_commented_addf(&msg, _(scissors_editor_comment));\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t\t      _(scissors_editor_comment));\n \t\telse\n-\t\t\tstrbuf_commented_addf(&msg,\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n \t\t\t\t_(no_scissors_editor_comment), comment_line_char);\n \t}\n \tif (signoff)\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex d5788352b6..0918b92752 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -11,6 +11,7 @@\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"editor.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"notes.h\"\n@@ -157,7 +158,7 @@ static void write_commented_object(int fd, const struct object_id *object)\n \n \tif (strbuf_read(&buf, show.out, 0) < 0)\n \t\tdie_errno(_(\"could not read 'show' output\"));\n-\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);\n \twrite_or_die(fd, cbuf.buf, cbuf.len);\n \n \tstrbuf_release(&cbuf);\n@@ -185,9 +186,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\t\tcopy_obj_to_fd(fd, old_note);\n \n \t\tstrbuf_addch(&buf, '\\n');\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n-\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),\n+\t\t\t\t\t   comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n \t\twrite_or_die(fd, buf.buf, buf.len);\n \n \t\twrite_commented_object(fd, object);\n@@ -199,7 +201,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\tif (launch_editor(d->edit_path, &d->buf, NULL)) {\n \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n \t\t}\n-\t\tstrbuf_stripspace(&d->buf, 1);\n+\t\tstrbuf_stripspace(&d->buf, 1, comment_line_char);\n \t}\n }\n \n@@ -225,7 +227,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \tstrbuf_addstr(&d->buf, arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n \n \td->given = 1;\n \treturn 0;\n@@ -244,7 +246,7 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n \t\t\tdie_errno(_(\"cannot read '%s'\"), arg);\n \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n \n \td->given = 1;\n \treturn 0;\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex ace1d5e8d1..d092e06dc7 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)\n \tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n \n-\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tstrbuf_stripspace(&todo_list.buf, 1, comment_line_char);\n \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 9451eb69ff..e182c2a14e 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"parse-options.h\"\n #include \"setup.h\"\n@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)\n \tsize_t len;\n \n \tmsg = strbuf_detach(buf, &len);\n-\tstrbuf_add_commented_lines(buf, msg, len);\n+\tstrbuf_add_commented_lines(buf, msg, len, comment_line_char);\n \tfree(msg);\n }\n \n@@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)\n \t\tdie_errno(\"could not read the input\");\n \n \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n-\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n+\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS,\n+\t\t\t\t  comment_line_char);\n \telse\n \t\tcomment_lines(&buf);\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1850a6a6fd..e7e2511f0c 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n \t\t\tstrbuf_addch(&buf, '\\n');\n \t\t\tif (opt->cleanup_mode == CLEANUP_ALL)\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template), tag, comment_line_char);\n \t\t\telse\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template_nocleanup), tag, comment_line_char);\n \t\t\twrite_or_die(fd, buf.buf, buf.len);\n \t\t\tstrbuf_release(&buf);\n \t\t}\n@@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t}\n \n \tif (opt->cleanup_mode != CLEANUP_NONE)\n-\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n+\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n \n \tif (!opt->message_given && !buf->len)\n \t\tdie(_(\"no tag message?\"));\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 5af0d4715b..5d15e2387d 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,\n \tstrbuf_complete_line(tagbuf);\n \tif (sig->len) {\n \t\tstrbuf_addch(tagbuf, '\\n');\n-\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len);\n+\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len,\n+\t\t\t\t\t   comment_line_char);\n \t}\n }\n \n@@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\t\tstrbuf_addch(&tagline, '\\n');\n \t\t\t\tstrbuf_add_commented_lines(&tagline,\n \t\t\t\t\t\torigins.items[first_tag].string,\n-\t\t\t\t\t\tstrlen(origins.items[first_tag].string));\n+\t\t\t\t\t\tstrlen(origins.items[first_tag].string),\n+\t\t\t\t\t\tcomment_line_char);\n \t\t\t\tstrbuf_insert(&tagbuf, 0, tagline.buf,\n \t\t\t\t\t      tagline.len);\n \t\t\t\tstrbuf_release(&tagline);\n@@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\tstrbuf_addch(&tagbuf, '\\n');\n \t\t\tstrbuf_add_commented_lines(&tagbuf,\n \t\t\t\t\torigins.items[i].string,\n-\t\t\t\t\tstrlen(origins.items[i].string));\n+\t\t\t\t\tstrlen(origins.items[i].string),\n+\t\t\t\t\tcomment_line_char);\n \t\t\tfmt_tag_signature(&tagbuf, &sig, buf, len);\n \t\t}\n \t\tstrbuf_release(&payload);\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex f3ac5acdd9..b625f17460 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -11,6 +11,7 @@\n #include \"tempfile.h\"\n #include \"alias.h\"\n #include \"wrapper.h\"\n+#include \"environment.h\"\n \n static int git_gpg_config(const char *, const char *, void *);\n \n@@ -584,8 +585,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,\n \t\t}\n \t}\n \n-\tstrbuf_stripspace(&ssh_keygen_out, 0);\n-\tstrbuf_stripspace(&ssh_keygen_err, 0);\n+\tstrbuf_stripspace(&ssh_keygen_out, 0, comment_line_char);\n+\tstrbuf_stripspace(&ssh_keygen_err, 0, comment_line_char);\n \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 789f407361..c6027e73c1 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -71,13 +71,14 @@ void append_todo_help(int command_count,\n \n \tif (!edit_todo) {\n \t\tstrbuf_addch(buf, '\\n');\n-\t\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n-\t\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n-\t\t\t\t\t      command_count),\n+\t\tstrbuf_commented_addf(buf, comment_line_char,\n+\t\t\t\t      Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t\t \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t\t command_count),\n \t\t\t\t      shortrevisions, shortonto, command_count);\n \t}\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -86,7 +87,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -97,7 +98,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n }\n \n int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n@@ -129,7 +130,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n \tif (launch_sequence_editor(todo_file, &new_todo->buf, NULL))\n \t\treturn -2;\n \n-\tstrbuf_stripspace(&new_todo->buf, 1);\n+\tstrbuf_stripspace(&new_todo->buf, 1, comment_line_char);\n \tif (initial && new_todo->buf.len == 0)\n \t\treturn -3;\n \ndiff --git a/sequencer.c b/sequencer.c\nindex c88d1d9553..9675b62bcb 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -659,11 +659,12 @@ void append_conflicts_hint(struct index_state *istate,\n \t}\n \n \tstrbuf_addch(msgbuf, '\\n');\n-\tstrbuf_commented_addf(msgbuf, \"Conflicts:\\n\");\n+\tstrbuf_commented_addf(msgbuf, comment_line_char, \"Conflicts:\\n\");\n \tfor (i = 0; i < istate->cache_nr;) {\n \t\tconst struct cache_entry *ce = istate->cache[i++];\n \t\tif (ce_stage(ce)) {\n-\t\t\tstrbuf_commented_addf(msgbuf, \"\\t%s\\n\", ce->name);\n+\t\t\tstrbuf_commented_addf(msgbuf, comment_line_char,\n+\t\t\t\t\t      \"\\t%s\\n\", ce->name);\n \t\t\twhile (i < istate->cache_nr &&\n \t\t\t       !strcmp(ce->name, istate->cache[i]->name))\n \t\t\t\ti++;\n@@ -1142,7 +1143,8 @@ void cleanup_message(struct strbuf *msgbuf,\n \t    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n }\n \n /*\n@@ -1173,7 +1175,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,\n \tif (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)\n \t\treturn 0;\n \n-\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t  comment_line_char);\n \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n \t\tstart = sb->buf;\n \tstrbuf_release(&tmpl);\n@@ -1545,7 +1548,8 @@ static int try_to_commit(struct repository *r,\n \t\tcleanup = opts->default_msg_cleanup;\n \n \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL,\n+\t\t\t\t  comment_line_char);\n \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n \t\tres = 1; /* run 'git commit' to display error message */\n \t\tgoto out;\n@@ -1839,7 +1843,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n \t\ts += count;\n \t\tlen -= count;\n \t}\n-\tstrbuf_add_commented_lines(buf, s, len);\n+\tstrbuf_add_commented_lines(buf, s, len, comment_line_char);\n }\n \n /* Does the current fixup chain contain a squash command? */\n@@ -1938,7 +1942,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_add_commented_lines(buf, body, commented_len, comment_line_char);\n \t/* buf->buf may be reallocated so store an offset into the buffer */\n \tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n@@ -2028,7 +2032,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tif (is_fixup_flag(command, flag))\n-\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t\t   comment_line_char);\n \t\telse\n \t\t\tstrbuf_addstr(&buf, body);\n \n@@ -2047,7 +2052,8 @@ static int update_squash_messages(struct repository *r,\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t   comment_line_char);\n \t} else\n \t\treturn error(_(\"unknown command: %d\"), command);\n \trepo_unuse_commit_buffer(r, commit, message);\ndiff --git a/strbuf.c b/strbuf.c\nindex d5978fee4e..eba65ca421 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,6 +1,5 @@\n #include \"git-compat-util.h\"\n #include \"alloc.h\"\n-#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"strbuf.h\"\n@@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n \tstrbuf_complete_line(out);\n }\n \n-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n+\t\t\t\tsize_t size, char comment_line_char)\n {\n \tstatic char prefix1[3];\n \tstatic char prefix2[2];\n@@ -374,7 +374,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size\n \tadd_lines(out, prefix1, prefix2, buf, size);\n }\n \n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,\n+\t\t\t   const char *fmt, ...)\n {\n \tva_list params;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -384,7 +385,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n \tstrbuf_vaddf(&buf, fmt, params);\n \tva_end(params);\n \n-\tstrbuf_add_commented_lines(sb, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);\n \tif (incomplete_line)\n \t\tsb->buf[--sb->len] = '\\0';\n \n@@ -1054,7 +1055,8 @@ static size_t cleanup(char *line, size_t len)\n  * Enable skip_comments to skip every line starting with comment\n  * character.\n  */\n-void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n+void strbuf_stripspace(struct strbuf *sb, int skip_comments,\n+\t\t       char comment_line_char)\n {\n \tsize_t empties = 0;\n \tsize_t i, j, len, newlen;\ndiff --git a/strbuf.h b/strbuf.h\nindex 1bae7e0f47..bc16fa4ef9 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -287,7 +287,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n  * by a comment character and a blank.\n  */\n void strbuf_add_commented_lines(struct strbuf *out,\n-\t\t\t\tconst char *buf, size_t size);\n+\t\t\t\tconst char *buf, size_t size,\n+\t\t\t\tchar comment_line_char);\n \n \n /**\n@@ -416,8 +417,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n  * Add a formatted string prepended by a comment character and a\n  * blank to the buffer.\n  */\n-__attribute__((format (printf, 2, 3)))\n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n+__attribute__((format (printf, 3, 4)))\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n \n __attribute__((format (printf,2,0)))\n void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n@@ -540,9 +541,10 @@ int strbuf_normalize_path(struct strbuf *sb);\n \n /**\n  * Strip whitespace from a buffer. The second parameter controls if\n- * comments are considered contents to be removed or not.\n+ * comments are considered contents to be removed or not. The third parameter\n+ * is the comment character that determines whether a line is a comment or not.\n  */\n-void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n+void strbuf_stripspace(struct strbuf *buf, int skip_comments, char comment_line_char);\n \n static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n {\ndiff --git a/wt-status.c b/wt-status.c\nindex 97b9c1c035..da7734866f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1023,7 +1023,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom\n \tif (s->display_comment_prefix) {\n \t\tsize_t len;\n \t\tsummary_content = strbuf_detach(&summary, &len);\n-\t\tstrbuf_add_commented_lines(&summary, summary_content, len);\n+\t\tstrbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);\n \t\tfree(summary_content);\n \t}\n \n@@ -1098,8 +1098,8 @@ void wt_status_append_cut_line(struct strbuf *buf)\n {\n \tconst char *explanation = _(\"Do not modify or remove the line above.\\nEverything below it will be ignored.\");\n \n-\tstrbuf_commented_addf(buf, \"%s\", cut_line);\n-\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation));\n+\tstrbuf_commented_addf(buf, comment_line_char, \"%s\", cut_line);\n+\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);\n }\n \n void wt_status_add_cut_line(FILE *fp)\n-- \n2.40.1.521.gf1e218fcd8-goog\n\n"},{"id":"476765","messageId":"CAPig+cTQg7XzORPHeD79aHEi1ggOjTPw9X02VPgxcV9uoBOBxg@mail.gmail.com","threadId":"59685","inReplyTo":"20230508165908.526247-1-calvinwan@google.com","subject":"Re: [PATCH v4 1/7] strbuf: clarify API boundary","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2023-05-08T17:22:15Z","receivedAt":"2023-05-08T17:22:34Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, May 8, 2023 at 1:05 PM Calvin Wan <calvinwan@google.com> wrote:\n> strbuf, as a generic and widely used structure across the codebase,\n> should be limited as a libary to only interact with primitives. Add\n\ns/libary/library/\n\n> documentation so future functions can be appropriately be placed. Older\n\nToo many \"be\"'s.\n\n> functions that do not follow this boundary should eventually be moved or\n> refactored.\n>\n> Signed-off-by: Calvin Wan <calvinwan@google.com>\n> ---\n> diff --git a/strbuf.h b/strbuf.h\n> @@ -5,7 +5,11 @@ struct string_list;\n>  /**\n>   * strbuf's are meant to be used with all the usual C string and memory\n> - * APIs. Given that the length of the buffer is known, it's often better to\n> + * APIs. The objects that this API interacts with in this file should be\n> + * limited to other primitives, however, there are older functions in here\n> + * that should eventually be moved out or refactored.\n> + *\n> + * Given that the length of the buffer is known, it's often better to\n>   * use the mem* functions than a str* one (memchr vs. strchr e.g.).\n>   * Though, one has to be careful about the fact that str* functions often\n>   * stop on NULs and that strbufs may have embedded NULs.\n\nThe new text is administrative in nature, aimed at people who will be\nmodifying strbuf itself. As such, it is unclear why it is being\ninserted into documentation aimed at _consumers_ of the strbuf API.\nMoreover, with it buried in existing API documentation like this, I\nfear that those at whom it is aimed will almost certainly overlook it.\n\nTo increase the likelihood that the target audience will indeed read\nthe new text, I'd suggest placing it in its own comment block very\nnear the top of the file, possibly prefixed with a loud \"NOTE FOR\nSTRBUF DEVELOPERS\" or some such. Further, as the new text is aimed at\nstrbuf developers, not strbuf consumers, it would make more sense to\nuse a plain /*...*/ comment block rather than a /**...*/ block.\n"},{"id":"476866","messageId":"CABPp-BGTByZg5rJCmBeZNwjNTFwsoQ5HTjEhmhYFFfi-KbfgTw@mail.gmail.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"Re: [PATCH v4 0/7] strbuf cleanups","fromName":"Elijah Newren","fromEmail":"newren@gmail.com","sentAt":"2023-05-09T01:57:59Z","receivedAt":"2023-05-09T01:58:17Z","isPatch":true,"sender":{"key":"newren@gmail.com","avatar":"https://avatars.githubusercontent.com/u/5455730?v=4"},"body":"On Mon, May 8, 2023 at 9:57 AM Calvin Wan <calvinwan@google.com> wrote:\n>\n> This reroll include suggestions made by Elijah and Junio, clarifying\n> commit messages in patches 2/4/5 and s/environment variable/global\n> variable in patch 7.\n>\n> Calvin Wan (7):\n>   strbuf: clarify API boundary\n>   abspath: move related functions to abspath\n>   credential-store: move related functions to credential-store file\n>   object-name: move related functions to object-name\n>   path: move related function to path\n>   strbuf: clarify dependency\n>   strbuf: remove global variable\n>\n>  abspath.c                  |  36 +++++++++++++\n>  abspath.h                  |  21 ++++++++\n>  add-patch.c                |  12 +++--\n>  builtin/am.c               |   2 +-\n>  builtin/branch.c           |   4 +-\n>  builtin/commit.c           |   2 +-\n>  builtin/credential-store.c |  19 +++++++\n>  builtin/merge.c            |  10 ++--\n>  builtin/notes.c            |  16 +++---\n>  builtin/rebase.c           |   2 +-\n>  builtin/stripspace.c       |   6 ++-\n>  builtin/tag.c              |   9 ++--\n>  fmt-merge-msg.c            |   9 ++--\n>  gpg-interface.c            |   5 +-\n>  hook.c                     |   1 +\n>  object-name.c              |  15 ++++++\n>  object-name.h              |   9 ++++\n>  path.c                     |  20 +++++++\n>  path.h                     |   5 ++\n>  pretty.c                   |   1 +\n>  rebase-interactive.c       |  15 +++---\n>  sequencer.c                |  24 +++++----\n>  strbuf.c                   | 106 +++----------------------------------\n>  strbuf.h                   |  53 +++++--------------\n>  tempfile.c                 |   1 +\n>  wt-status.c                |   6 +--\n>  26 files changed, 220 insertions(+), 189 deletions(-)\n>\n> Range-diff against v3:\n> -:  ---------- > 1:  e0dd3f5295 strbuf: clarify API boundary\n\nHuh?  I thought v3 had this patch.  v2 certainly did, and with the\nsame contents.  Did you just give the wrong range for the range-diff?\n\nAside: Can I plug gitgitgadget for a minute?  It\n  * handles the range-diff consistently\n  * sets up reply-to nicely\n  * ensures testing on a variety of platforms\n  * makes it _trivial_ to download the series via a simple fetch, with\nremote/branch/command documented in the cover letter\n\nI think the last point is particularly cool.  Yes, I know of b4, and\nit helps a lot, but a simple fetch, especially one where the cover\nletter contains the command, makes things easier for someone who comes\nalong to review.  I know I'm happier as a reviewer when I see a patch\nseries sent by gitgitgadget, because of this last point.  (Granted,\nfolks could just copy that really nice usability touch by hand in\ntheir cover letters if they like send-email, but I suspect it's enough\nof a hassle to the sender that people just don't do it.).  Anyway,\njust some food for thought.\n\n> 1:  ec1ea6ae4f ! 2:  48fb5db28b abspath: move related functions to abspath\n>     @@ Metadata\n>       ## Commit message ##\n>          abspath: move related functions to abspath\n>\n>     -    Move abspath-related functions from strbuf.[ch] to abspath.[ch] since\n>     -    paths are not primitive objects and therefore strbuf should not interact\n>     -    with them.\n>     +    Move abspath-related functions from strbuf.[ch] to abspath.[ch] so that\n>     +    strbuf is focused on string manipulation routines with minimal\n>     +    dependencies.\n>\n>       ## abspath.c ##\n>      @@ abspath.c: char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n> 2:  2d74561b91 = 3:  a663f91819 credential-store: move related functions to credential-store file\n> 3:  30b5e635cb ! 4:  ccef9dd5f2 object-name: move related functions to object-name\n>     @@ Commit message\n>          object-name: move related functions to object-name\n>\n>          Move object-name-related functions from strbuf.[ch] to object-name.[ch]\n>     -    since paths are not a primitive object that strbuf should directly\n>     -    interact with.\n>     +    so that strbuf is focused on string manipulation routines with minimal\n>     +    dependencies.\n>\n>       ## object-name.c ##\n>      @@ object-name.c: static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n> 4:  6905618470 ! 5:  0d6b9cf0f7 path: move related function to path\n>     @@ Metadata\n>       ## Commit message ##\n>          path: move related function to path\n>\n>     -    Move path-related function from strbuf.[ch] to path.[ch] since path is\n>     -    not a primitive object and therefore strbuf should not directly interact\n>     -    with it.\n>     +    Move path-related function from strbuf.[ch] to path.[ch] so that strbuf\n>     +    is focused on string manipulation routines with minimal dependencies.\n>\n>       ## path.c ##\n>      @@ path.c: int normalize_path_copy(char *dst, const char *src)\n> 5:  caf3482bf7 = 6:  5655c56a6d strbuf: clarify dependency\n> 6:  3bbaebf292 ! 7:  874d0efac3 strbuf: remove environment variable\n>     @@ Metadata\n>      Author: Calvin Wan <calvinwan@google.com>\n>\n>       ## Commit message ##\n>     -    strbuf: remove environment variable\n>     +    strbuf: remove global variable\n>\n>          As a library that only interacts with other primitives, strbuf should\n>     -    not utilize the comment_line_char environment variable within its\n>     +    not utilize the comment_line_char global variable within its\n>          functions. Therefore, add an additional parameter for functions that use\n>          comment_line_char and refactor callers to pass it in instead.\n>\n> --\n> 2.40.1.521.gf1e218fcd8-goog\n\nOther than the off-by-one in the range-diff of the cover letter, this\nall looks good to me:\n\nReviewed-by: Elijah Newren <newren@gmail.com>\n"},{"id":"476867","messageId":"6459ac3e658c6_7c68294a1@chronos.notmuch","threadId":"59685","inReplyTo":"CABPp-BGTByZg5rJCmBeZNwjNTFwsoQ5HTjEhmhYFFfi-KbfgTw@mail.gmail.com","subject":"Re: [PATCH v4 0/7] strbuf cleanups","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2023-05-09T02:13:18Z","receivedAt":"2023-05-09T02:13:23Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Elijah Newren wrote:\n> On Mon, May 8, 2023 at 9:57 AM Calvin Wan <calvinwan@google.com> wrote:\n\n> > Range-diff against v3:\n> > -:  ---------- > 1:  e0dd3f5295 strbuf: clarify API boundary\n> \n> Huh?  I thought v3 had this patch.  v2 certainly did, and with the\n> same contents.  Did you just give the wrong range for the range-diff?\n> \n> Aside: Can I plug gitgitgadget for a minute?\n\nI guess I can plug git-send-series [1] as well.\n\n>   * handles the range-diff consistently\n>   * sets up reply-to nicely\n\nSame with git-send-email.\n\n>   * ensures testing on a variety of platforms\n>   * makes it _trivial_ to download the series via a simple fetch, with\n> remote/branch/command documented in the cover letter\n\nThis is orthogonal to sending a patch series, but anyone pushing to\nGitHub can do that.\n\nAdvantages of git-send-email that gitgitgadget doesn't have:\n\n * Everything about it can be handled locally\n * It's a standalone script fully in your control\n * It's not tied to any organization or corporation\n\n[1] https://github.com/felipec/git-send-series\n\n-- \nFelipe Contreras"},{"id":"476953","messageId":"8c8afa4a-ae2d-5a13-f9fa-5a5e11a0c810@gmail.com","threadId":"59685","inReplyTo":"20230508165908.526247-7-calvinwan@google.com","subject":"Re: [PATCH v4 7/7] strbuf: remove global variable","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-05-10T08:12:32Z","receivedAt":"2023-05-10T08:13:19Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Calvin\n\nOn 08/05/2023 17:59, Calvin Wan wrote:\n> As a library that only interacts with other primitives, strbuf should\n> not utilize the comment_line_char global variable within its\n> functions. Therefore, add an additional parameter for functions that use\n> comment_line_char and refactor callers to pass it in instead.\n\nI find the revised subject and commit message much easier to understand.\n\n> diff --git a/strbuf.c b/strbuf.c\n> index d5978fee4e..eba65ca421 100644\n> --- a/strbuf.c\n> +++ b/strbuf.c\n> @@ -1,6 +1,5 @@\n>   #include \"git-compat-util.h\"\n>   #include \"alloc.h\"\n> -#include \"environment.h\"\n>   #include \"gettext.h\"\n>   #include \"hex.h\"\n>   #include \"strbuf.h\"\n> @@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n>   \tstrbuf_complete_line(out);\n>   }\n>   \n> -void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n> +void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n> +\t\t\t\tsize_t size, char comment_line_char)\n\nI don't really object to this change as I can understand why you are \nmaking it, but it does make this function more cumbersome to use within \ngit itself where we now have to pass the global comment_line_char \nexplicitly.\n\n> @@ -1054,7 +1055,8 @@ static size_t cleanup(char *line, size_t len)\n>    * Enable skip_comments to skip every line starting with comment\n>    * character.\n>    */\n> -void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n> +void strbuf_stripspace(struct strbuf *sb, int skip_comments,\n> +\t\t       char comment_line_char)\n\nRather than adding a new parameter here could we change the signature to\n\n\tvoid strbuf_stripspace(struct strbuf *sb, char comment_char)\n\nand not strip comments if comment_char == '\\0'? There doesn't seem much \npoint in forcing callers to pass comment_line_char when they don't want \nto strip comments.\n\nBest Wishes\n\nPhillip\n"},{"id":"477001","messageId":"xmqqr0rn241m.fsf@gitster.g","threadId":"59685","inReplyTo":"CAPig+cTQg7XzORPHeD79aHEi1ggOjTPw9X02VPgxcV9uoBOBxg@mail.gmail.com","subject":"Re: [PATCH v4 1/7] strbuf: clarify API boundary","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-10T22:51:49Z","receivedAt":"2023-05-10T22:51:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> On Mon, May 8, 2023 at 1:05 PM Calvin Wan <calvinwan@google.com> wrote:\n>> strbuf, as a generic and widely used structure across the codebase,\n>> should be limited as a libary to only interact with primitives. Add\n>\n> s/libary/library/\n>\n>> documentation so future functions can be appropriately be placed. Older\n>\n> Too many \"be\"'s.\n>\n>> functions that do not follow this boundary should eventually be moved or\n>> refactored.\n>>\n>> Signed-off-by: Calvin Wan <calvinwan@google.com>\n>> ---\n>> diff --git a/strbuf.h b/strbuf.h\n>> @@ -5,7 +5,11 @@ struct string_list;\n>>  /**\n>>   * strbuf's are meant to be used with all the usual C string and memory\n>> - * APIs. Given that the length of the buffer is known, it's often better to\n>> + * APIs. The objects that this API interacts with in this file should be\n>> + * limited to other primitives, however, there are older functions in here\n>> + * that should eventually be moved out or refactored.\n>> + *\n>> + * Given that the length of the buffer is known, it's often better to\n>>   * use the mem* functions than a str* one (memchr vs. strchr e.g.).\n>>   * Though, one has to be careful about the fact that str* functions often\n>>   * stop on NULs and that strbufs may have embedded NULs.\n>\n> The new text is administrative in nature, aimed at people who will be\n> modifying strbuf itself. As such, it is unclear why it is being\n> inserted into documentation aimed at _consumers_ of the strbuf API.\n> Moreover, with it buried in existing API documentation like this, I\n> fear that those at whom it is aimed will almost certainly overlook it.\n>\n> To increase the likelihood that the target audience will indeed read\n> the new text, I'd suggest placing it in its own comment block very\n> near the top of the file, possibly prefixed with a loud \"NOTE FOR\n> STRBUF DEVELOPERS\" or some such. Further, as the new text is aimed at\n> strbuf developers, not strbuf consumers, it would make more sense to\n> use a plain /*...*/ comment block rather than a /**...*/ block.\n\nAll look good suggestions to make.\n\nIf there is nothing else outstanding, let's see a small and\nhopefully final reroll so that the topic can be merged to 'next'\nsoonish.\n\nThanks.\n"},{"id":"477070","messageId":"20230511194446.1492907-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230508165728.525603-1-calvinwan@google.com","subject":"[PATCH v5 0/7] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T19:44:46Z","receivedAt":"2023-05-11T19:47:17Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"This reroll includes suggestions made by Eric and Phillip for better\ndocumentation on patch 1 and removal of an extraneous parameter in patch 7.\n\nCalvin Wan (7):\n  strbuf: clarify API boundary\n  abspath: move related functions to abspath\n  credential-store: move related functions to credential-store file\n  object-name: move related functions to object-name\n  path: move related function to path\n  strbuf: clarify dependency\n  strbuf: remove global variable\n\n abspath.c                  |  36 ++++++++++++\n abspath.h                  |  21 +++++++\n add-patch.c                |  12 ++--\n builtin/am.c               |   2 +-\n builtin/branch.c           |   4 +-\n builtin/commit.c           |   2 +-\n builtin/credential-store.c |  19 +++++++\n builtin/merge.c            |  10 ++--\n builtin/notes.c            |  16 +++---\n builtin/rebase.c           |   2 +-\n builtin/stripspace.c       |   6 +-\n builtin/tag.c              |   9 ++-\n fmt-merge-msg.c            |   9 ++-\n gpg-interface.c            |   5 +-\n hook.c                     |   1 +\n object-name.c              |  15 +++++\n object-name.h              |   9 +++\n path.c                     |  20 +++++++\n path.h                     |   5 ++\n pretty.c                   |   1 +\n rebase-interactive.c       |  15 ++---\n sequencer.c                |  24 +++++---\n strbuf.c                   | 112 ++++---------------------------------\n strbuf.h                   |  59 ++++++-------------\n tempfile.c                 |   1 +\n wt-status.c                |   6 +-\n 26 files changed, 229 insertions(+), 192 deletions(-)\n\nRange-diff against v4:\n1:  e0dd3f5295 ! 1:  287e787c9c strbuf: clarify API boundary\n    @@ Commit message\n         strbuf: clarify API boundary\n     \n         strbuf, as a generic and widely used structure across the codebase,\n    -    should be limited as a libary to only interact with primitives. Add\n    -    documentation so future functions can be appropriately be placed. Older\n    +    should be limited as a library to only interact with primitives. Add\n    +    documentation so future functions can appropriately be placed. Older\n         functions that do not follow this boundary should eventually be moved or\n         refactored.\n     \n      ## strbuf.h ##\n    -@@ strbuf.h: struct string_list;\n    +@@\n    + #ifndef STRBUF_H\n    + #define STRBUF_H\n    + \n    ++/*\n    ++ * NOTE FOR STRBUF DEVELOPERS\n    ++ *\n    ++ * The objects that this API interacts with should be limited to other\n    ++ * primitives, however, there are older functions in here that interact\n    ++ * with non-primitive objects which should eventually be moved out or\n    ++ * refactored.\n    ++ */\n    ++\n    + struct string_list;\n      \n      /**\n    -  * strbuf's are meant to be used with all the usual C string and memory\n    -- * APIs. Given that the length of the buffer is known, it's often better to\n    -+ * APIs. The objects that this API interacts with in this file should be \n    -+ * limited to other primitives, however, there are older functions in here \n    -+ * that should eventually be moved out or refactored. \n    -+ * \n    -+ * Given that the length of the buffer is known, it's often better to\n    -  * use the mem* functions than a str* one (memchr vs. strchr e.g.).\n    -  * Though, one has to be careful about the fact that str* functions often\n    -  * stop on NULs and that strbufs may have embedded NULs.\n2:  48fb5db28b = 2:  5bd27cad7a abspath: move related functions to abspath\n3:  a663f91819 = 3:  08e3e40de6 credential-store: move related functions to credential-store file\n4:  ccef9dd5f2 = 4:  1a21d4fdd1 object-name: move related functions to object-name\n5:  0d6b9cf0f7 = 5:  03b20f3384 path: move related function to path\n6:  5655c56a6d = 6:  b55f4a39e1 strbuf: clarify dependency\n7:  874d0efac3 ! 7:  6ea36d7730 strbuf: remove global variable\n    @@ Commit message\n         not utilize the comment_line_char global variable within its\n         functions. Therefore, add an additional parameter for functions that use\n         comment_line_char and refactor callers to pass it in instead.\n    +    strbuf_stripspace() removes the skip_comments boolean and checks if\n    +    comment_line_char is a non-NULL character to determine whether to skip\n    +    comments or not.\n     \n      ## add-patch.c ##\n     @@ add-patch.c: static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n    @@ builtin/am.c: static int parse_mail(struct am_state *state, const char *mail)\n      \tstrbuf_addstr(&msg, \"\\n\\n\");\n      \tstrbuf_addbuf(&msg, &mi.log_message);\n     -\tstrbuf_stripspace(&msg, 0);\n    -+\tstrbuf_stripspace(&msg, 0, comment_line_char);\n    ++\tstrbuf_stripspace(&msg, '\\0');\n      \n      \tassert(!state->author_name);\n      \tstate->author_name = strbuf_detach(&author_name, NULL);\n    @@ builtin/branch.c: static int edit_branch_description(const char *branch_name)\n      \t\treturn -1;\n      \t}\n     -\tstrbuf_stripspace(&buf, 1);\n    -+\tstrbuf_stripspace(&buf, 1, comment_line_char);\n    ++\tstrbuf_stripspace(&buf, comment_line_char);\n      \n      \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n      \tif (buf.len || exists)\n    @@ builtin/commit.c: static int prepare_to_commit(const char *index_file, const cha\n      \n      \tif (clean_message_contents)\n     -\t\tstrbuf_stripspace(&sb, 0);\n    -+\t\tstrbuf_stripspace(&sb, 0, comment_line_char);\n    ++\t\tstrbuf_stripspace(&sb, '\\0');\n      \n      \tif (signoff)\n      \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\n    @@ builtin/notes.c: static void prepare_note_data(const struct object_id *object, s\n      \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n      \t\t}\n     -\t\tstrbuf_stripspace(&d->buf, 1);\n    -+\t\tstrbuf_stripspace(&d->buf, 1, comment_line_char);\n    ++\t\tstrbuf_stripspace(&d->buf, comment_line_char);\n      \t}\n      }\n      \n    @@ builtin/notes.c: static int parse_msg_arg(const struct option *opt, const char *\n      \t\tstrbuf_addch(&d->buf, '\\n');\n      \tstrbuf_addstr(&d->buf, arg);\n     -\tstrbuf_stripspace(&d->buf, 0);\n    -+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n    ++\tstrbuf_stripspace(&d->buf, '\\0');\n      \n      \td->given = 1;\n      \treturn 0;\n    @@ builtin/notes.c: static int parse_file_arg(const struct option *opt, const char\n      \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n      \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n     -\tstrbuf_stripspace(&d->buf, 0);\n    -+\tstrbuf_stripspace(&d->buf, 0, comment_line_char);\n    ++\tstrbuf_stripspace(&d->buf, '\\0');\n      \n      \td->given = 1;\n      \treturn 0;\n    @@ builtin/rebase.c: static int edit_todo_file(unsigned flags)\n      \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n      \n     -\tstrbuf_stripspace(&todo_list.buf, 1);\n    -+\tstrbuf_stripspace(&todo_list.buf, 1, comment_line_char);\n    ++\tstrbuf_stripspace(&todo_list.buf, comment_line_char);\n      \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n      \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n      \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\n    @@ builtin/stripspace.c: int cmd_stripspace(int argc, const char **argv, const char\n      \n      \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n     -\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n    -+\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS,\n    -+\t\t\t\t  comment_line_char);\n    ++\t\tstrbuf_stripspace(&buf,\n    ++\t\t\t  mode == STRIP_COMMENTS ? comment_line_char : '\\0');\n      \telse\n      \t\tcomment_lines(&buf);\n      \n    @@ builtin/tag.c: static void create_tag(const struct object_id *object, const char\n      \n      \tif (opt->cleanup_mode != CLEANUP_NONE)\n     -\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n    -+\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL,\n    -+\t\t\t\t  comment_line_char);\n    ++\t\tstrbuf_stripspace(buf,\n    ++\t\t  opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\\0');\n      \n      \tif (!opt->message_given && !buf->len)\n      \t\tdie(_(\"no tag message?\"));\n    @@ gpg-interface.c: static int verify_ssh_signed_buffer(struct signature_check *sig\n      \n     -\tstrbuf_stripspace(&ssh_keygen_out, 0);\n     -\tstrbuf_stripspace(&ssh_keygen_err, 0);\n    -+\tstrbuf_stripspace(&ssh_keygen_out, 0, comment_line_char);\n    -+\tstrbuf_stripspace(&ssh_keygen_err, 0, comment_line_char);\n    ++\tstrbuf_stripspace(&ssh_keygen_out, '\\0');\n    ++\tstrbuf_stripspace(&ssh_keygen_err, '\\0');\n      \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n      \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n      \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\n    @@ rebase-interactive.c: int edit_todo_list(struct repository *r, struct todo_list\n      \t\treturn -2;\n      \n     -\tstrbuf_stripspace(&new_todo->buf, 1);\n    -+\tstrbuf_stripspace(&new_todo->buf, 1, comment_line_char);\n    ++\tstrbuf_stripspace(&new_todo->buf, comment_line_char);\n      \tif (initial && new_todo->buf.len == 0)\n      \t\treturn -3;\n      \n    @@ sequencer.c: void cleanup_message(struct strbuf *msgbuf,\n      \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n      \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n     -\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n    -+\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n    -+\t\t\t\t  comment_line_char);\n    ++\t\tstrbuf_stripspace(msgbuf,\n    ++\t\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n      }\n      \n      /*\n    @@ sequencer.c: int template_untouched(const struct strbuf *sb, const char *templat\n      \t\treturn 0;\n      \n     -\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n    -+\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL,\n    -+\t\t\t  comment_line_char);\n    ++\tstrbuf_stripspace(&tmpl,\n    ++\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n      \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n      \t\tstart = sb->buf;\n      \tstrbuf_release(&tmpl);\n    @@ sequencer.c: static int try_to_commit(struct repository *r,\n      \n      \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n     -\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n    -+\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL,\n    -+\t\t\t\t  comment_line_char);\n    ++\t\tstrbuf_stripspace(msg,\n    ++\t\t  cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n      \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n      \t\tres = 1; /* run 'git commit' to display error message */\n      \t\tgoto out;\n    @@ strbuf.c: void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n      \t\tsb->buf[--sb->len] = '\\0';\n      \n     @@ strbuf.c: static size_t cleanup(char *line, size_t len)\n    -  * Enable skip_comments to skip every line starting with comment\n    -  * character.\n    +  *\n    +  * If last line does not have a newline at the end, one is added.\n    +  *\n    +- * Enable skip_comments to skip every line starting with comment\n    +- * character.\n    ++ * Pass a non-NULL comment_line_char to skip every line starting\n    ++ * with it\n       */\n     -void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n    -+void strbuf_stripspace(struct strbuf *sb, int skip_comments,\n    -+\t\t       char comment_line_char)\n    ++void strbuf_stripspace(struct strbuf *sb, char comment_line_char)\n      {\n      \tsize_t empties = 0;\n      \tsize_t i, j, len, newlen;\n    +@@ strbuf.c: void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n    + \t\teol = memchr(sb->buf + i, '\\n', sb->len - i);\n    + \t\tlen = eol ? eol - (sb->buf + i) + 1 : sb->len - i;\n    + \n    +-\t\tif (skip_comments && len && sb->buf[i] == comment_line_char) {\n    ++\t\tif (comment_line_char != '\\0' && len &&\n    ++\t\t    sb->buf[i] == comment_line_char) {\n    + \t\t\tnewlen = 0;\n    + \t\t\tcontinue;\n    + \t\t}\n     \n      ## strbuf.h ##\n     @@ strbuf.h: void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n    @@ strbuf.h: void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n      \n      __attribute__((format (printf,2,0)))\n      void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n    -@@ strbuf.h: int strbuf_normalize_path(struct strbuf *sb);\n    +@@ strbuf.h: int strbuf_getcwd(struct strbuf *sb);\n    + int strbuf_normalize_path(struct strbuf *sb);\n      \n      /**\n    -  * Strip whitespace from a buffer. The second parameter controls if\n    +- * Strip whitespace from a buffer. The second parameter controls if\n     - * comments are considered contents to be removed or not.\n    -+ * comments are considered contents to be removed or not. The third parameter\n    -+ * is the comment character that determines whether a line is a comment or not.\n    ++ * Strip whitespace from a buffer. The second parameter is the comment\n    ++ * character that determines whether a line is a comment or not. If the\n    ++ * second parameter is a non-NULL character, comments are considered\n    ++ * contents to be removed.\n       */\n     -void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n    -+void strbuf_stripspace(struct strbuf *buf, int skip_comments, char comment_line_char);\n    ++void strbuf_stripspace(struct strbuf *buf, char comment_line_char);\n      \n      static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n      {\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477072","messageId":"20230511194822.1493798-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230511194446.1492907-1-calvinwan@google.com","subject":"[PATCH v5 1/7] strbuf: clarify API boundary","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T19:48:16Z","receivedAt":"2023-05-11T19:49:15Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"strbuf, as a generic and widely used structure across the codebase,\nshould be limited as a library to only interact with primitives. Add\ndocumentation so future functions can appropriately be placed. Older\nfunctions that do not follow this boundary should eventually be moved or\nrefactored.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.h | 9 +++++++++\n 1 file changed, 9 insertions(+)\n\ndiff --git a/strbuf.h b/strbuf.h\nindex 3dfeadb44c..0256114002 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -1,6 +1,15 @@\n #ifndef STRBUF_H\n #define STRBUF_H\n \n+/*\n+ * NOTE FOR STRBUF DEVELOPERS\n+ *\n+ * The objects that this API interacts with should be limited to other\n+ * primitives, however, there are older functions in here that interact\n+ * with non-primitive objects which should eventually be moved out or\n+ * refactored.\n+ */\n+\n struct string_list;\n \n /**\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477071","messageId":"20230511194822.1493798-2-calvinwan@google.com","threadId":"59685","inReplyTo":"20230511194446.1492907-1-calvinwan@google.com","subject":"[PATCH v5 2/7] abspath: move related functions to abspath","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T19:48:17Z","receivedAt":"2023-05-11T19:49:16Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move abspath-related functions from strbuf.[ch] to abspath.[ch] so that\nstrbuf is focused on string manipulation routines with minimal\ndependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n abspath.c  | 36 ++++++++++++++++++++++++++++++++++++\n abspath.h  | 21 +++++++++++++++++++++\n hook.c     |  1 +\n strbuf.c   | 37 -------------------------------------\n strbuf.h   | 22 ----------------------\n tempfile.c |  1 +\n 6 files changed, 59 insertions(+), 59 deletions(-)\n\ndiff --git a/abspath.c b/abspath.c\nindex d032f5dce5..1202cde23d 100644\n--- a/abspath.c\n+++ b/abspath.c\n@@ -289,3 +289,39 @@ char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n \t\treturn xstrdup(arg);\n \treturn prefix_filename(pfx, arg);\n }\n+\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n+{\n+\tif (!*path)\n+\t\tdie(\"The empty string is not a valid path\");\n+\tif (!is_absolute_path(path)) {\n+\t\tstruct stat cwd_stat, pwd_stat;\n+\t\tsize_t orig_len = sb->len;\n+\t\tchar *cwd = xgetcwd();\n+\t\tchar *pwd = getenv(\"PWD\");\n+\t\tif (pwd && strcmp(pwd, cwd) &&\n+\t\t    !stat(cwd, &cwd_stat) &&\n+\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n+\t\t    !stat(pwd, &pwd_stat) &&\n+\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n+\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n+\t\t\tstrbuf_addstr(sb, pwd);\n+\t\telse\n+\t\t\tstrbuf_addstr(sb, cwd);\n+\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n+\t\t\tstrbuf_addch(sb, '/');\n+\t\tfree(cwd);\n+\t}\n+\tstrbuf_addstr(sb, path);\n+}\n+\n+void strbuf_add_real_path(struct strbuf *sb, const char *path)\n+{\n+\tif (sb->len) {\n+\t\tstruct strbuf resolved = STRBUF_INIT;\n+\t\tstrbuf_realpath(&resolved, path, 1);\n+\t\tstrbuf_addbuf(sb, &resolved);\n+\t\tstrbuf_release(&resolved);\n+\t} else\n+\t\tstrbuf_realpath(sb, path, 1);\n+}\ndiff --git a/abspath.h b/abspath.h\nindex 7cd3de5e9d..4653080d5e 100644\n--- a/abspath.h\n+++ b/abspath.h\n@@ -30,4 +30,25 @@ static inline int is_absolute_path(const char *path)\n \treturn is_dir_sep(path[0]) || has_dos_drive_prefix(path);\n }\n \n+/**\n+ * Add a path to a buffer, converting a relative path to an\n+ * absolute one in the process.  Symbolic links are not\n+ * resolved.\n+ */\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n+\n+/**\n+ * Canonize `path` (make it absolute, resolve symlinks, remove extra\n+ * slashes) and append it to `sb`.  Die with an informative error\n+ * message if there is a problem.\n+ *\n+ * The directory part of `path` (i.e., everything up to the last\n+ * dir_sep) must denote a valid, existing directory, but the last\n+ * component need not exist.\n+ *\n+ * Callers that don't mind links should use the more lightweight\n+ * strbuf_add_absolute_path() instead.\n+ */\n+void strbuf_add_real_path(struct strbuf *sb, const char *path);\n+\n #endif /* ABSPATH_H */\ndiff --git a/hook.c b/hook.c\nindex 76e322f580..2d8706371e 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -1,4 +1,5 @@\n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hook.h\"\ndiff --git a/strbuf.c b/strbuf.c\nindex 729378ec82..c3b6d48797 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,5 +1,4 @@\n #include \"git-compat-util.h\"\n-#include \"abspath.h\"\n #include \"alloc.h\"\n #include \"environment.h\"\n #include \"gettext.h\"\n@@ -899,42 +898,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)\n \tstrbuf_humanise(buf, bytes, 1);\n }\n \n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n-{\n-\tif (!*path)\n-\t\tdie(\"The empty string is not a valid path\");\n-\tif (!is_absolute_path(path)) {\n-\t\tstruct stat cwd_stat, pwd_stat;\n-\t\tsize_t orig_len = sb->len;\n-\t\tchar *cwd = xgetcwd();\n-\t\tchar *pwd = getenv(\"PWD\");\n-\t\tif (pwd && strcmp(pwd, cwd) &&\n-\t\t    !stat(cwd, &cwd_stat) &&\n-\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n-\t\t    !stat(pwd, &pwd_stat) &&\n-\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n-\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n-\t\t\tstrbuf_addstr(sb, pwd);\n-\t\telse\n-\t\t\tstrbuf_addstr(sb, cwd);\n-\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n-\t\t\tstrbuf_addch(sb, '/');\n-\t\tfree(cwd);\n-\t}\n-\tstrbuf_addstr(sb, path);\n-}\n-\n-void strbuf_add_real_path(struct strbuf *sb, const char *path)\n-{\n-\tif (sb->len) {\n-\t\tstruct strbuf resolved = STRBUF_INIT;\n-\t\tstrbuf_realpath(&resolved, path, 1);\n-\t\tstrbuf_addbuf(sb, &resolved);\n-\t\tstrbuf_release(&resolved);\n-\t} else\n-\t\tstrbuf_realpath(sb, path, 1);\n-}\n-\n int printf_ln(const char *fmt, ...)\n {\n \tint ret;\ndiff --git a/strbuf.h b/strbuf.h\nindex 0256114002..e1c0c326f2 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -536,28 +536,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);\n  */\n int strbuf_getcwd(struct strbuf *sb);\n \n-/**\n- * Add a path to a buffer, converting a relative path to an\n- * absolute one in the process.  Symbolic links are not\n- * resolved.\n- */\n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n-\n-/**\n- * Canonize `path` (make it absolute, resolve symlinks, remove extra\n- * slashes) and append it to `sb`.  Die with an informative error\n- * message if there is a problem.\n- *\n- * The directory part of `path` (i.e., everything up to the last\n- * dir_sep) must denote a valid, existing directory, but the last\n- * component need not exist.\n- *\n- * Callers that don't mind links should use the more lightweight\n- * strbuf_add_absolute_path() instead.\n- */\n-void strbuf_add_real_path(struct strbuf *sb, const char *path);\n-\n-\n /**\n  * Normalize in-place the path contained in the strbuf. See\n  * normalize_path_copy() for details. If an error occurs, the contents of \"sb\"\ndiff --git a/tempfile.c b/tempfile.c\nindex 50c377134c..6c88a63b42 100644\n--- a/tempfile.c\n+++ b/tempfile.c\n@@ -43,6 +43,7 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"path.h\"\n #include \"tempfile.h\"\n #include \"sigchain.h\"\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477073","messageId":"20230511194822.1493798-3-calvinwan@google.com","threadId":"59685","inReplyTo":"20230511194446.1492907-1-calvinwan@google.com","subject":"[PATCH v5 3/7] credential-store: move related functions to credential-store file","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T19:48:18Z","receivedAt":"2023-05-11T19:49:18Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"is_rfc3986_unreserved() and is_rfc3986_reserved_or_unreserved() are only\ncalled from builtin/credential-store.c and they are only relevant to that\nfile so move those functions and make them static.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n builtin/credential-store.c | 19 +++++++++++++++++++\n strbuf.c                   | 19 -------------------\n strbuf.h                   |  3 ---\n 3 files changed, 19 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/credential-store.c b/builtin/credential-store.c\nindex 8977604eb9..4776118331 100644\n--- a/builtin/credential-store.c\n+++ b/builtin/credential-store.c\n@@ -73,6 +73,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,\n \t\tdie_errno(\"unable to write credential store\");\n }\n \n+static int is_rfc3986_unreserved(char ch)\n+{\n+\treturn isalnum(ch) ||\n+\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n+}\n+\n+static int is_rfc3986_reserved_or_unreserved(char ch)\n+{\n+\tif (is_rfc3986_unreserved(ch))\n+\t\treturn 1;\n+\tswitch (ch) {\n+\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n+\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n+\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static void store_credential_file(const char *fn, struct credential *c)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/strbuf.c b/strbuf.c\nindex c3b6d48797..da2693b21f 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -809,25 +809,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)\n \t}\n }\n \n-int is_rfc3986_reserved_or_unreserved(char ch)\n-{\n-\tif (is_rfc3986_unreserved(ch))\n-\t\treturn 1;\n-\tswitch (ch) {\n-\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n-\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n-\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-int is_rfc3986_unreserved(char ch)\n-{\n-\treturn isalnum(ch) ||\n-\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n-}\n-\n static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,\n \t\t\t\t char_predicate allow_unencoded_fn)\n {\ndiff --git a/strbuf.h b/strbuf.h\nindex e1c0c326f2..90ad8b8892 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -691,9 +691,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);\n \n typedef int (*char_predicate)(char ch);\n \n-int is_rfc3986_unreserved(char ch);\n-int is_rfc3986_reserved_or_unreserved(char ch);\n-\n void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,\n \t\t\t     char_predicate allow_unencoded_fn);\n \n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477074","messageId":"20230511194822.1493798-6-calvinwan@google.com","threadId":"59685","inReplyTo":"20230511194446.1492907-1-calvinwan@google.com","subject":"[PATCH v5 6/7] strbuf: clarify dependency","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T19:48:21Z","receivedAt":"2023-05-11T19:49:20Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"refs.h was once needed but is no longer so as of 6bab74e7fb8 (\"strbuf:\nmove strbuf_branchname to sha1_name.c\", 2010-11-06). strbuf.h was\nincluded thru refs.h, so removing refs.h requires strbuf.h to be added\nback.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex 178d75f250..d5978fee4e 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,7 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"refs.h\"\n+#include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n #include \"date.h\"\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477075","messageId":"20230511194822.1493798-5-calvinwan@google.com","threadId":"59685","inReplyTo":"20230511194446.1492907-1-calvinwan@google.com","subject":"[PATCH v5 5/7] path: move related function to path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T19:48:20Z","receivedAt":"2023-05-11T19:49:22Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move path-related function from strbuf.[ch] to path.[ch] so that strbuf\nis focused on string manipulation routines with minimal dependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n path.c   | 20 ++++++++++++++++++++\n path.h   |  5 +++++\n strbuf.c | 20 --------------------\n 3 files changed, 25 insertions(+), 20 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 7c1cd8182a..e17a2613c5 100644\n--- a/path.c\n+++ b/path.c\n@@ -1213,6 +1213,26 @@ int normalize_path_copy(char *dst, const char *src)\n \treturn normalize_path_copy_len(dst, src, NULL);\n }\n \n+int strbuf_normalize_path(struct strbuf *src)\n+{\n+\tstruct strbuf dst = STRBUF_INIT;\n+\n+\tstrbuf_grow(&dst, src->len);\n+\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n+\t\tstrbuf_release(&dst);\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * normalize_path does not tell us the new length, so we have to\n+\t * compute it by looking for the new NUL it placed\n+\t */\n+\tstrbuf_setlen(&dst, strlen(dst.buf));\n+\tstrbuf_swap(src, &dst);\n+\tstrbuf_release(&dst);\n+\treturn 0;\n+}\n+\n /*\n  * path = Canonical absolute path\n  * prefixes = string_list containing normalized, absolute paths without\ndiff --git a/path.h b/path.h\nindex 60e83a49a9..639372edd9 100644\n--- a/path.h\n+++ b/path.h\n@@ -191,6 +191,11 @@ const char *remove_leading_path(const char *in, const char *prefix);\n const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);\n int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);\n int normalize_path_copy(char *dst, const char *src);\n+/**\n+ * Normalize in-place the path contained in the strbuf. If an error occurs,\n+ * the contents of \"sb\" are left untouched, and -1 is returned.\n+ */\n+int strbuf_normalize_path(struct strbuf *src);\n int longest_ancestor_length(const char *path, struct string_list *prefixes);\n char *strip_path_suffix(const char *path, const char *suffix);\n int daemon_avoid_alias(const char *path);\ndiff --git a/strbuf.c b/strbuf.c\nindex 6533559e95..178d75f250 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1088,26 +1088,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \tstrbuf_setlen(sb, j);\n }\n \n-int strbuf_normalize_path(struct strbuf *src)\n-{\n-\tstruct strbuf dst = STRBUF_INIT;\n-\n-\tstrbuf_grow(&dst, src->len);\n-\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n-\t\tstrbuf_release(&dst);\n-\t\treturn -1;\n-\t}\n-\n-\t/*\n-\t * normalize_path does not tell us the new length, so we have to\n-\t * compute it by looking for the new NUL it placed\n-\t */\n-\tstrbuf_setlen(&dst, strlen(dst.buf));\n-\tstrbuf_swap(src, &dst);\n-\tstrbuf_release(&dst);\n-\treturn 0;\n-}\n-\n void strbuf_strip_file_from_path(struct strbuf *sb)\n {\n \tchar *path_sep = find_last_dir_sep(sb->buf);\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477076","messageId":"20230511194822.1493798-4-calvinwan@google.com","threadId":"59685","inReplyTo":"20230511194446.1492907-1-calvinwan@google.com","subject":"[PATCH v5 4/7] object-name: move related functions to object-name","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T19:48:19Z","receivedAt":"2023-05-11T19:49:24Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move object-name-related functions from strbuf.[ch] to object-name.[ch]\nso that strbuf is focused on string manipulation routines with minimal\ndependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n object-name.c | 15 +++++++++++++++\n object-name.h |  9 +++++++++\n pretty.c      |  1 +\n strbuf.c      | 16 ----------------\n strbuf.h      | 10 ----------\n 5 files changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 538e8a8f62..c2e82aceea 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -766,6 +766,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n \t\tfind_abbrev_len_for_pack(p, mad);\n }\n \n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len)\n+{\n+\tint r;\n+\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n+\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n+\tstrbuf_setlen(sb, sb->len + r);\n+}\n+\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len)\n+{\n+\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n+}\n+\n int repo_find_unique_abbrev_r(struct repository *r, char *hex,\n \t\t\t      const struct object_id *oid, int len)\n {\ndiff --git a/object-name.h b/object-name.h\nindex 1d63698f42..9ae5223071 100644\n--- a/object-name.h\n+++ b/object-name.h\n@@ -40,6 +40,15 @@ struct object_context {\n const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);\n int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);\n \n+/**\n+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n+ * the strbuf `sb`.\n+ */\n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len);\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len);\n+\n int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);\n __attribute__((format (printf, 2, 3)))\n int get_oidf(struct object_id *oid, const char *fmt, ...);\ndiff --git a/pretty.c b/pretty.c\nindex 0bb938021b..78bac2d818 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -18,6 +18,7 @@\n #include \"gpg-interface.h\"\n #include \"trailer.h\"\n #include \"run-command.h\"\n+#include \"object-name.h\"\n \n /*\n  * The limit for formatting directives, which enable the caller to append\ndiff --git a/strbuf.c b/strbuf.c\nindex da2693b21f..6533559e95 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,6 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"object-name.h\"\n #include \"refs.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n@@ -1023,21 +1022,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,\n \tstrbuf_setlen(sb, sb->len + len);\n }\n \n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len)\n-{\n-\tint r;\n-\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n-\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n-\tstrbuf_setlen(sb, sb->len + r);\n-}\n-\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len)\n-{\n-\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n-}\n-\n /*\n  * Returns the length of a line, without trailing spaces.\n  *\ndiff --git a/strbuf.h b/strbuf.h\nindex 90ad8b8892..b38bfd34af 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -617,16 +617,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,\n  */\n void strbuf_list_free(struct strbuf **list);\n \n-/**\n- * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n- * the strbuf `sb`.\n- */\n-struct repository;\n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len);\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len);\n-\n /*\n  * Remove the filename from the provided path string. If the path\n  * contains a trailing separator, then the path is considered a directory\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477077","messageId":"20230511194822.1493798-7-calvinwan@google.com","threadId":"59685","inReplyTo":"20230511194446.1492907-1-calvinwan@google.com","subject":"[PATCH v5 7/7] strbuf: remove global variable","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T19:48:22Z","receivedAt":"2023-05-11T19:49:38Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"As a library that only interacts with other primitives, strbuf should\nnot utilize the comment_line_char global variable within its\nfunctions. Therefore, add an additional parameter for functions that use\ncomment_line_char and refactor callers to pass it in instead.\nstrbuf_stripspace() removes the skip_comments boolean and checks if\ncomment_line_char is a non-NULL character to determine whether to skip\ncomments or not.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n add-patch.c          | 12 +++++++-----\n builtin/am.c         |  2 +-\n builtin/branch.c     |  4 ++--\n builtin/commit.c     |  2 +-\n builtin/merge.c      | 10 ++++++----\n builtin/notes.c      | 16 +++++++++-------\n builtin/rebase.c     |  2 +-\n builtin/stripspace.c |  6 ++++--\n builtin/tag.c        |  9 ++++++---\n fmt-merge-msg.c      |  9 ++++++---\n gpg-interface.c      |  5 +++--\n rebase-interactive.c | 15 ++++++++-------\n sequencer.c          | 24 +++++++++++++++---------\n strbuf.c             | 18 ++++++++++--------\n strbuf.h             | 15 +++++++++------\n wt-status.c          |  6 +++---\n 16 files changed, 91 insertions(+), 64 deletions(-)\n\ndiff --git a/add-patch.c b/add-patch.c\nindex 8d770d203f..9702c1aabd 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \tsize_t i;\n \n \tstrbuf_reset(&s->buf);\n-\tstrbuf_commented_addf(&s->buf, _(\"Manual hunk edit mode -- see bottom for \"\n-\t\t\t\t      \"a quick guide.\\n\"));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n+\t\t\t      _(\"Manual hunk edit mode -- see bottom for \"\n+\t\t\t\t\"a quick guide.\\n\"));\n \trender_hunk(s, hunk, 0, 0, &s->buf);\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"---\\n\"\n \t\t\t\t\"To remove '%c' lines, make them ' ' lines \"\n \t\t\t\t\"(context).\\n\"\n@@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \t\t\t      s->mode->is_reverse ? '+' : '-',\n \t\t\t      s->mode->is_reverse ? '-' : '+',\n \t\t\t      comment_line_char);\n-\tstrbuf_commented_addf(&s->buf, \"%s\", _(s->mode->edit_hunk_hint));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char, \"%s\",\n+\t\t\t      _(s->mode->edit_hunk_hint));\n \t/*\n \t * TRANSLATORS: 'it' refers to the patch mentioned in the previous\n \t * messages.\n \t */\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"If it does not apply cleanly, you will be \"\n \t\t\t\t\"given an opportunity to\\n\"\n \t\t\t\t\"edit again.  If all lines of the hunk are \"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5c83f2e003..9ece2e3066 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n \tstrbuf_addbuf(&msg, &mi.log_message);\n-\tstrbuf_stripspace(&msg, 0);\n+\tstrbuf_stripspace(&msg, '\\0');\n \n \tassert(!state->author_name);\n \tstate->author_name = strbuf_detach(&author_name, NULL);\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 501c47657c..4560610d09 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -629,7 +629,7 @@ static int edit_branch_description(const char *branch_name)\n \texists = !read_branch_desc(&buf, branch_name);\n \tif (!buf.len || buf.buf[buf.len-1] != '\\n')\n \t\tstrbuf_addch(&buf, '\\n');\n-\tstrbuf_commented_addf(&buf,\n+\tstrbuf_commented_addf(&buf, comment_line_char,\n \t\t    _(\"Please edit the description for the branch\\n\"\n \t\t      \"  %s\\n\"\n \t\t      \"Lines starting with '%c' will be stripped.\\n\"),\n@@ -640,7 +640,7 @@ static int edit_branch_description(const char *branch_name)\n \t\tstrbuf_release(&buf);\n \t\treturn -1;\n \t}\n-\tstrbuf_stripspace(&buf, 1);\n+\tstrbuf_stripspace(&buf, comment_line_char);\n \n \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n \tif (buf.len || exists)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex e67c4be221..e002ebf070 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \ts->hints = 0;\n \n \tif (clean_message_contents)\n-\t\tstrbuf_stripspace(&sb, 0);\n+\t\tstrbuf_stripspace(&sb, '\\0');\n \n \tif (signoff)\n \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8da3e46abb..1d14767c0c 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)\n \t\tstrbuf_addch(&msg, '\\n');\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {\n \t\t\twt_status_append_cut_line(&msg);\n-\t\t\tstrbuf_commented_addf(&msg, \"\\n\");\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char, \"\\n\");\n \t\t}\n-\t\tstrbuf_commented_addf(&msg, _(merge_editor_comment));\n+\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t      _(merge_editor_comment));\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n-\t\t\tstrbuf_commented_addf(&msg, _(scissors_editor_comment));\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t\t      _(scissors_editor_comment));\n \t\telse\n-\t\t\tstrbuf_commented_addf(&msg,\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n \t\t\t\t_(no_scissors_editor_comment), comment_line_char);\n \t}\n \tif (signoff)\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex d5788352b6..3bad5b458b 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -11,6 +11,7 @@\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"editor.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"notes.h\"\n@@ -157,7 +158,7 @@ static void write_commented_object(int fd, const struct object_id *object)\n \n \tif (strbuf_read(&buf, show.out, 0) < 0)\n \t\tdie_errno(_(\"could not read 'show' output\"));\n-\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);\n \twrite_or_die(fd, cbuf.buf, cbuf.len);\n \n \tstrbuf_release(&cbuf);\n@@ -185,9 +186,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\t\tcopy_obj_to_fd(fd, old_note);\n \n \t\tstrbuf_addch(&buf, '\\n');\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n-\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),\n+\t\t\t\t\t   comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n \t\twrite_or_die(fd, buf.buf, buf.len);\n \n \t\twrite_commented_object(fd, object);\n@@ -199,7 +201,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\tif (launch_editor(d->edit_path, &d->buf, NULL)) {\n \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n \t\t}\n-\t\tstrbuf_stripspace(&d->buf, 1);\n+\t\tstrbuf_stripspace(&d->buf, comment_line_char);\n \t}\n }\n \n@@ -225,7 +227,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \tstrbuf_addstr(&d->buf, arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, '\\0');\n \n \td->given = 1;\n \treturn 0;\n@@ -244,7 +246,7 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n \t\t\tdie_errno(_(\"cannot read '%s'\"), arg);\n \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, '\\0');\n \n \td->given = 1;\n \treturn 0;\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex ace1d5e8d1..b1ba9fb05d 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)\n \tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n \n-\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tstrbuf_stripspace(&todo_list.buf, comment_line_char);\n \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 9451eb69ff..1987752359 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"parse-options.h\"\n #include \"setup.h\"\n@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)\n \tsize_t len;\n \n \tmsg = strbuf_detach(buf, &len);\n-\tstrbuf_add_commented_lines(buf, msg, len);\n+\tstrbuf_add_commented_lines(buf, msg, len, comment_line_char);\n \tfree(msg);\n }\n \n@@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)\n \t\tdie_errno(\"could not read the input\");\n \n \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n-\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n+\t\tstrbuf_stripspace(&buf,\n+\t\t\t  mode == STRIP_COMMENTS ? comment_line_char : '\\0');\n \telse\n \t\tcomment_lines(&buf);\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1850a6a6fd..b79e0a88e6 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n \t\t\tstrbuf_addch(&buf, '\\n');\n \t\t\tif (opt->cleanup_mode == CLEANUP_ALL)\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template), tag, comment_line_char);\n \t\t\telse\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template_nocleanup), tag, comment_line_char);\n \t\t\twrite_or_die(fd, buf.buf, buf.len);\n \t\t\tstrbuf_release(&buf);\n \t\t}\n@@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t}\n \n \tif (opt->cleanup_mode != CLEANUP_NONE)\n-\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n+\t\tstrbuf_stripspace(buf,\n+\t\t  opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\\0');\n \n \tif (!opt->message_given && !buf->len)\n \t\tdie(_(\"no tag message?\"));\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 5af0d4715b..5d15e2387d 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,\n \tstrbuf_complete_line(tagbuf);\n \tif (sig->len) {\n \t\tstrbuf_addch(tagbuf, '\\n');\n-\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len);\n+\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len,\n+\t\t\t\t\t   comment_line_char);\n \t}\n }\n \n@@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\t\tstrbuf_addch(&tagline, '\\n');\n \t\t\t\tstrbuf_add_commented_lines(&tagline,\n \t\t\t\t\t\torigins.items[first_tag].string,\n-\t\t\t\t\t\tstrlen(origins.items[first_tag].string));\n+\t\t\t\t\t\tstrlen(origins.items[first_tag].string),\n+\t\t\t\t\t\tcomment_line_char);\n \t\t\t\tstrbuf_insert(&tagbuf, 0, tagline.buf,\n \t\t\t\t\t      tagline.len);\n \t\t\t\tstrbuf_release(&tagline);\n@@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\tstrbuf_addch(&tagbuf, '\\n');\n \t\t\tstrbuf_add_commented_lines(&tagbuf,\n \t\t\t\t\torigins.items[i].string,\n-\t\t\t\t\tstrlen(origins.items[i].string));\n+\t\t\t\t\tstrlen(origins.items[i].string),\n+\t\t\t\t\tcomment_line_char);\n \t\t\tfmt_tag_signature(&tagbuf, &sig, buf, len);\n \t\t}\n \t\tstrbuf_release(&payload);\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex f3ac5acdd9..c27a751b70 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -11,6 +11,7 @@\n #include \"tempfile.h\"\n #include \"alias.h\"\n #include \"wrapper.h\"\n+#include \"environment.h\"\n \n static int git_gpg_config(const char *, const char *, void *);\n \n@@ -584,8 +585,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,\n \t\t}\n \t}\n \n-\tstrbuf_stripspace(&ssh_keygen_out, 0);\n-\tstrbuf_stripspace(&ssh_keygen_err, 0);\n+\tstrbuf_stripspace(&ssh_keygen_out, '\\0');\n+\tstrbuf_stripspace(&ssh_keygen_err, '\\0');\n \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 789f407361..012defbb53 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -71,13 +71,14 @@ void append_todo_help(int command_count,\n \n \tif (!edit_todo) {\n \t\tstrbuf_addch(buf, '\\n');\n-\t\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n-\t\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n-\t\t\t\t\t      command_count),\n+\t\tstrbuf_commented_addf(buf, comment_line_char,\n+\t\t\t\t      Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t\t \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t\t command_count),\n \t\t\t\t      shortrevisions, shortonto, command_count);\n \t}\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -86,7 +87,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -97,7 +98,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n }\n \n int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n@@ -129,7 +130,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n \tif (launch_sequence_editor(todo_file, &new_todo->buf, NULL))\n \t\treturn -2;\n \n-\tstrbuf_stripspace(&new_todo->buf, 1);\n+\tstrbuf_stripspace(&new_todo->buf, comment_line_char);\n \tif (initial && new_todo->buf.len == 0)\n \t\treturn -3;\n \ndiff --git a/sequencer.c b/sequencer.c\nindex c88d1d9553..eae4563ef7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -659,11 +659,12 @@ void append_conflicts_hint(struct index_state *istate,\n \t}\n \n \tstrbuf_addch(msgbuf, '\\n');\n-\tstrbuf_commented_addf(msgbuf, \"Conflicts:\\n\");\n+\tstrbuf_commented_addf(msgbuf, comment_line_char, \"Conflicts:\\n\");\n \tfor (i = 0; i < istate->cache_nr;) {\n \t\tconst struct cache_entry *ce = istate->cache[i++];\n \t\tif (ce_stage(ce)) {\n-\t\t\tstrbuf_commented_addf(msgbuf, \"\\t%s\\n\", ce->name);\n+\t\t\tstrbuf_commented_addf(msgbuf, comment_line_char,\n+\t\t\t\t\t      \"\\t%s\\n\", ce->name);\n \t\t\twhile (i < istate->cache_nr &&\n \t\t\t       !strcmp(ce->name, istate->cache[i]->name))\n \t\t\t\ti++;\n@@ -1142,7 +1143,8 @@ void cleanup_message(struct strbuf *msgbuf,\n \t    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msgbuf,\n+\t\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n }\n \n /*\n@@ -1173,7 +1175,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,\n \tif (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)\n \t\treturn 0;\n \n-\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\tstrbuf_stripspace(&tmpl,\n+\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n \t\tstart = sb->buf;\n \tstrbuf_release(&tmpl);\n@@ -1545,7 +1548,8 @@ static int try_to_commit(struct repository *r,\n \t\tcleanup = opts->default_msg_cleanup;\n \n \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msg,\n+\t\t  cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n \t\tres = 1; /* run 'git commit' to display error message */\n \t\tgoto out;\n@@ -1839,7 +1843,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n \t\ts += count;\n \t\tlen -= count;\n \t}\n-\tstrbuf_add_commented_lines(buf, s, len);\n+\tstrbuf_add_commented_lines(buf, s, len, comment_line_char);\n }\n \n /* Does the current fixup chain contain a squash command? */\n@@ -1938,7 +1942,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_add_commented_lines(buf, body, commented_len, comment_line_char);\n \t/* buf->buf may be reallocated so store an offset into the buffer */\n \tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n@@ -2028,7 +2032,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tif (is_fixup_flag(command, flag))\n-\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t\t   comment_line_char);\n \t\telse\n \t\t\tstrbuf_addstr(&buf, body);\n \n@@ -2047,7 +2052,8 @@ static int update_squash_messages(struct repository *r,\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t   comment_line_char);\n \t} else\n \t\treturn error(_(\"unknown command: %d\"), command);\n \trepo_unuse_commit_buffer(r, commit, message);\ndiff --git a/strbuf.c b/strbuf.c\nindex d5978fee4e..9348ac6863 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,6 +1,5 @@\n #include \"git-compat-util.h\"\n #include \"alloc.h\"\n-#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"strbuf.h\"\n@@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n \tstrbuf_complete_line(out);\n }\n \n-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n+\t\t\t\tsize_t size, char comment_line_char)\n {\n \tstatic char prefix1[3];\n \tstatic char prefix2[2];\n@@ -374,7 +374,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size\n \tadd_lines(out, prefix1, prefix2, buf, size);\n }\n \n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,\n+\t\t\t   const char *fmt, ...)\n {\n \tva_list params;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -384,7 +385,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n \tstrbuf_vaddf(&buf, fmt, params);\n \tva_end(params);\n \n-\tstrbuf_add_commented_lines(sb, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);\n \tif (incomplete_line)\n \t\tsb->buf[--sb->len] = '\\0';\n \n@@ -1051,10 +1052,10 @@ static size_t cleanup(char *line, size_t len)\n  *\n  * If last line does not have a newline at the end, one is added.\n  *\n- * Enable skip_comments to skip every line starting with comment\n- * character.\n+ * Pass a non-NULL comment_line_char to skip every line starting\n+ * with it\n  */\n-void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n+void strbuf_stripspace(struct strbuf *sb, char comment_line_char)\n {\n \tsize_t empties = 0;\n \tsize_t i, j, len, newlen;\n@@ -1067,7 +1068,8 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \t\teol = memchr(sb->buf + i, '\\n', sb->len - i);\n \t\tlen = eol ? eol - (sb->buf + i) + 1 : sb->len - i;\n \n-\t\tif (skip_comments && len && sb->buf[i] == comment_line_char) {\n+\t\tif (comment_line_char != '\\0' && len &&\n+\t\t    sb->buf[i] == comment_line_char) {\n \t\t\tnewlen = 0;\n \t\t\tcontinue;\n \t\t}\ndiff --git a/strbuf.h b/strbuf.h\nindex b38bfd34af..89ae30b620 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -292,7 +292,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n  * by a comment character and a blank.\n  */\n void strbuf_add_commented_lines(struct strbuf *out,\n-\t\t\t\tconst char *buf, size_t size);\n+\t\t\t\tconst char *buf, size_t size,\n+\t\t\t\tchar comment_line_char);\n \n \n /**\n@@ -421,8 +422,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n  * Add a formatted string prepended by a comment character and a\n  * blank to the buffer.\n  */\n-__attribute__((format (printf, 2, 3)))\n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n+__attribute__((format (printf, 3, 4)))\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n \n __attribute__((format (printf,2,0)))\n void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n@@ -544,10 +545,12 @@ int strbuf_getcwd(struct strbuf *sb);\n int strbuf_normalize_path(struct strbuf *sb);\n \n /**\n- * Strip whitespace from a buffer. The second parameter controls if\n- * comments are considered contents to be removed or not.\n+ * Strip whitespace from a buffer. The second parameter is the comment\n+ * character that determines whether a line is a comment or not. If the\n+ * second parameter is a non-NULL character, comments are considered\n+ * contents to be removed.\n  */\n-void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n+void strbuf_stripspace(struct strbuf *buf, char comment_line_char);\n \n static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n {\ndiff --git a/wt-status.c b/wt-status.c\nindex 97b9c1c035..da7734866f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1023,7 +1023,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom\n \tif (s->display_comment_prefix) {\n \t\tsize_t len;\n \t\tsummary_content = strbuf_detach(&summary, &len);\n-\t\tstrbuf_add_commented_lines(&summary, summary_content, len);\n+\t\tstrbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);\n \t\tfree(summary_content);\n \t}\n \n@@ -1098,8 +1098,8 @@ void wt_status_append_cut_line(struct strbuf *buf)\n {\n \tconst char *explanation = _(\"Do not modify or remove the line above.\\nEverything below it will be ignored.\");\n \n-\tstrbuf_commented_addf(buf, \"%s\", cut_line);\n-\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation));\n+\tstrbuf_commented_addf(buf, comment_line_char, \"%s\", cut_line);\n+\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);\n }\n \n void wt_status_add_cut_line(FILE *fp)\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477080","messageId":"CAPig+cSTVbvyUOOoVrsTS8t4VSoCbVRoA=i6j0_4KZX5ZTt34Q@mail.gmail.com","threadId":"59685","inReplyTo":"20230511194822.1493798-1-calvinwan@google.com","subject":"Re: [PATCH v5 1/7] strbuf: clarify API boundary","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2023-05-11T19:57:19Z","receivedAt":"2023-05-11T19:57:35Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, May 11, 2023 at 3:48 PM Calvin Wan <calvinwan@google.com> wrote:\n> strbuf, as a generic and widely used structure across the codebase,\n> should be limited as a library to only interact with primitives. Add\n> documentation so future functions can appropriately be placed. Older\n> functions that do not follow this boundary should eventually be moved or\n> refactored.\n>\n> Signed-off-by: Calvin Wan <calvinwan@google.com>\n> ---\n> diff --git a/strbuf.h b/strbuf.h\n> @@ -1,6 +1,15 @@\n> +/*\n> + * NOTE FOR STRBUF DEVELOPERS\n> + *\n> + * The objects that this API interacts with should be limited to other\n> + * primitives, however, there are older functions in here that interact\n> + * with non-primitive objects which should eventually be moved out or\n> + * refactored.\n> + */\n\nSorry, I meant to send a follow-up to my previous email[1] but forgot.\nIn particular, I wanted to say that I think the second part of the\nabove comment (the \"however\" and everything which follows) ought to be\ndropped since it will become stale once those \"older functions\" are\nfinally removed; it is likely nobody will remember to update this\ncomment. So, the above could rewritten something like this:\n\n /*\n  * NOTE FOR STRBUF DEVELOPERS\n  *\n  * strbuf is a low-level primitive; as such it should interact only\n  * with other low-level primitives. Do not introduce new functions\n  * which interact with higher-level APIs.\n  */\n\n[1]: https://lore.kernel.org/git/CAPig+cTQg7XzORPHeD79aHEi1ggOjTPw9X02VPgxcV9uoBOBxg@mail.gmail.com/\n"},{"id":"477082","messageId":"CAFySSZBE9PDyRd+fW25awStc3-0Skjj4gqnR-FZQy23vry1RtQ@mail.gmail.com","threadId":"59685","inReplyTo":"CAPig+cSTVbvyUOOoVrsTS8t4VSoCbVRoA=i6j0_4KZX5ZTt34Q@mail.gmail.com","subject":"Re: [PATCH v5 1/7] strbuf: clarify API boundary","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-11T20:03:15Z","receivedAt":"2023-05-11T20:03:31Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"> Sorry, I meant to send a follow-up to my previous email[1] but forgot.\n> In particular, I wanted to say that I think the second part of the\n> above comment (the \"however\" and everything which follows) ought to be\n> dropped since it will become stale once those \"older functions\" are\n> finally removed; it is likely nobody will remember to update this\n> comment. So, the above could rewritten something like this:\n>\n>  /*\n>   * NOTE FOR STRBUF DEVELOPERS\n>   *\n>   * strbuf is a low-level primitive; as such it should interact only\n>   * with other low-level primitives. Do not introduce new functions\n>   * which interact with higher-level APIs.\n>   */\n\nI agree that it'll probably be forgotten about so your suggested\ndocumentation sounds better. If others don't have any more comments\non the other patches, I'll reroll just this patch.\n"},{"id":"477085","messageId":"CAPig+cR-m45q0Y9YUnRPRzny0Q=sa4dPWCjxwHBN84VMtEsxzA@mail.gmail.com","threadId":"59685","inReplyTo":"20230511194822.1493798-7-calvinwan@google.com","subject":"Re: [PATCH v5 7/7] strbuf: remove global variable","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2023-05-11T20:24:56Z","receivedAt":"2023-05-11T20:25:34Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, May 11, 2023 at 3:48 PM Calvin Wan <calvinwan@google.com> wrote:\n> As a library that only interacts with other primitives, strbuf should\n> not utilize the comment_line_char global variable within its\n> functions. Therefore, add an additional parameter for functions that use\n> comment_line_char and refactor callers to pass it in instead.\n> strbuf_stripspace() removes the skip_comments boolean and checks if\n> comment_line_char is a non-NULL character to determine whether to skip\n> comments or not.\n>\n> Signed-off-by: Calvin Wan <calvinwan@google.com>\n> ---\n> diff --git a/strbuf.c b/strbuf.c\n> @@ -1051,10 +1052,10 @@ static size_t cleanup(char *line, size_t len)\n> - * Enable skip_comments to skip every line starting with comment\n> - * character.\n> + * Pass a non-NULL comment_line_char to skip every line starting\n> + * with it\n\nWhen speaking of a character, we normally spell this NUL rather than\nNULL (which is how we spell a null pointer).\n\nThe end-of-sentence period got lost in the rewrite.\n\nProbably not worth a reroll on its own.\n\n> @@ -1067,7 +1068,8 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n> -               if (skip_comments && len && sb->buf[i] == comment_line_char) {\n> +               if (comment_line_char != '\\0' && len &&\n> +                   sb->buf[i] == comment_line_char) {\n\nIn this code-base, it is more common to say:\n\n    if (comment_line_char && len && ...\n\nrather than:\n\n    if (comment_line_char != '\\0' && len && ...\n\nProbably not worth a reroll.\n\n> diff --git a/strbuf.h b/strbuf.h\n> @@ -544,10 +545,12 @@ int strbuf_getcwd(struct strbuf *sb);\n>  /**\n> - * Strip whitespace from a buffer. The second parameter controls if\n> - * comments are considered contents to be removed or not.\n> + * Strip whitespace from a buffer. The second parameter is the comment\n> + * character that determines whether a line is a comment or not. If the\n> + * second parameter is a non-NULL character, comments are considered\n> + * contents to be removed.\n>   */\n> -void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n> +void strbuf_stripspace(struct strbuf *buf, char comment_line_char);\n\nDitto regarding NUL vs. NULL.\n\nRather than saying \"the second parameter\", readers would have an\neasier time if you just spelled it out directly (i.e.\n\"comment_line_char\").\n\nThe phrase \"comments are considered contents to be removed\" made sense\nbefore the rewrite, but sounds a bit awkward after the rewrite.\nPerhaps rewrite it something like this:\n\n    Strip whitespace from a buffer. If comment_line_char is non-NUL,\n    then lines beginning with that character are considered comments,\n    thus removed.\n\nMay not be worth a reroll.\n"},{"id":"477098","messageId":"xmqqr0rmtuid.fsf@gitster.g","threadId":"59685","inReplyTo":"20230511194822.1493798-7-calvinwan@google.com","subject":"Re: [PATCH v5 7/7] strbuf: remove global variable","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-11T21:42:34Z","receivedAt":"2023-05-11T21:42:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> strbuf_stripspace() removes the skip_comments boolean and checks if\n> comment_line_char is a non-NULL character to determine whether to skip\n> comments or not.\n\nHmph, that is certainly cute.  Taking it as granted that NUL can\nnever serve any useful purpose in a text file (where stripspace\nmakes any sense), passing NUL as the comment_line_char can certainly\nbe used as a sign that no stripping is desired.\n\nAnd those existing callers that do not want comment stripping are\nalready passing 0 at the position because the original parameter is\nan integer (used as a Boolean); they now ought to be passing '\\0'\ninstead, but passing 0 is acceptable.\n\nIt is not trivial to catch existing callers that pass 1 to mean\n\"please strip\" as they are not supposed to pass comment_line_char\n(usually \"#\", but there is a global variable for that visible to\nthem).  If left unconverted, they end up asking that lines that\nbegin with SOH ('\\001') to be considered comments and get stripped.\nIn order to catch such a mistake, however, you cannot say \"ah, the\nskip_comments parameter is '1'; is that because the end user really\nwanted SOH as the comment leader?  Let's warn if the value of the\ncomment_line_char global is not 1\" for obvious reasons X-<.\n\nSo this step, while it makes sense in a vacuum, is a cute idea, and\nis nicer in the longer term (because we certainly do not want to\nhave to pass an extra parameter to the function), raises the risk of\nsemantic mismerge higher for topics in flight that do want to use\nstripspace to remove lines that are commented out.  My quick \"git\nlog -S\" seems to tell me there is no such topic I happened to have\npicked up in 'seen' right now, though, so it may be OK.\n\nThanks.\n\n\n"},{"id":"477179","messageId":"c9e22e51-4e4a-b692-edfd-1f3bc7ee7da9@gmail.com","threadId":"59685","inReplyTo":"20230511194822.1493798-7-calvinwan@google.com","subject":"Re: [PATCH v5 7/7] strbuf: remove global variable","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-05-12T14:53:03Z","receivedAt":"2023-05-12T14:53:13Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Calvin\n\nOn 11/05/2023 20:48, Calvin Wan wrote:\n> As a library that only interacts with other primitives, strbuf should\n> not utilize the comment_line_char global variable within its\n> functions. Therefore, add an additional parameter for functions that use\n> comment_line_char and refactor callers to pass it in instead.\n> strbuf_stripspace() removes the skip_comments boolean and checks if\n> comment_line_char is a non-NULL character to determine whether to skip\n> comments or not.\n\nThanks for re-rolling, I agree with Eric's comments but would be happy \nif this was merged as-is.\n\nBest Wishes\n\nPhillip\n\n> Signed-off-by: Calvin Wan <calvinwan@google.com>\n> ---\n>   add-patch.c          | 12 +++++++-----\n>   builtin/am.c         |  2 +-\n>   builtin/branch.c     |  4 ++--\n>   builtin/commit.c     |  2 +-\n>   builtin/merge.c      | 10 ++++++----\n>   builtin/notes.c      | 16 +++++++++-------\n>   builtin/rebase.c     |  2 +-\n>   builtin/stripspace.c |  6 ++++--\n>   builtin/tag.c        |  9 ++++++---\n>   fmt-merge-msg.c      |  9 ++++++---\n>   gpg-interface.c      |  5 +++--\n>   rebase-interactive.c | 15 ++++++++-------\n>   sequencer.c          | 24 +++++++++++++++---------\n>   strbuf.c             | 18 ++++++++++--------\n>   strbuf.h             | 15 +++++++++------\n>   wt-status.c          |  6 +++---\n>   16 files changed, 91 insertions(+), 64 deletions(-)\n> \n> diff --git a/add-patch.c b/add-patch.c\n> index 8d770d203f..9702c1aabd 100644\n> --- a/add-patch.c\n> +++ b/add-patch.c\n> @@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n>   \tsize_t i;\n>   \n>   \tstrbuf_reset(&s->buf);\n> -\tstrbuf_commented_addf(&s->buf, _(\"Manual hunk edit mode -- see bottom for \"\n> -\t\t\t\t      \"a quick guide.\\n\"));\n> +\tstrbuf_commented_addf(&s->buf, comment_line_char,\n> +\t\t\t      _(\"Manual hunk edit mode -- see bottom for \"\n> +\t\t\t\t\"a quick guide.\\n\"));\n>   \trender_hunk(s, hunk, 0, 0, &s->buf);\n> -\tstrbuf_commented_addf(&s->buf,\n> +\tstrbuf_commented_addf(&s->buf, comment_line_char,\n>   \t\t\t      _(\"---\\n\"\n>   \t\t\t\t\"To remove '%c' lines, make them ' ' lines \"\n>   \t\t\t\t\"(context).\\n\"\n> @@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n>   \t\t\t      s->mode->is_reverse ? '+' : '-',\n>   \t\t\t      s->mode->is_reverse ? '-' : '+',\n>   \t\t\t      comment_line_char);\n> -\tstrbuf_commented_addf(&s->buf, \"%s\", _(s->mode->edit_hunk_hint));\n> +\tstrbuf_commented_addf(&s->buf, comment_line_char, \"%s\",\n> +\t\t\t      _(s->mode->edit_hunk_hint));\n>   \t/*\n>   \t * TRANSLATORS: 'it' refers to the patch mentioned in the previous\n>   \t * messages.\n>   \t */\n> -\tstrbuf_commented_addf(&s->buf,\n> +\tstrbuf_commented_addf(&s->buf, comment_line_char,\n>   \t\t\t      _(\"If it does not apply cleanly, you will be \"\n>   \t\t\t\t\"given an opportunity to\\n\"\n>   \t\t\t\t\"edit again.  If all lines of the hunk are \"\n> diff --git a/builtin/am.c b/builtin/am.c\n> index 5c83f2e003..9ece2e3066 100644\n> --- a/builtin/am.c\n> +++ b/builtin/am.c\n> @@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n>   \n>   \tstrbuf_addstr(&msg, \"\\n\\n\");\n>   \tstrbuf_addbuf(&msg, &mi.log_message);\n> -\tstrbuf_stripspace(&msg, 0);\n> +\tstrbuf_stripspace(&msg, '\\0');\n>   \n>   \tassert(!state->author_name);\n>   \tstate->author_name = strbuf_detach(&author_name, NULL);\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index 501c47657c..4560610d09 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> @@ -629,7 +629,7 @@ static int edit_branch_description(const char *branch_name)\n>   \texists = !read_branch_desc(&buf, branch_name);\n>   \tif (!buf.len || buf.buf[buf.len-1] != '\\n')\n>   \t\tstrbuf_addch(&buf, '\\n');\n> -\tstrbuf_commented_addf(&buf,\n> +\tstrbuf_commented_addf(&buf, comment_line_char,\n>   \t\t    _(\"Please edit the description for the branch\\n\"\n>   \t\t      \"  %s\\n\"\n>   \t\t      \"Lines starting with '%c' will be stripped.\\n\"),\n> @@ -640,7 +640,7 @@ static int edit_branch_description(const char *branch_name)\n>   \t\tstrbuf_release(&buf);\n>   \t\treturn -1;\n>   \t}\n> -\tstrbuf_stripspace(&buf, 1);\n> +\tstrbuf_stripspace(&buf, comment_line_char);\n>   \n>   \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n>   \tif (buf.len || exists)\n> diff --git a/builtin/commit.c b/builtin/commit.c\n> index e67c4be221..e002ebf070 100644\n> --- a/builtin/commit.c\n> +++ b/builtin/commit.c\n> @@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n>   \ts->hints = 0;\n>   \n>   \tif (clean_message_contents)\n> -\t\tstrbuf_stripspace(&sb, 0);\n> +\t\tstrbuf_stripspace(&sb, '\\0');\n>   \n>   \tif (signoff)\n>   \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\n> diff --git a/builtin/merge.c b/builtin/merge.c\n> index 8da3e46abb..1d14767c0c 100644\n> --- a/builtin/merge.c\n> +++ b/builtin/merge.c\n> @@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)\n>   \t\tstrbuf_addch(&msg, '\\n');\n>   \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {\n>   \t\t\twt_status_append_cut_line(&msg);\n> -\t\t\tstrbuf_commented_addf(&msg, \"\\n\");\n> +\t\t\tstrbuf_commented_addf(&msg, comment_line_char, \"\\n\");\n>   \t\t}\n> -\t\tstrbuf_commented_addf(&msg, _(merge_editor_comment));\n> +\t\tstrbuf_commented_addf(&msg, comment_line_char,\n> +\t\t\t\t      _(merge_editor_comment));\n>   \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n> -\t\t\tstrbuf_commented_addf(&msg, _(scissors_editor_comment));\n> +\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n> +\t\t\t\t\t      _(scissors_editor_comment));\n>   \t\telse\n> -\t\t\tstrbuf_commented_addf(&msg,\n> +\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n>   \t\t\t\t_(no_scissors_editor_comment), comment_line_char);\n>   \t}\n>   \tif (signoff)\n> diff --git a/builtin/notes.c b/builtin/notes.c\n> index d5788352b6..3bad5b458b 100644\n> --- a/builtin/notes.c\n> +++ b/builtin/notes.c\n> @@ -11,6 +11,7 @@\n>   #include \"config.h\"\n>   #include \"builtin.h\"\n>   #include \"editor.h\"\n> +#include \"environment.h\"\n>   #include \"gettext.h\"\n>   #include \"hex.h\"\n>   #include \"notes.h\"\n> @@ -157,7 +158,7 @@ static void write_commented_object(int fd, const struct object_id *object)\n>   \n>   \tif (strbuf_read(&buf, show.out, 0) < 0)\n>   \t\tdie_errno(_(\"could not read 'show' output\"));\n> -\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len);\n> +\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);\n>   \twrite_or_die(fd, cbuf.buf, cbuf.len);\n>   \n>   \tstrbuf_release(&cbuf);\n> @@ -185,9 +186,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n>   \t\t\tcopy_obj_to_fd(fd, old_note);\n>   \n>   \t\tstrbuf_addch(&buf, '\\n');\n> -\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n> -\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));\n> -\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n> +\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n> +\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),\n> +\t\t\t\t\t   comment_line_char);\n> +\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n>   \t\twrite_or_die(fd, buf.buf, buf.len);\n>   \n>   \t\twrite_commented_object(fd, object);\n> @@ -199,7 +201,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n>   \t\tif (launch_editor(d->edit_path, &d->buf, NULL)) {\n>   \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n>   \t\t}\n> -\t\tstrbuf_stripspace(&d->buf, 1);\n> +\t\tstrbuf_stripspace(&d->buf, comment_line_char);\n>   \t}\n>   }\n>   \n> @@ -225,7 +227,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n>   \tif (d->buf.len)\n>   \t\tstrbuf_addch(&d->buf, '\\n');\n>   \tstrbuf_addstr(&d->buf, arg);\n> -\tstrbuf_stripspace(&d->buf, 0);\n> +\tstrbuf_stripspace(&d->buf, '\\0');\n>   \n>   \td->given = 1;\n>   \treturn 0;\n> @@ -244,7 +246,7 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n>   \t\t\tdie_errno(_(\"cannot read '%s'\"), arg);\n>   \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n>   \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n> -\tstrbuf_stripspace(&d->buf, 0);\n> +\tstrbuf_stripspace(&d->buf, '\\0');\n>   \n>   \td->given = 1;\n>   \treturn 0;\n> diff --git a/builtin/rebase.c b/builtin/rebase.c\n> index ace1d5e8d1..b1ba9fb05d 100644\n> --- a/builtin/rebase.c\n> +++ b/builtin/rebase.c\n> @@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)\n>   \tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n>   \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n>   \n> -\tstrbuf_stripspace(&todo_list.buf, 1);\n> +\tstrbuf_stripspace(&todo_list.buf, comment_line_char);\n>   \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n>   \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n>   \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\n> diff --git a/builtin/stripspace.c b/builtin/stripspace.c\n> index 9451eb69ff..1987752359 100644\n> --- a/builtin/stripspace.c\n> +++ b/builtin/stripspace.c\n> @@ -1,6 +1,7 @@\n>   #include \"builtin.h\"\n>   #include \"cache.h\"\n>   #include \"config.h\"\n> +#include \"environment.h\"\n>   #include \"gettext.h\"\n>   #include \"parse-options.h\"\n>   #include \"setup.h\"\n> @@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)\n>   \tsize_t len;\n>   \n>   \tmsg = strbuf_detach(buf, &len);\n> -\tstrbuf_add_commented_lines(buf, msg, len);\n> +\tstrbuf_add_commented_lines(buf, msg, len, comment_line_char);\n>   \tfree(msg);\n>   }\n>   \n> @@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)\n>   \t\tdie_errno(\"could not read the input\");\n>   \n>   \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n> -\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n> +\t\tstrbuf_stripspace(&buf,\n> +\t\t\t  mode == STRIP_COMMENTS ? comment_line_char : '\\0');\n>   \telse\n>   \t\tcomment_lines(&buf);\n>   \n> diff --git a/builtin/tag.c b/builtin/tag.c\n> index 1850a6a6fd..b79e0a88e6 100644\n> --- a/builtin/tag.c\n> +++ b/builtin/tag.c\n> @@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n>   \t\t\tstruct strbuf buf = STRBUF_INIT;\n>   \t\t\tstrbuf_addch(&buf, '\\n');\n>   \t\t\tif (opt->cleanup_mode == CLEANUP_ALL)\n> -\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n> +\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n> +\t\t\t\t      _(tag_template), tag, comment_line_char);\n>   \t\t\telse\n> -\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);\n> +\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n> +\t\t\t\t      _(tag_template_nocleanup), tag, comment_line_char);\n>   \t\t\twrite_or_die(fd, buf.buf, buf.len);\n>   \t\t\tstrbuf_release(&buf);\n>   \t\t}\n> @@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n>   \t}\n>   \n>   \tif (opt->cleanup_mode != CLEANUP_NONE)\n> -\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n> +\t\tstrbuf_stripspace(buf,\n> +\t\t  opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\\0');\n>   \n>   \tif (!opt->message_given && !buf->len)\n>   \t\tdie(_(\"no tag message?\"));\n> diff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\n> index 5af0d4715b..5d15e2387d 100644\n> --- a/fmt-merge-msg.c\n> +++ b/fmt-merge-msg.c\n> @@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,\n>   \tstrbuf_complete_line(tagbuf);\n>   \tif (sig->len) {\n>   \t\tstrbuf_addch(tagbuf, '\\n');\n> -\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len);\n> +\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len,\n> +\t\t\t\t\t   comment_line_char);\n>   \t}\n>   }\n>   \n> @@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n>   \t\t\t\tstrbuf_addch(&tagline, '\\n');\n>   \t\t\t\tstrbuf_add_commented_lines(&tagline,\n>   \t\t\t\t\t\torigins.items[first_tag].string,\n> -\t\t\t\t\t\tstrlen(origins.items[first_tag].string));\n> +\t\t\t\t\t\tstrlen(origins.items[first_tag].string),\n> +\t\t\t\t\t\tcomment_line_char);\n>   \t\t\t\tstrbuf_insert(&tagbuf, 0, tagline.buf,\n>   \t\t\t\t\t      tagline.len);\n>   \t\t\t\tstrbuf_release(&tagline);\n> @@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n>   \t\t\tstrbuf_addch(&tagbuf, '\\n');\n>   \t\t\tstrbuf_add_commented_lines(&tagbuf,\n>   \t\t\t\t\torigins.items[i].string,\n> -\t\t\t\t\tstrlen(origins.items[i].string));\n> +\t\t\t\t\tstrlen(origins.items[i].string),\n> +\t\t\t\t\tcomment_line_char);\n>   \t\t\tfmt_tag_signature(&tagbuf, &sig, buf, len);\n>   \t\t}\n>   \t\tstrbuf_release(&payload);\n> diff --git a/gpg-interface.c b/gpg-interface.c\n> index f3ac5acdd9..c27a751b70 100644\n> --- a/gpg-interface.c\n> +++ b/gpg-interface.c\n> @@ -11,6 +11,7 @@\n>   #include \"tempfile.h\"\n>   #include \"alias.h\"\n>   #include \"wrapper.h\"\n> +#include \"environment.h\"\n>   \n>   static int git_gpg_config(const char *, const char *, void *);\n>   \n> @@ -584,8 +585,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,\n>   \t\t}\n>   \t}\n>   \n> -\tstrbuf_stripspace(&ssh_keygen_out, 0);\n> -\tstrbuf_stripspace(&ssh_keygen_err, 0);\n> +\tstrbuf_stripspace(&ssh_keygen_out, '\\0');\n> +\tstrbuf_stripspace(&ssh_keygen_err, '\\0');\n>   \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n>   \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n>   \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\n> diff --git a/rebase-interactive.c b/rebase-interactive.c\n> index 789f407361..012defbb53 100644\n> --- a/rebase-interactive.c\n> +++ b/rebase-interactive.c\n> @@ -71,13 +71,14 @@ void append_todo_help(int command_count,\n>   \n>   \tif (!edit_todo) {\n>   \t\tstrbuf_addch(buf, '\\n');\n> -\t\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n> -\t\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n> -\t\t\t\t\t      command_count),\n> +\t\tstrbuf_commented_addf(buf, comment_line_char,\n> +\t\t\t\t      Q_(\"Rebase %s onto %s (%d command)\",\n> +\t\t\t\t\t \"Rebase %s onto %s (%d commands)\",\n> +\t\t\t\t\t command_count),\n>   \t\t\t\t      shortrevisions, shortonto, command_count);\n>   \t}\n>   \n> -\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n> +\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n>   \n>   \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n>   \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n> @@ -86,7 +87,7 @@ void append_todo_help(int command_count,\n>   \t\tmsg = _(\"\\nIf you remove a line here \"\n>   \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n>   \n> -\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n> +\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n>   \n>   \tif (edit_todo)\n>   \t\tmsg = _(\"\\nYou are editing the todo file \"\n> @@ -97,7 +98,7 @@ void append_todo_help(int command_count,\n>   \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n>   \t\t\t\"the rebase will be aborted.\\n\\n\");\n>   \n> -\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n> +\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n>   }\n>   \n>   int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n> @@ -129,7 +130,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n>   \tif (launch_sequence_editor(todo_file, &new_todo->buf, NULL))\n>   \t\treturn -2;\n>   \n> -\tstrbuf_stripspace(&new_todo->buf, 1);\n> +\tstrbuf_stripspace(&new_todo->buf, comment_line_char);\n>   \tif (initial && new_todo->buf.len == 0)\n>   \t\treturn -3;\n>   \n> diff --git a/sequencer.c b/sequencer.c\n> index c88d1d9553..eae4563ef7 100644\n> --- a/sequencer.c\n> +++ b/sequencer.c\n> @@ -659,11 +659,12 @@ void append_conflicts_hint(struct index_state *istate,\n>   \t}\n>   \n>   \tstrbuf_addch(msgbuf, '\\n');\n> -\tstrbuf_commented_addf(msgbuf, \"Conflicts:\\n\");\n> +\tstrbuf_commented_addf(msgbuf, comment_line_char, \"Conflicts:\\n\");\n>   \tfor (i = 0; i < istate->cache_nr;) {\n>   \t\tconst struct cache_entry *ce = istate->cache[i++];\n>   \t\tif (ce_stage(ce)) {\n> -\t\t\tstrbuf_commented_addf(msgbuf, \"\\t%s\\n\", ce->name);\n> +\t\t\tstrbuf_commented_addf(msgbuf, comment_line_char,\n> +\t\t\t\t\t      \"\\t%s\\n\", ce->name);\n>   \t\t\twhile (i < istate->cache_nr &&\n>   \t\t\t       !strcmp(ce->name, istate->cache[i]->name))\n>   \t\t\t\ti++;\n> @@ -1142,7 +1143,8 @@ void cleanup_message(struct strbuf *msgbuf,\n>   \t    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n>   \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n>   \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n> -\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n> +\t\tstrbuf_stripspace(msgbuf,\n> +\t\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n>   }\n>   \n>   /*\n> @@ -1173,7 +1175,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,\n>   \tif (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)\n>   \t\treturn 0;\n>   \n> -\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n> +\tstrbuf_stripspace(&tmpl,\n> +\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n>   \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n>   \t\tstart = sb->buf;\n>   \tstrbuf_release(&tmpl);\n> @@ -1545,7 +1548,8 @@ static int try_to_commit(struct repository *r,\n>   \t\tcleanup = opts->default_msg_cleanup;\n>   \n>   \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n> -\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n> +\t\tstrbuf_stripspace(msg,\n> +\t\t  cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n>   \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n>   \t\tres = 1; /* run 'git commit' to display error message */\n>   \t\tgoto out;\n> @@ -1839,7 +1843,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n>   \t\ts += count;\n>   \t\tlen -= count;\n>   \t}\n> -\tstrbuf_add_commented_lines(buf, s, len);\n> +\tstrbuf_add_commented_lines(buf, s, len, comment_line_char);\n>   }\n>   \n>   /* Does the current fixup chain contain a squash command? */\n> @@ -1938,7 +1942,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,\n>   \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n>   \t\t    ++opts->current_fixup_count + 1);\n>   \tstrbuf_addstr(buf, \"\\n\\n\");\n> -\tstrbuf_add_commented_lines(buf, body, commented_len);\n> +\tstrbuf_add_commented_lines(buf, body, commented_len, comment_line_char);\n>   \t/* buf->buf may be reallocated so store an offset into the buffer */\n>   \tfixup_off = buf->len;\n>   \tstrbuf_addstr(buf, body + commented_len);\n> @@ -2028,7 +2032,8 @@ static int update_squash_messages(struct repository *r,\n>   \t\t\t      _(first_commit_msg_str));\n>   \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n>   \t\tif (is_fixup_flag(command, flag))\n> -\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n> +\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n> +\t\t\t\t\t\t   comment_line_char);\n>   \t\telse\n>   \t\t\tstrbuf_addstr(&buf, body);\n>   \n> @@ -2047,7 +2052,8 @@ static int update_squash_messages(struct repository *r,\n>   \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n>   \t\t\t    ++opts->current_fixup_count + 1);\n>   \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n> -\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n> +\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n> +\t\t\t\t\t   comment_line_char);\n>   \t} else\n>   \t\treturn error(_(\"unknown command: %d\"), command);\n>   \trepo_unuse_commit_buffer(r, commit, message);\n> diff --git a/strbuf.c b/strbuf.c\n> index d5978fee4e..9348ac6863 100644\n> --- a/strbuf.c\n> +++ b/strbuf.c\n> @@ -1,6 +1,5 @@\n>   #include \"git-compat-util.h\"\n>   #include \"alloc.h\"\n> -#include \"environment.h\"\n>   #include \"gettext.h\"\n>   #include \"hex.h\"\n>   #include \"strbuf.h\"\n> @@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n>   \tstrbuf_complete_line(out);\n>   }\n>   \n> -void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n> +void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n> +\t\t\t\tsize_t size, char comment_line_char)\n>   {\n>   \tstatic char prefix1[3];\n>   \tstatic char prefix2[2];\n> @@ -374,7 +374,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size\n>   \tadd_lines(out, prefix1, prefix2, buf, size);\n>   }\n>   \n> -void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n> +void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,\n> +\t\t\t   const char *fmt, ...)\n>   {\n>   \tva_list params;\n>   \tstruct strbuf buf = STRBUF_INIT;\n> @@ -384,7 +385,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n>   \tstrbuf_vaddf(&buf, fmt, params);\n>   \tva_end(params);\n>   \n> -\tstrbuf_add_commented_lines(sb, buf.buf, buf.len);\n> +\tstrbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);\n>   \tif (incomplete_line)\n>   \t\tsb->buf[--sb->len] = '\\0';\n>   \n> @@ -1051,10 +1052,10 @@ static size_t cleanup(char *line, size_t len)\n>    *\n>    * If last line does not have a newline at the end, one is added.\n>    *\n> - * Enable skip_comments to skip every line starting with comment\n> - * character.\n> + * Pass a non-NULL comment_line_char to skip every line starting\n> + * with it\n>    */\n> -void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n> +void strbuf_stripspace(struct strbuf *sb, char comment_line_char)\n>   {\n>   \tsize_t empties = 0;\n>   \tsize_t i, j, len, newlen;\n> @@ -1067,7 +1068,8 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n>   \t\teol = memchr(sb->buf + i, '\\n', sb->len - i);\n>   \t\tlen = eol ? eol - (sb->buf + i) + 1 : sb->len - i;\n>   \n> -\t\tif (skip_comments && len && sb->buf[i] == comment_line_char) {\n> +\t\tif (comment_line_char != '\\0' && len &&\n> +\t\t    sb->buf[i] == comment_line_char) {\n>   \t\t\tnewlen = 0;\n>   \t\t\tcontinue;\n>   \t\t}\n> diff --git a/strbuf.h b/strbuf.h\n> index b38bfd34af..89ae30b620 100644\n> --- a/strbuf.h\n> +++ b/strbuf.h\n> @@ -292,7 +292,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n>    * by a comment character and a blank.\n>    */\n>   void strbuf_add_commented_lines(struct strbuf *out,\n> -\t\t\t\tconst char *buf, size_t size);\n> +\t\t\t\tconst char *buf, size_t size,\n> +\t\t\t\tchar comment_line_char);\n>   \n>   \n>   /**\n> @@ -421,8 +422,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n>    * Add a formatted string prepended by a comment character and a\n>    * blank to the buffer.\n>    */\n> -__attribute__((format (printf, 2, 3)))\n> -void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n> +__attribute__((format (printf, 3, 4)))\n> +void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n>   \n>   __attribute__((format (printf,2,0)))\n>   void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n> @@ -544,10 +545,12 @@ int strbuf_getcwd(struct strbuf *sb);\n>   int strbuf_normalize_path(struct strbuf *sb);\n>   \n>   /**\n> - * Strip whitespace from a buffer. The second parameter controls if\n> - * comments are considered contents to be removed or not.\n> + * Strip whitespace from a buffer. The second parameter is the comment\n> + * character that determines whether a line is a comment or not. If the\n> + * second parameter is a non-NULL character, comments are considered\n> + * contents to be removed.\n>    */\n> -void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n> +void strbuf_stripspace(struct strbuf *buf, char comment_line_char);\n>   \n>   static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n>   {\n> diff --git a/wt-status.c b/wt-status.c\n> index 97b9c1c035..da7734866f 100644\n> --- a/wt-status.c\n> +++ b/wt-status.c\n> @@ -1023,7 +1023,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom\n>   \tif (s->display_comment_prefix) {\n>   \t\tsize_t len;\n>   \t\tsummary_content = strbuf_detach(&summary, &len);\n> -\t\tstrbuf_add_commented_lines(&summary, summary_content, len);\n> +\t\tstrbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);\n>   \t\tfree(summary_content);\n>   \t}\n>   \n> @@ -1098,8 +1098,8 @@ void wt_status_append_cut_line(struct strbuf *buf)\n>   {\n>   \tconst char *explanation = _(\"Do not modify or remove the line above.\\nEverything below it will be ignored.\");\n>   \n> -\tstrbuf_commented_addf(buf, \"%s\", cut_line);\n> -\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation));\n> +\tstrbuf_commented_addf(buf, comment_line_char, \"%s\", cut_line);\n> +\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);\n>   }\n>   \n>   void wt_status_add_cut_line(FILE *fp)\n"},{"id":"477180","messageId":"215b700d-6175-3527-857d-4347bb4efb95@gmail.com","threadId":"59685","inReplyTo":"xmqqr0rmtuid.fsf@gitster.g","subject":"Re: [PATCH v5 7/7] strbuf: remove global variable","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2023-05-12T14:54:46Z","receivedAt":"2023-05-12T14:55:30Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 11/05/2023 22:42, Junio C Hamano wrote:\n> Calvin Wan <calvinwan@google.com> writes:\n>\n> So this step, while it makes sense in a vacuum, is a cute idea, and\n> is nicer in the longer term (because we certainly do not want to\n> have to pass an extra parameter to the function), raises the risk of\n> semantic mismerge higher for topics in flight that do want to use\n> stripspace to remove lines that are commented out.  My quick \"git\n> log -S\" seems to tell me there is no such topic I happened to have\n> picked up in 'seen' right now, though, so it may be OK.\n\nI just grepped seen for strbuf_stripspace() and it looks like all the \ncallers are converted correctly.\n\nBest Wishes\n\nPhillip\n"},{"id":"477188","messageId":"20230512171429.2202982-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230511194446.1492907-1-calvinwan@google.com","subject":"[PATCH v6 0/7] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-12T17:14:29Z","receivedAt":"2023-05-12T17:14:36Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Reroll with last couple of nits fixed. Thanks again to everyone for\nreviewing this series!\n\nCalvin Wan (7):\n  strbuf: clarify API boundary\n  abspath: move related functions to abspath\n  credential-store: move related functions to credential-store file\n  object-name: move related functions to object-name\n  path: move related function to path\n  strbuf: clarify dependency\n  strbuf: remove global variable\n\n abspath.c                  |  36 ++++++++++++\n abspath.h                  |  21 +++++++\n add-patch.c                |  12 ++--\n builtin/am.c               |   2 +-\n builtin/branch.c           |   4 +-\n builtin/commit.c           |   2 +-\n builtin/credential-store.c |  19 +++++++\n builtin/merge.c            |  10 ++--\n builtin/notes.c            |  16 +++---\n builtin/rebase.c           |   2 +-\n builtin/stripspace.c       |   6 +-\n builtin/tag.c              |   9 ++-\n fmt-merge-msg.c            |   9 ++-\n gpg-interface.c            |   5 +-\n hook.c                     |   1 +\n object-name.c              |  15 +++++\n object-name.h              |   9 +++\n path.c                     |  20 +++++++\n path.h                     |   5 ++\n pretty.c                   |   1 +\n rebase-interactive.c       |  15 ++---\n sequencer.c                |  24 +++++---\n strbuf.c                   | 112 ++++---------------------------------\n strbuf.h                   |  57 ++++++-------------\n tempfile.c                 |   1 +\n wt-status.c                |   6 +-\n 26 files changed, 227 insertions(+), 192 deletions(-)\n\nRange-diff against v5:\n1:  287e787c9c ! 1:  5ae531a1e2 strbuf: clarify API boundary\n    @@ strbuf.h\n     +/*\n     + * NOTE FOR STRBUF DEVELOPERS\n     + *\n    -+ * The objects that this API interacts with should be limited to other\n    -+ * primitives, however, there are older functions in here that interact\n    -+ * with non-primitive objects which should eventually be moved out or\n    -+ * refactored.\n    ++ * strbuf is a low-level primitive; as such it should interact only\n    ++ * with other low-level primitives. Do not introduce new functions\n    ++ * which interact with higher-level APIs.\n     + */\n     +\n      struct string_list;\n2:  5bd27cad7a = 2:  3bb2b9c01a abspath: move related functions to abspath\n3:  08e3e40de6 = 3:  ff91ca2fda credential-store: move related functions to credential-store file\n4:  1a21d4fdd1 = 4:  10e61eb570 object-name: move related functions to object-name\n5:  03b20f3384 = 5:  c3d5db4e11 path: move related function to path\n6:  b55f4a39e1 = 6:  113d156195 strbuf: clarify dependency\n7:  6ea36d7730 ! 7:  01c923160d strbuf: remove global variable\n    @@ Commit message\n         functions. Therefore, add an additional parameter for functions that use\n         comment_line_char and refactor callers to pass it in instead.\n         strbuf_stripspace() removes the skip_comments boolean and checks if\n    -    comment_line_char is a non-NULL character to determine whether to skip\n    +    comment_line_char is a non-NUL character to determine whether to skip\n         comments or not.\n     \n      ## add-patch.c ##\n    @@ strbuf.c: static size_t cleanup(char *line, size_t len)\n       *\n     - * Enable skip_comments to skip every line starting with comment\n     - * character.\n    -+ * Pass a non-NULL comment_line_char to skip every line starting\n    -+ * with it\n    ++ * Pass a non-NUL comment_line_char to skip every line starting\n    ++ * with it.\n       */\n     -void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n     +void strbuf_stripspace(struct strbuf *sb, char comment_line_char)\n    @@ strbuf.c: void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n      \t\tlen = eol ? eol - (sb->buf + i) + 1 : sb->len - i;\n      \n     -\t\tif (skip_comments && len && sb->buf[i] == comment_line_char) {\n    -+\t\tif (comment_line_char != '\\0' && len &&\n    ++\t\tif (comment_line_char && len &&\n     +\t\t    sb->buf[i] == comment_line_char) {\n      \t\t\tnewlen = 0;\n      \t\t\tcontinue;\n    @@ strbuf.h: int strbuf_getcwd(struct strbuf *sb);\n      /**\n     - * Strip whitespace from a buffer. The second parameter controls if\n     - * comments are considered contents to be removed or not.\n    -+ * Strip whitespace from a buffer. The second parameter is the comment\n    -+ * character that determines whether a line is a comment or not. If the\n    -+ * second parameter is a non-NULL character, comments are considered\n    -+ * contents to be removed.\n    ++ * Strip whitespace from a buffer. If comment_line_char is non-NUL,\n    ++ * then lines beginning with that character are considered comments,\n    ++ * thus removed.\n       */\n     -void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n     +void strbuf_stripspace(struct strbuf *buf, char comment_line_char);\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477189","messageId":"20230512171516.2203472-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"[PATCH v6 1/7] strbuf: clarify API boundary","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-12T17:15:10Z","receivedAt":"2023-05-12T17:15:29Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"strbuf, as a generic and widely used structure across the codebase,\nshould be limited as a library to only interact with primitives. Add\ndocumentation so future functions can appropriately be placed. Older\nfunctions that do not follow this boundary should eventually be moved or\nrefactored.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.h | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/strbuf.h b/strbuf.h\nindex 3dfeadb44c..70778c6e10 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -1,6 +1,14 @@\n #ifndef STRBUF_H\n #define STRBUF_H\n \n+/*\n+ * NOTE FOR STRBUF DEVELOPERS\n+ *\n+ * strbuf is a low-level primitive; as such it should interact only\n+ * with other low-level primitives. Do not introduce new functions\n+ * which interact with higher-level APIs.\n+ */\n+\n struct string_list;\n \n /**\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477190","messageId":"20230512171516.2203472-2-calvinwan@google.com","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"[PATCH v6 2/7] abspath: move related functions to abspath","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-12T17:15:11Z","receivedAt":"2023-05-12T17:15:36Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move abspath-related functions from strbuf.[ch] to abspath.[ch] so that\nstrbuf is focused on string manipulation routines with minimal\ndependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n abspath.c  | 36 ++++++++++++++++++++++++++++++++++++\n abspath.h  | 21 +++++++++++++++++++++\n hook.c     |  1 +\n strbuf.c   | 37 -------------------------------------\n strbuf.h   | 22 ----------------------\n tempfile.c |  1 +\n 6 files changed, 59 insertions(+), 59 deletions(-)\n\ndiff --git a/abspath.c b/abspath.c\nindex d032f5dce5..1202cde23d 100644\n--- a/abspath.c\n+++ b/abspath.c\n@@ -289,3 +289,39 @@ char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n \t\treturn xstrdup(arg);\n \treturn prefix_filename(pfx, arg);\n }\n+\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n+{\n+\tif (!*path)\n+\t\tdie(\"The empty string is not a valid path\");\n+\tif (!is_absolute_path(path)) {\n+\t\tstruct stat cwd_stat, pwd_stat;\n+\t\tsize_t orig_len = sb->len;\n+\t\tchar *cwd = xgetcwd();\n+\t\tchar *pwd = getenv(\"PWD\");\n+\t\tif (pwd && strcmp(pwd, cwd) &&\n+\t\t    !stat(cwd, &cwd_stat) &&\n+\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n+\t\t    !stat(pwd, &pwd_stat) &&\n+\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n+\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n+\t\t\tstrbuf_addstr(sb, pwd);\n+\t\telse\n+\t\t\tstrbuf_addstr(sb, cwd);\n+\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n+\t\t\tstrbuf_addch(sb, '/');\n+\t\tfree(cwd);\n+\t}\n+\tstrbuf_addstr(sb, path);\n+}\n+\n+void strbuf_add_real_path(struct strbuf *sb, const char *path)\n+{\n+\tif (sb->len) {\n+\t\tstruct strbuf resolved = STRBUF_INIT;\n+\t\tstrbuf_realpath(&resolved, path, 1);\n+\t\tstrbuf_addbuf(sb, &resolved);\n+\t\tstrbuf_release(&resolved);\n+\t} else\n+\t\tstrbuf_realpath(sb, path, 1);\n+}\ndiff --git a/abspath.h b/abspath.h\nindex 7cd3de5e9d..4653080d5e 100644\n--- a/abspath.h\n+++ b/abspath.h\n@@ -30,4 +30,25 @@ static inline int is_absolute_path(const char *path)\n \treturn is_dir_sep(path[0]) || has_dos_drive_prefix(path);\n }\n \n+/**\n+ * Add a path to a buffer, converting a relative path to an\n+ * absolute one in the process.  Symbolic links are not\n+ * resolved.\n+ */\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n+\n+/**\n+ * Canonize `path` (make it absolute, resolve symlinks, remove extra\n+ * slashes) and append it to `sb`.  Die with an informative error\n+ * message if there is a problem.\n+ *\n+ * The directory part of `path` (i.e., everything up to the last\n+ * dir_sep) must denote a valid, existing directory, but the last\n+ * component need not exist.\n+ *\n+ * Callers that don't mind links should use the more lightweight\n+ * strbuf_add_absolute_path() instead.\n+ */\n+void strbuf_add_real_path(struct strbuf *sb, const char *path);\n+\n #endif /* ABSPATH_H */\ndiff --git a/hook.c b/hook.c\nindex 76e322f580..2d8706371e 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -1,4 +1,5 @@\n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hook.h\"\ndiff --git a/strbuf.c b/strbuf.c\nindex 729378ec82..c3b6d48797 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,5 +1,4 @@\n #include \"git-compat-util.h\"\n-#include \"abspath.h\"\n #include \"alloc.h\"\n #include \"environment.h\"\n #include \"gettext.h\"\n@@ -899,42 +898,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)\n \tstrbuf_humanise(buf, bytes, 1);\n }\n \n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n-{\n-\tif (!*path)\n-\t\tdie(\"The empty string is not a valid path\");\n-\tif (!is_absolute_path(path)) {\n-\t\tstruct stat cwd_stat, pwd_stat;\n-\t\tsize_t orig_len = sb->len;\n-\t\tchar *cwd = xgetcwd();\n-\t\tchar *pwd = getenv(\"PWD\");\n-\t\tif (pwd && strcmp(pwd, cwd) &&\n-\t\t    !stat(cwd, &cwd_stat) &&\n-\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n-\t\t    !stat(pwd, &pwd_stat) &&\n-\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n-\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n-\t\t\tstrbuf_addstr(sb, pwd);\n-\t\telse\n-\t\t\tstrbuf_addstr(sb, cwd);\n-\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n-\t\t\tstrbuf_addch(sb, '/');\n-\t\tfree(cwd);\n-\t}\n-\tstrbuf_addstr(sb, path);\n-}\n-\n-void strbuf_add_real_path(struct strbuf *sb, const char *path)\n-{\n-\tif (sb->len) {\n-\t\tstruct strbuf resolved = STRBUF_INIT;\n-\t\tstrbuf_realpath(&resolved, path, 1);\n-\t\tstrbuf_addbuf(sb, &resolved);\n-\t\tstrbuf_release(&resolved);\n-\t} else\n-\t\tstrbuf_realpath(sb, path, 1);\n-}\n-\n int printf_ln(const char *fmt, ...)\n {\n \tint ret;\ndiff --git a/strbuf.h b/strbuf.h\nindex 70778c6e10..207efb4f98 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -535,28 +535,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);\n  */\n int strbuf_getcwd(struct strbuf *sb);\n \n-/**\n- * Add a path to a buffer, converting a relative path to an\n- * absolute one in the process.  Symbolic links are not\n- * resolved.\n- */\n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n-\n-/**\n- * Canonize `path` (make it absolute, resolve symlinks, remove extra\n- * slashes) and append it to `sb`.  Die with an informative error\n- * message if there is a problem.\n- *\n- * The directory part of `path` (i.e., everything up to the last\n- * dir_sep) must denote a valid, existing directory, but the last\n- * component need not exist.\n- *\n- * Callers that don't mind links should use the more lightweight\n- * strbuf_add_absolute_path() instead.\n- */\n-void strbuf_add_real_path(struct strbuf *sb, const char *path);\n-\n-\n /**\n  * Normalize in-place the path contained in the strbuf. See\n  * normalize_path_copy() for details. If an error occurs, the contents of \"sb\"\ndiff --git a/tempfile.c b/tempfile.c\nindex 50c377134c..6c88a63b42 100644\n--- a/tempfile.c\n+++ b/tempfile.c\n@@ -43,6 +43,7 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"path.h\"\n #include \"tempfile.h\"\n #include \"sigchain.h\"\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477191","messageId":"20230512171516.2203472-4-calvinwan@google.com","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"[PATCH v6 4/7] object-name: move related functions to object-name","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-12T17:15:13Z","receivedAt":"2023-05-12T17:15:39Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move object-name-related functions from strbuf.[ch] to object-name.[ch]\nso that strbuf is focused on string manipulation routines with minimal\ndependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n object-name.c | 15 +++++++++++++++\n object-name.h |  9 +++++++++\n pretty.c      |  1 +\n strbuf.c      | 16 ----------------\n strbuf.h      | 10 ----------\n 5 files changed, 25 insertions(+), 26 deletions(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 538e8a8f62..c2e82aceea 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -766,6 +766,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n \t\tfind_abbrev_len_for_pack(p, mad);\n }\n \n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len)\n+{\n+\tint r;\n+\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n+\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n+\tstrbuf_setlen(sb, sb->len + r);\n+}\n+\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len)\n+{\n+\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n+}\n+\n int repo_find_unique_abbrev_r(struct repository *r, char *hex,\n \t\t\t      const struct object_id *oid, int len)\n {\ndiff --git a/object-name.h b/object-name.h\nindex 1d63698f42..9ae5223071 100644\n--- a/object-name.h\n+++ b/object-name.h\n@@ -40,6 +40,15 @@ struct object_context {\n const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);\n int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);\n \n+/**\n+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n+ * the strbuf `sb`.\n+ */\n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len);\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len);\n+\n int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);\n __attribute__((format (printf, 2, 3)))\n int get_oidf(struct object_id *oid, const char *fmt, ...);\ndiff --git a/pretty.c b/pretty.c\nindex 0bb938021b..78bac2d818 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -18,6 +18,7 @@\n #include \"gpg-interface.h\"\n #include \"trailer.h\"\n #include \"run-command.h\"\n+#include \"object-name.h\"\n \n /*\n  * The limit for formatting directives, which enable the caller to append\ndiff --git a/strbuf.c b/strbuf.c\nindex da2693b21f..6533559e95 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,6 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"object-name.h\"\n #include \"refs.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n@@ -1023,21 +1022,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,\n \tstrbuf_setlen(sb, sb->len + len);\n }\n \n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len)\n-{\n-\tint r;\n-\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n-\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n-\tstrbuf_setlen(sb, sb->len + r);\n-}\n-\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len)\n-{\n-\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n-}\n-\n /*\n  * Returns the length of a line, without trailing spaces.\n  *\ndiff --git a/strbuf.h b/strbuf.h\nindex 114ad0c024..5d97e27b99 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -616,16 +616,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,\n  */\n void strbuf_list_free(struct strbuf **list);\n \n-/**\n- * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n- * the strbuf `sb`.\n- */\n-struct repository;\n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len);\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len);\n-\n /*\n  * Remove the filename from the provided path string. If the path\n  * contains a trailing separator, then the path is considered a directory\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477192","messageId":"20230512171516.2203472-3-calvinwan@google.com","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"[PATCH v6 3/7] credential-store: move related functions to credential-store file","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-12T17:15:12Z","receivedAt":"2023-05-12T17:15:41Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"is_rfc3986_unreserved() and is_rfc3986_reserved_or_unreserved() are only\ncalled from builtin/credential-store.c and they are only relevant to that\nfile so move those functions and make them static.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n builtin/credential-store.c | 19 +++++++++++++++++++\n strbuf.c                   | 19 -------------------\n strbuf.h                   |  3 ---\n 3 files changed, 19 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/credential-store.c b/builtin/credential-store.c\nindex 8977604eb9..4776118331 100644\n--- a/builtin/credential-store.c\n+++ b/builtin/credential-store.c\n@@ -73,6 +73,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,\n \t\tdie_errno(\"unable to write credential store\");\n }\n \n+static int is_rfc3986_unreserved(char ch)\n+{\n+\treturn isalnum(ch) ||\n+\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n+}\n+\n+static int is_rfc3986_reserved_or_unreserved(char ch)\n+{\n+\tif (is_rfc3986_unreserved(ch))\n+\t\treturn 1;\n+\tswitch (ch) {\n+\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n+\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n+\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static void store_credential_file(const char *fn, struct credential *c)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/strbuf.c b/strbuf.c\nindex c3b6d48797..da2693b21f 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -809,25 +809,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)\n \t}\n }\n \n-int is_rfc3986_reserved_or_unreserved(char ch)\n-{\n-\tif (is_rfc3986_unreserved(ch))\n-\t\treturn 1;\n-\tswitch (ch) {\n-\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n-\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n-\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-int is_rfc3986_unreserved(char ch)\n-{\n-\treturn isalnum(ch) ||\n-\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n-}\n-\n static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,\n \t\t\t\t char_predicate allow_unencoded_fn)\n {\ndiff --git a/strbuf.h b/strbuf.h\nindex 207efb4f98..114ad0c024 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -690,9 +690,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);\n \n typedef int (*char_predicate)(char ch);\n \n-int is_rfc3986_unreserved(char ch);\n-int is_rfc3986_reserved_or_unreserved(char ch);\n-\n void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,\n \t\t\t     char_predicate allow_unencoded_fn);\n \n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477193","messageId":"20230512171516.2203472-5-calvinwan@google.com","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"[PATCH v6 5/7] path: move related function to path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-12T17:15:14Z","receivedAt":"2023-05-12T17:15:44Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move path-related function from strbuf.[ch] to path.[ch] so that strbuf\nis focused on string manipulation routines with minimal dependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n path.c   | 20 ++++++++++++++++++++\n path.h   |  5 +++++\n strbuf.c | 20 --------------------\n 3 files changed, 25 insertions(+), 20 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 7c1cd8182a..e17a2613c5 100644\n--- a/path.c\n+++ b/path.c\n@@ -1213,6 +1213,26 @@ int normalize_path_copy(char *dst, const char *src)\n \treturn normalize_path_copy_len(dst, src, NULL);\n }\n \n+int strbuf_normalize_path(struct strbuf *src)\n+{\n+\tstruct strbuf dst = STRBUF_INIT;\n+\n+\tstrbuf_grow(&dst, src->len);\n+\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n+\t\tstrbuf_release(&dst);\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * normalize_path does not tell us the new length, so we have to\n+\t * compute it by looking for the new NUL it placed\n+\t */\n+\tstrbuf_setlen(&dst, strlen(dst.buf));\n+\tstrbuf_swap(src, &dst);\n+\tstrbuf_release(&dst);\n+\treturn 0;\n+}\n+\n /*\n  * path = Canonical absolute path\n  * prefixes = string_list containing normalized, absolute paths without\ndiff --git a/path.h b/path.h\nindex 60e83a49a9..639372edd9 100644\n--- a/path.h\n+++ b/path.h\n@@ -191,6 +191,11 @@ const char *remove_leading_path(const char *in, const char *prefix);\n const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);\n int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);\n int normalize_path_copy(char *dst, const char *src);\n+/**\n+ * Normalize in-place the path contained in the strbuf. If an error occurs,\n+ * the contents of \"sb\" are left untouched, and -1 is returned.\n+ */\n+int strbuf_normalize_path(struct strbuf *src);\n int longest_ancestor_length(const char *path, struct string_list *prefixes);\n char *strip_path_suffix(const char *path, const char *suffix);\n int daemon_avoid_alias(const char *path);\ndiff --git a/strbuf.c b/strbuf.c\nindex 6533559e95..178d75f250 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1088,26 +1088,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \tstrbuf_setlen(sb, j);\n }\n \n-int strbuf_normalize_path(struct strbuf *src)\n-{\n-\tstruct strbuf dst = STRBUF_INIT;\n-\n-\tstrbuf_grow(&dst, src->len);\n-\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n-\t\tstrbuf_release(&dst);\n-\t\treturn -1;\n-\t}\n-\n-\t/*\n-\t * normalize_path does not tell us the new length, so we have to\n-\t * compute it by looking for the new NUL it placed\n-\t */\n-\tstrbuf_setlen(&dst, strlen(dst.buf));\n-\tstrbuf_swap(src, &dst);\n-\tstrbuf_release(&dst);\n-\treturn 0;\n-}\n-\n void strbuf_strip_file_from_path(struct strbuf *sb)\n {\n \tchar *path_sep = find_last_dir_sep(sb->buf);\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477194","messageId":"20230512171516.2203472-6-calvinwan@google.com","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"[PATCH v6 6/7] strbuf: clarify dependency","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-12T17:15:15Z","receivedAt":"2023-05-12T17:15:53Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"refs.h was once needed but is no longer so as of 6bab74e7fb8 (\"strbuf:\nmove strbuf_branchname to sha1_name.c\", 2010-11-06). strbuf.h was\nincluded thru refs.h, so removing refs.h requires strbuf.h to be added\nback.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex 178d75f250..d5978fee4e 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,7 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"refs.h\"\n+#include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n #include \"date.h\"\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477195","messageId":"20230512171516.2203472-7-calvinwan@google.com","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"[PATCH v6 7/7] strbuf: remove global variable","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-05-12T17:15:16Z","receivedAt":"2023-05-12T17:15:59Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"As a library that only interacts with other primitives, strbuf should\nnot utilize the comment_line_char global variable within its\nfunctions. Therefore, add an additional parameter for functions that use\ncomment_line_char and refactor callers to pass it in instead.\nstrbuf_stripspace() removes the skip_comments boolean and checks if\ncomment_line_char is a non-NUL character to determine whether to skip\ncomments or not.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n add-patch.c          | 12 +++++++-----\n builtin/am.c         |  2 +-\n builtin/branch.c     |  4 ++--\n builtin/commit.c     |  2 +-\n builtin/merge.c      | 10 ++++++----\n builtin/notes.c      | 16 +++++++++-------\n builtin/rebase.c     |  2 +-\n builtin/stripspace.c |  6 ++++--\n builtin/tag.c        |  9 ++++++---\n fmt-merge-msg.c      |  9 ++++++---\n gpg-interface.c      |  5 +++--\n rebase-interactive.c | 15 ++++++++-------\n sequencer.c          | 24 +++++++++++++++---------\n strbuf.c             | 18 ++++++++++--------\n strbuf.h             | 14 ++++++++------\n wt-status.c          |  6 +++---\n 16 files changed, 90 insertions(+), 64 deletions(-)\n\ndiff --git a/add-patch.c b/add-patch.c\nindex 8d770d203f..9702c1aabd 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \tsize_t i;\n \n \tstrbuf_reset(&s->buf);\n-\tstrbuf_commented_addf(&s->buf, _(\"Manual hunk edit mode -- see bottom for \"\n-\t\t\t\t      \"a quick guide.\\n\"));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n+\t\t\t      _(\"Manual hunk edit mode -- see bottom for \"\n+\t\t\t\t\"a quick guide.\\n\"));\n \trender_hunk(s, hunk, 0, 0, &s->buf);\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"---\\n\"\n \t\t\t\t\"To remove '%c' lines, make them ' ' lines \"\n \t\t\t\t\"(context).\\n\"\n@@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \t\t\t      s->mode->is_reverse ? '+' : '-',\n \t\t\t      s->mode->is_reverse ? '-' : '+',\n \t\t\t      comment_line_char);\n-\tstrbuf_commented_addf(&s->buf, \"%s\", _(s->mode->edit_hunk_hint));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char, \"%s\",\n+\t\t\t      _(s->mode->edit_hunk_hint));\n \t/*\n \t * TRANSLATORS: 'it' refers to the patch mentioned in the previous\n \t * messages.\n \t */\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"If it does not apply cleanly, you will be \"\n \t\t\t\t\"given an opportunity to\\n\"\n \t\t\t\t\"edit again.  If all lines of the hunk are \"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5c83f2e003..9ece2e3066 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n \tstrbuf_addbuf(&msg, &mi.log_message);\n-\tstrbuf_stripspace(&msg, 0);\n+\tstrbuf_stripspace(&msg, '\\0');\n \n \tassert(!state->author_name);\n \tstate->author_name = strbuf_detach(&author_name, NULL);\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 501c47657c..4560610d09 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -629,7 +629,7 @@ static int edit_branch_description(const char *branch_name)\n \texists = !read_branch_desc(&buf, branch_name);\n \tif (!buf.len || buf.buf[buf.len-1] != '\\n')\n \t\tstrbuf_addch(&buf, '\\n');\n-\tstrbuf_commented_addf(&buf,\n+\tstrbuf_commented_addf(&buf, comment_line_char,\n \t\t    _(\"Please edit the description for the branch\\n\"\n \t\t      \"  %s\\n\"\n \t\t      \"Lines starting with '%c' will be stripped.\\n\"),\n@@ -640,7 +640,7 @@ static int edit_branch_description(const char *branch_name)\n \t\tstrbuf_release(&buf);\n \t\treturn -1;\n \t}\n-\tstrbuf_stripspace(&buf, 1);\n+\tstrbuf_stripspace(&buf, comment_line_char);\n \n \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n \tif (buf.len || exists)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex e67c4be221..e002ebf070 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \ts->hints = 0;\n \n \tif (clean_message_contents)\n-\t\tstrbuf_stripspace(&sb, 0);\n+\t\tstrbuf_stripspace(&sb, '\\0');\n \n \tif (signoff)\n \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8da3e46abb..1d14767c0c 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)\n \t\tstrbuf_addch(&msg, '\\n');\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {\n \t\t\twt_status_append_cut_line(&msg);\n-\t\t\tstrbuf_commented_addf(&msg, \"\\n\");\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char, \"\\n\");\n \t\t}\n-\t\tstrbuf_commented_addf(&msg, _(merge_editor_comment));\n+\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t      _(merge_editor_comment));\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n-\t\t\tstrbuf_commented_addf(&msg, _(scissors_editor_comment));\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t\t      _(scissors_editor_comment));\n \t\telse\n-\t\t\tstrbuf_commented_addf(&msg,\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n \t\t\t\t_(no_scissors_editor_comment), comment_line_char);\n \t}\n \tif (signoff)\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex d5788352b6..3bad5b458b 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -11,6 +11,7 @@\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"editor.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"notes.h\"\n@@ -157,7 +158,7 @@ static void write_commented_object(int fd, const struct object_id *object)\n \n \tif (strbuf_read(&buf, show.out, 0) < 0)\n \t\tdie_errno(_(\"could not read 'show' output\"));\n-\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);\n \twrite_or_die(fd, cbuf.buf, cbuf.len);\n \n \tstrbuf_release(&cbuf);\n@@ -185,9 +186,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\t\tcopy_obj_to_fd(fd, old_note);\n \n \t\tstrbuf_addch(&buf, '\\n');\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n-\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),\n+\t\t\t\t\t   comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n \t\twrite_or_die(fd, buf.buf, buf.len);\n \n \t\twrite_commented_object(fd, object);\n@@ -199,7 +201,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\tif (launch_editor(d->edit_path, &d->buf, NULL)) {\n \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n \t\t}\n-\t\tstrbuf_stripspace(&d->buf, 1);\n+\t\tstrbuf_stripspace(&d->buf, comment_line_char);\n \t}\n }\n \n@@ -225,7 +227,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \tstrbuf_addstr(&d->buf, arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, '\\0');\n \n \td->given = 1;\n \treturn 0;\n@@ -244,7 +246,7 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n \t\t\tdie_errno(_(\"cannot read '%s'\"), arg);\n \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, '\\0');\n \n \td->given = 1;\n \treturn 0;\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex ace1d5e8d1..b1ba9fb05d 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)\n \tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n \n-\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tstrbuf_stripspace(&todo_list.buf, comment_line_char);\n \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 9451eb69ff..1987752359 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"parse-options.h\"\n #include \"setup.h\"\n@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)\n \tsize_t len;\n \n \tmsg = strbuf_detach(buf, &len);\n-\tstrbuf_add_commented_lines(buf, msg, len);\n+\tstrbuf_add_commented_lines(buf, msg, len, comment_line_char);\n \tfree(msg);\n }\n \n@@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)\n \t\tdie_errno(\"could not read the input\");\n \n \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n-\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n+\t\tstrbuf_stripspace(&buf,\n+\t\t\t  mode == STRIP_COMMENTS ? comment_line_char : '\\0');\n \telse\n \t\tcomment_lines(&buf);\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1850a6a6fd..b79e0a88e6 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n \t\t\tstrbuf_addch(&buf, '\\n');\n \t\t\tif (opt->cleanup_mode == CLEANUP_ALL)\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template), tag, comment_line_char);\n \t\t\telse\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template_nocleanup), tag, comment_line_char);\n \t\t\twrite_or_die(fd, buf.buf, buf.len);\n \t\t\tstrbuf_release(&buf);\n \t\t}\n@@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t}\n \n \tif (opt->cleanup_mode != CLEANUP_NONE)\n-\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n+\t\tstrbuf_stripspace(buf,\n+\t\t  opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\\0');\n \n \tif (!opt->message_given && !buf->len)\n \t\tdie(_(\"no tag message?\"));\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 5af0d4715b..5d15e2387d 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,\n \tstrbuf_complete_line(tagbuf);\n \tif (sig->len) {\n \t\tstrbuf_addch(tagbuf, '\\n');\n-\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len);\n+\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len,\n+\t\t\t\t\t   comment_line_char);\n \t}\n }\n \n@@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\t\tstrbuf_addch(&tagline, '\\n');\n \t\t\t\tstrbuf_add_commented_lines(&tagline,\n \t\t\t\t\t\torigins.items[first_tag].string,\n-\t\t\t\t\t\tstrlen(origins.items[first_tag].string));\n+\t\t\t\t\t\tstrlen(origins.items[first_tag].string),\n+\t\t\t\t\t\tcomment_line_char);\n \t\t\t\tstrbuf_insert(&tagbuf, 0, tagline.buf,\n \t\t\t\t\t      tagline.len);\n \t\t\t\tstrbuf_release(&tagline);\n@@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\tstrbuf_addch(&tagbuf, '\\n');\n \t\t\tstrbuf_add_commented_lines(&tagbuf,\n \t\t\t\t\torigins.items[i].string,\n-\t\t\t\t\tstrlen(origins.items[i].string));\n+\t\t\t\t\tstrlen(origins.items[i].string),\n+\t\t\t\t\tcomment_line_char);\n \t\t\tfmt_tag_signature(&tagbuf, &sig, buf, len);\n \t\t}\n \t\tstrbuf_release(&payload);\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex f3ac5acdd9..c27a751b70 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -11,6 +11,7 @@\n #include \"tempfile.h\"\n #include \"alias.h\"\n #include \"wrapper.h\"\n+#include \"environment.h\"\n \n static int git_gpg_config(const char *, const char *, void *);\n \n@@ -584,8 +585,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,\n \t\t}\n \t}\n \n-\tstrbuf_stripspace(&ssh_keygen_out, 0);\n-\tstrbuf_stripspace(&ssh_keygen_err, 0);\n+\tstrbuf_stripspace(&ssh_keygen_out, '\\0');\n+\tstrbuf_stripspace(&ssh_keygen_err, '\\0');\n \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 789f407361..012defbb53 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -71,13 +71,14 @@ void append_todo_help(int command_count,\n \n \tif (!edit_todo) {\n \t\tstrbuf_addch(buf, '\\n');\n-\t\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n-\t\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n-\t\t\t\t\t      command_count),\n+\t\tstrbuf_commented_addf(buf, comment_line_char,\n+\t\t\t\t      Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t\t \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t\t command_count),\n \t\t\t\t      shortrevisions, shortonto, command_count);\n \t}\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -86,7 +87,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -97,7 +98,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n }\n \n int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n@@ -129,7 +130,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n \tif (launch_sequence_editor(todo_file, &new_todo->buf, NULL))\n \t\treturn -2;\n \n-\tstrbuf_stripspace(&new_todo->buf, 1);\n+\tstrbuf_stripspace(&new_todo->buf, comment_line_char);\n \tif (initial && new_todo->buf.len == 0)\n \t\treturn -3;\n \ndiff --git a/sequencer.c b/sequencer.c\nindex c88d1d9553..eae4563ef7 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -659,11 +659,12 @@ void append_conflicts_hint(struct index_state *istate,\n \t}\n \n \tstrbuf_addch(msgbuf, '\\n');\n-\tstrbuf_commented_addf(msgbuf, \"Conflicts:\\n\");\n+\tstrbuf_commented_addf(msgbuf, comment_line_char, \"Conflicts:\\n\");\n \tfor (i = 0; i < istate->cache_nr;) {\n \t\tconst struct cache_entry *ce = istate->cache[i++];\n \t\tif (ce_stage(ce)) {\n-\t\t\tstrbuf_commented_addf(msgbuf, \"\\t%s\\n\", ce->name);\n+\t\t\tstrbuf_commented_addf(msgbuf, comment_line_char,\n+\t\t\t\t\t      \"\\t%s\\n\", ce->name);\n \t\t\twhile (i < istate->cache_nr &&\n \t\t\t       !strcmp(ce->name, istate->cache[i]->name))\n \t\t\t\ti++;\n@@ -1142,7 +1143,8 @@ void cleanup_message(struct strbuf *msgbuf,\n \t    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msgbuf,\n+\t\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n }\n \n /*\n@@ -1173,7 +1175,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,\n \tif (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)\n \t\treturn 0;\n \n-\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\tstrbuf_stripspace(&tmpl,\n+\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n \t\tstart = sb->buf;\n \tstrbuf_release(&tmpl);\n@@ -1545,7 +1548,8 @@ static int try_to_commit(struct repository *r,\n \t\tcleanup = opts->default_msg_cleanup;\n \n \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msg,\n+\t\t  cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n \t\tres = 1; /* run 'git commit' to display error message */\n \t\tgoto out;\n@@ -1839,7 +1843,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n \t\ts += count;\n \t\tlen -= count;\n \t}\n-\tstrbuf_add_commented_lines(buf, s, len);\n+\tstrbuf_add_commented_lines(buf, s, len, comment_line_char);\n }\n \n /* Does the current fixup chain contain a squash command? */\n@@ -1938,7 +1942,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_add_commented_lines(buf, body, commented_len, comment_line_char);\n \t/* buf->buf may be reallocated so store an offset into the buffer */\n \tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n@@ -2028,7 +2032,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tif (is_fixup_flag(command, flag))\n-\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t\t   comment_line_char);\n \t\telse\n \t\t\tstrbuf_addstr(&buf, body);\n \n@@ -2047,7 +2052,8 @@ static int update_squash_messages(struct repository *r,\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t   comment_line_char);\n \t} else\n \t\treturn error(_(\"unknown command: %d\"), command);\n \trepo_unuse_commit_buffer(r, commit, message);\ndiff --git a/strbuf.c b/strbuf.c\nindex d5978fee4e..67e399b60a 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,6 +1,5 @@\n #include \"git-compat-util.h\"\n #include \"alloc.h\"\n-#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"strbuf.h\"\n@@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n \tstrbuf_complete_line(out);\n }\n \n-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n+\t\t\t\tsize_t size, char comment_line_char)\n {\n \tstatic char prefix1[3];\n \tstatic char prefix2[2];\n@@ -374,7 +374,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size\n \tadd_lines(out, prefix1, prefix2, buf, size);\n }\n \n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,\n+\t\t\t   const char *fmt, ...)\n {\n \tva_list params;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -384,7 +385,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n \tstrbuf_vaddf(&buf, fmt, params);\n \tva_end(params);\n \n-\tstrbuf_add_commented_lines(sb, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);\n \tif (incomplete_line)\n \t\tsb->buf[--sb->len] = '\\0';\n \n@@ -1051,10 +1052,10 @@ static size_t cleanup(char *line, size_t len)\n  *\n  * If last line does not have a newline at the end, one is added.\n  *\n- * Enable skip_comments to skip every line starting with comment\n- * character.\n+ * Pass a non-NUL comment_line_char to skip every line starting\n+ * with it.\n  */\n-void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n+void strbuf_stripspace(struct strbuf *sb, char comment_line_char)\n {\n \tsize_t empties = 0;\n \tsize_t i, j, len, newlen;\n@@ -1067,7 +1068,8 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \t\teol = memchr(sb->buf + i, '\\n', sb->len - i);\n \t\tlen = eol ? eol - (sb->buf + i) + 1 : sb->len - i;\n \n-\t\tif (skip_comments && len && sb->buf[i] == comment_line_char) {\n+\t\tif (comment_line_char && len &&\n+\t\t    sb->buf[i] == comment_line_char) {\n \t\t\tnewlen = 0;\n \t\t\tcontinue;\n \t\t}\ndiff --git a/strbuf.h b/strbuf.h\nindex 5d97e27b99..da91c17257 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -291,7 +291,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n  * by a comment character and a blank.\n  */\n void strbuf_add_commented_lines(struct strbuf *out,\n-\t\t\t\tconst char *buf, size_t size);\n+\t\t\t\tconst char *buf, size_t size,\n+\t\t\t\tchar comment_line_char);\n \n \n /**\n@@ -420,8 +421,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n  * Add a formatted string prepended by a comment character and a\n  * blank to the buffer.\n  */\n-__attribute__((format (printf, 2, 3)))\n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n+__attribute__((format (printf, 3, 4)))\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n \n __attribute__((format (printf,2,0)))\n void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n@@ -543,10 +544,11 @@ int strbuf_getcwd(struct strbuf *sb);\n int strbuf_normalize_path(struct strbuf *sb);\n \n /**\n- * Strip whitespace from a buffer. The second parameter controls if\n- * comments are considered contents to be removed or not.\n+ * Strip whitespace from a buffer. If comment_line_char is non-NUL,\n+ * then lines beginning with that character are considered comments,\n+ * thus removed.\n  */\n-void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n+void strbuf_stripspace(struct strbuf *buf, char comment_line_char);\n \n static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n {\ndiff --git a/wt-status.c b/wt-status.c\nindex 97b9c1c035..da7734866f 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1023,7 +1023,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom\n \tif (s->display_comment_prefix) {\n \t\tsize_t len;\n \t\tsummary_content = strbuf_detach(&summary, &len);\n-\t\tstrbuf_add_commented_lines(&summary, summary_content, len);\n+\t\tstrbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);\n \t\tfree(summary_content);\n \t}\n \n@@ -1098,8 +1098,8 @@ void wt_status_append_cut_line(struct strbuf *buf)\n {\n \tconst char *explanation = _(\"Do not modify or remove the line above.\\nEverything below it will be ignored.\");\n \n-\tstrbuf_commented_addf(buf, \"%s\", cut_line);\n-\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation));\n+\tstrbuf_commented_addf(buf, comment_line_char, \"%s\", cut_line);\n+\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);\n }\n \n void wt_status_add_cut_line(FILE *fp)\n-- \n2.40.1.606.ga4b1b128d6-goog\n\n"},{"id":"477204","messageId":"xmqqr0rlpcrb.fsf@gitster.g","threadId":"59685","inReplyTo":"c9e22e51-4e4a-b692-edfd-1f3bc7ee7da9@gmail.com","subject":"Re: [PATCH v5 7/7] strbuf: remove global variable","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-12T19:31:52Z","receivedAt":"2023-05-12T19:31:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> Hi Calvin\n>\n> On 11/05/2023 20:48, Calvin Wan wrote:\n>> As a library that only interacts with other primitives, strbuf should\n>> not utilize the comment_line_char global variable within its\n>> functions. Therefore, add an additional parameter for functions that use\n>> comment_line_char and refactor callers to pass it in instead.\n>> strbuf_stripspace() removes the skip_comments boolean and checks if\n>> comment_line_char is a non-NULL character to determine whether to skip\n>> comments or not.\n>\n> Thanks for re-rolling, I agree with Eric's comments but would be happy\n> if this was merged as-is.\n\nThanks for reviewing.\n"},{"id":"477211","messageId":"xmqq5y8xpabr.fsf@gitster.g","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"Re: [PATCH v6 0/7] strbuf cleanups","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2023-05-12T20:24:24Z","receivedAt":"2023-05-12T20:26:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Calvin Wan <calvinwan@google.com> writes:\n\n> Reroll with last couple of nits fixed. Thanks again to everyone for\n> reviewing this series!\n>\n> Calvin Wan (7):\n>   strbuf: clarify API boundary\n>   abspath: move related functions to abspath\n>   credential-store: move related functions to credential-store file\n>   object-name: move related functions to object-name\n>   path: move related function to path\n>   strbuf: clarify dependency\n>   strbuf: remove global variable\n\nLooking good.  I see Eric's comments, to which Phillip agreed to,\nare all addressed in these patches.\n\nWill replace; let's mark the topic for 'next'.\n\n"},{"id":"477245","messageId":"CAPig+cR=BdoyDNaS2Rrx8+07yT_FFaJygPyVyuBKw_DExX1NbQ@mail.gmail.com","threadId":"59685","inReplyTo":"xmqq5y8xpabr.fsf@gitster.g","subject":"Re: [PATCH v6 0/7] strbuf cleanups","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2023-05-13T05:54:01Z","receivedAt":"2023-05-13T05:57:57Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, May 12, 2023 at 4:24 PM Junio C Hamano <gitster@pobox.com> wrote:\n> Calvin Wan <calvinwan@google.com> writes:\n> > Reroll with last couple of nits fixed. Thanks again to everyone for\n> > reviewing this series!\n>\n> Looking good.  I see Eric's comments, to which Phillip agreed to,\n> are all addressed in these patches.\n\nAgreed. This version is looking good; I have no further comments.\nThanks for taking my comments into consideration.\n"},{"id":"478107","messageId":"20230606194720.2053551-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230512171429.2202982-1-calvinwan@google.com","subject":"[PATCH v7 0/7] strbuf cleanups","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-06-06T19:47:20Z","receivedAt":"2023-06-06T19:48:20Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"I rebased this series onto 2.41 and noticed I was getting a compilation\nerror for a missing dependency to repository in dir.h. With all of the\nother cleanups happening, I assume some dependency chain that used to\nexist doesn't anymore. This reroll moves \"strbuf: clarify dependency\" to\nthe second patch so any dependency chain broken by the other cleanup\npatches can be caught. And that is why patch 4 adds a forward\ndeclaration back. I also caught an additional unnecessary dependency\nthat could be removed in patch 5. This series should now be able to be\nrebased onto 2.41 without any issue.\n\nCalvin Wan (7):\n  strbuf: clarify API boundary\n  strbuf: clarify dependency\n  abspath: move related functions to abspath\n  credential-store: move related functions to credential-store file\n  object-name: move related functions to object-name\n  path: move related function to path\n  strbuf: remove global variable\n\n abspath.c                  |  36 ++++++++++++\n abspath.h                  |  21 +++++++\n add-patch.c                |  12 ++--\n builtin/am.c               |   2 +-\n builtin/branch.c           |   4 +-\n builtin/commit.c           |   2 +-\n builtin/credential-store.c |  19 +++++++\n builtin/merge.c            |  10 ++--\n builtin/notes.c            |  16 +++---\n builtin/rebase.c           |   2 +-\n builtin/stripspace.c       |   6 +-\n builtin/tag.c              |   9 ++-\n dir.h                      |   2 +\n fmt-merge-msg.c            |   9 ++-\n gpg-interface.c            |   5 +-\n hook.c                     |   1 +\n object-name.c              |  15 +++++\n object-name.h              |   9 +++\n path.c                     |  20 +++++++\n path.h                     |   5 ++\n pretty.c                   |   1 +\n rebase-interactive.c       |  15 ++---\n sequencer.c                |  24 +++++---\n strbuf.c                   | 113 ++++---------------------------------\n strbuf.h                   |  57 ++++++-------------\n tempfile.c                 |   1 +\n wt-status.c                |   6 +-\n 27 files changed, 229 insertions(+), 193 deletions(-)\n\nRange-diff against v6:\n1:  5ae531a1e2 = 1:  121788f263 strbuf: clarify API boundary\n-:  ---------- > 2:  5e91404ecd strbuf: clarify dependency\n2:  3bb2b9c01a = 3:  5c05f40181 abspath: move related functions to abspath\n3:  ff91ca2fda = 4:  e1addc77e5 credential-store: move related functions to credential-store file\n4:  10e61eb570 ! 5:  62e8c42f59 object-name: move related functions to object-name\n    @@ Commit message\n         so that strbuf is focused on string manipulation routines with minimal\n         dependencies.\n     \n    +    dir.h relied on the forward declration of the repository struct in\n    +    strbuf.h. Since that is removed in this patch, add the forward\n    +    declaration to dir.h.\n    +\n    + ## dir.h ##\n    +@@\n    +  *\n    +  */\n    + \n    ++struct repository;\n    ++\n    + struct dir_entry {\n    + \tunsigned int len;\n    + \tchar name[FLEX_ARRAY]; /* more */\n    +\n      ## object-name.c ##\n     @@ object-name.c: static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n      \t\tfind_abbrev_len_for_pack(p, mad);\n    @@ strbuf.c\n      #include \"gettext.h\"\n      #include \"hex.h\"\n     -#include \"object-name.h\"\n    - #include \"refs.h\"\n    + #include \"repository.h\"\n    + #include \"strbuf.h\"\n      #include \"string-list.h\"\n    - #include \"utf8.h\"\n     @@ strbuf.c: void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,\n      \tstrbuf_setlen(sb, sb->len + len);\n      }\n5:  c3d5db4e11 ! 6:  0abba57acb path: move related function to path\n    @@ Commit message\n         Move path-related function from strbuf.[ch] to path.[ch] so that strbuf\n         is focused on string manipulation routines with minimal dependencies.\n     \n    +    repository.h is no longer a necessary dependency after moving this\n    +    function out.\n    +\n      ## path.c ##\n     @@ path.c: int normalize_path_copy(char *dst, const char *src)\n      \treturn normalize_path_copy_len(dst, src, NULL);\n    @@ path.h: const char *remove_leading_path(const char *in, const char *prefix);\n      int daemon_avoid_alias(const char *path);\n     \n      ## strbuf.c ##\n    +@@\n    + #include \"environment.h\"\n    + #include \"gettext.h\"\n    + #include \"hex.h\"\n    +-#include \"repository.h\"\n    + #include \"strbuf.h\"\n    + #include \"string-list.h\"\n    + #include \"utf8.h\"\n     @@ strbuf.c: void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n      \tstrbuf_setlen(sb, j);\n      }\n6:  113d156195 < -:  ---------- strbuf: clarify dependency\n7:  01c923160d = 7:  d33267a390 strbuf: remove global variable\n-- \n2.41.0.162.gfafddb0af9-goog\n\n"},{"id":"478108","messageId":"20230606194843.2054314-1-calvinwan@google.com","threadId":"59685","inReplyTo":"20230606194720.2053551-1-calvinwan@google.com","subject":"[PATCH v7 1/7] strbuf: clarify API boundary","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-06-06T19:48:37Z","receivedAt":"2023-06-06T19:48:57Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"strbuf, as a generic and widely used structure across the codebase,\nshould be limited as a library to only interact with primitives. Add\ndocumentation so future functions can appropriately be placed. Older\nfunctions that do not follow this boundary should eventually be moved or\nrefactored.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.h | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/strbuf.h b/strbuf.h\nindex 3dfeadb44c..70778c6e10 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -1,6 +1,14 @@\n #ifndef STRBUF_H\n #define STRBUF_H\n \n+/*\n+ * NOTE FOR STRBUF DEVELOPERS\n+ *\n+ * strbuf is a low-level primitive; as such it should interact only\n+ * with other low-level primitives. Do not introduce new functions\n+ * which interact with higher-level APIs.\n+ */\n+\n struct string_list;\n \n /**\n-- \n2.41.0.162.gfafddb0af9-goog\n\n"},{"id":"478109","messageId":"20230606194843.2054314-2-calvinwan@google.com","threadId":"59685","inReplyTo":"20230606194720.2053551-1-calvinwan@google.com","subject":"[PATCH v7 2/7] strbuf: clarify dependency","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-06-06T19:48:38Z","receivedAt":"2023-06-06T19:48:58Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"refs.h was once needed but is no longer so as of 6bab74e7fb8 (\"strbuf:\nmove strbuf_branchname to sha1_name.c\", 2010-11-06). strbuf.h was\nincluded thru refs.h, so removing refs.h requires strbuf.h to be added\nback.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n strbuf.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex 08eec8f1d8..f5dfd093a0 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -5,8 +5,8 @@\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"object-name.h\"\n-#include \"refs.h\"\n #include \"repository.h\"\n+#include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n #include \"date.h\"\n-- \n2.41.0.162.gfafddb0af9-goog\n\n"},{"id":"478110","messageId":"20230606194843.2054314-6-calvinwan@google.com","threadId":"59685","inReplyTo":"20230606194720.2053551-1-calvinwan@google.com","subject":"[PATCH v7 6/7] path: move related function to path","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-06-06T19:48:42Z","receivedAt":"2023-06-06T19:49:01Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move path-related function from strbuf.[ch] to path.[ch] so that strbuf\nis focused on string manipulation routines with minimal dependencies.\n\nrepository.h is no longer a necessary dependency after moving this\nfunction out.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n path.c   | 20 ++++++++++++++++++++\n path.h   |  5 +++++\n strbuf.c | 21 ---------------------\n 3 files changed, 25 insertions(+), 21 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 7c1cd8182a..e17a2613c5 100644\n--- a/path.c\n+++ b/path.c\n@@ -1213,6 +1213,26 @@ int normalize_path_copy(char *dst, const char *src)\n \treturn normalize_path_copy_len(dst, src, NULL);\n }\n \n+int strbuf_normalize_path(struct strbuf *src)\n+{\n+\tstruct strbuf dst = STRBUF_INIT;\n+\n+\tstrbuf_grow(&dst, src->len);\n+\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n+\t\tstrbuf_release(&dst);\n+\t\treturn -1;\n+\t}\n+\n+\t/*\n+\t * normalize_path does not tell us the new length, so we have to\n+\t * compute it by looking for the new NUL it placed\n+\t */\n+\tstrbuf_setlen(&dst, strlen(dst.buf));\n+\tstrbuf_swap(src, &dst);\n+\tstrbuf_release(&dst);\n+\treturn 0;\n+}\n+\n /*\n  * path = Canonical absolute path\n  * prefixes = string_list containing normalized, absolute paths without\ndiff --git a/path.h b/path.h\nindex 60e83a49a9..639372edd9 100644\n--- a/path.h\n+++ b/path.h\n@@ -191,6 +191,11 @@ const char *remove_leading_path(const char *in, const char *prefix);\n const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);\n int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);\n int normalize_path_copy(char *dst, const char *src);\n+/**\n+ * Normalize in-place the path contained in the strbuf. If an error occurs,\n+ * the contents of \"sb\" are left untouched, and -1 is returned.\n+ */\n+int strbuf_normalize_path(struct strbuf *src);\n int longest_ancestor_length(const char *path, struct string_list *prefixes);\n char *strip_path_suffix(const char *path, const char *suffix);\n int daemon_avoid_alias(const char *path);\ndiff --git a/strbuf.c b/strbuf.c\nindex 80b7e051cd..d5978fee4e 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,6 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"repository.h\"\n #include \"strbuf.h\"\n #include \"string-list.h\"\n #include \"utf8.h\"\n@@ -1089,26 +1088,6 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \tstrbuf_setlen(sb, j);\n }\n \n-int strbuf_normalize_path(struct strbuf *src)\n-{\n-\tstruct strbuf dst = STRBUF_INIT;\n-\n-\tstrbuf_grow(&dst, src->len);\n-\tif (normalize_path_copy(dst.buf, src->buf) < 0) {\n-\t\tstrbuf_release(&dst);\n-\t\treturn -1;\n-\t}\n-\n-\t/*\n-\t * normalize_path does not tell us the new length, so we have to\n-\t * compute it by looking for the new NUL it placed\n-\t */\n-\tstrbuf_setlen(&dst, strlen(dst.buf));\n-\tstrbuf_swap(src, &dst);\n-\tstrbuf_release(&dst);\n-\treturn 0;\n-}\n-\n void strbuf_strip_file_from_path(struct strbuf *sb)\n {\n \tchar *path_sep = find_last_dir_sep(sb->buf);\n-- \n2.41.0.162.gfafddb0af9-goog\n\n"},{"id":"478111","messageId":"20230606194843.2054314-3-calvinwan@google.com","threadId":"59685","inReplyTo":"20230606194720.2053551-1-calvinwan@google.com","subject":"[PATCH v7 3/7] abspath: move related functions to abspath","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-06-06T19:48:39Z","receivedAt":"2023-06-06T19:49:04Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move abspath-related functions from strbuf.[ch] to abspath.[ch] so that\nstrbuf is focused on string manipulation routines with minimal\ndependencies.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n abspath.c  | 36 ++++++++++++++++++++++++++++++++++++\n abspath.h  | 21 +++++++++++++++++++++\n hook.c     |  1 +\n strbuf.c   | 37 -------------------------------------\n strbuf.h   | 22 ----------------------\n tempfile.c |  1 +\n 6 files changed, 59 insertions(+), 59 deletions(-)\n\ndiff --git a/abspath.c b/abspath.c\nindex d032f5dce5..1202cde23d 100644\n--- a/abspath.c\n+++ b/abspath.c\n@@ -289,3 +289,39 @@ char *prefix_filename_except_for_dash(const char *pfx, const char *arg)\n \t\treturn xstrdup(arg);\n \treturn prefix_filename(pfx, arg);\n }\n+\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n+{\n+\tif (!*path)\n+\t\tdie(\"The empty string is not a valid path\");\n+\tif (!is_absolute_path(path)) {\n+\t\tstruct stat cwd_stat, pwd_stat;\n+\t\tsize_t orig_len = sb->len;\n+\t\tchar *cwd = xgetcwd();\n+\t\tchar *pwd = getenv(\"PWD\");\n+\t\tif (pwd && strcmp(pwd, cwd) &&\n+\t\t    !stat(cwd, &cwd_stat) &&\n+\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n+\t\t    !stat(pwd, &pwd_stat) &&\n+\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n+\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n+\t\t\tstrbuf_addstr(sb, pwd);\n+\t\telse\n+\t\t\tstrbuf_addstr(sb, cwd);\n+\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n+\t\t\tstrbuf_addch(sb, '/');\n+\t\tfree(cwd);\n+\t}\n+\tstrbuf_addstr(sb, path);\n+}\n+\n+void strbuf_add_real_path(struct strbuf *sb, const char *path)\n+{\n+\tif (sb->len) {\n+\t\tstruct strbuf resolved = STRBUF_INIT;\n+\t\tstrbuf_realpath(&resolved, path, 1);\n+\t\tstrbuf_addbuf(sb, &resolved);\n+\t\tstrbuf_release(&resolved);\n+\t} else\n+\t\tstrbuf_realpath(sb, path, 1);\n+}\ndiff --git a/abspath.h b/abspath.h\nindex 7cd3de5e9d..4653080d5e 100644\n--- a/abspath.h\n+++ b/abspath.h\n@@ -30,4 +30,25 @@ static inline int is_absolute_path(const char *path)\n \treturn is_dir_sep(path[0]) || has_dos_drive_prefix(path);\n }\n \n+/**\n+ * Add a path to a buffer, converting a relative path to an\n+ * absolute one in the process.  Symbolic links are not\n+ * resolved.\n+ */\n+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n+\n+/**\n+ * Canonize `path` (make it absolute, resolve symlinks, remove extra\n+ * slashes) and append it to `sb`.  Die with an informative error\n+ * message if there is a problem.\n+ *\n+ * The directory part of `path` (i.e., everything up to the last\n+ * dir_sep) must denote a valid, existing directory, but the last\n+ * component need not exist.\n+ *\n+ * Callers that don't mind links should use the more lightweight\n+ * strbuf_add_absolute_path() instead.\n+ */\n+void strbuf_add_real_path(struct strbuf *sb, const char *path);\n+\n #endif /* ABSPATH_H */\ndiff --git a/hook.c b/hook.c\nindex 3ca5e60895..f6306d72b3 100644\n--- a/hook.c\n+++ b/hook.c\n@@ -1,4 +1,5 @@\n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"advice.h\"\n #include \"gettext.h\"\n #include \"hook.h\"\ndiff --git a/strbuf.c b/strbuf.c\nindex f5dfd093a0..a2249ae7ed 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,5 +1,4 @@\n #include \"git-compat-util.h\"\n-#include \"abspath.h\"\n #include \"alloc.h\"\n #include \"environment.h\"\n #include \"gettext.h\"\n@@ -900,42 +899,6 @@ void strbuf_humanise_rate(struct strbuf *buf, off_t bytes)\n \tstrbuf_humanise(buf, bytes, 1);\n }\n \n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path)\n-{\n-\tif (!*path)\n-\t\tdie(\"The empty string is not a valid path\");\n-\tif (!is_absolute_path(path)) {\n-\t\tstruct stat cwd_stat, pwd_stat;\n-\t\tsize_t orig_len = sb->len;\n-\t\tchar *cwd = xgetcwd();\n-\t\tchar *pwd = getenv(\"PWD\");\n-\t\tif (pwd && strcmp(pwd, cwd) &&\n-\t\t    !stat(cwd, &cwd_stat) &&\n-\t\t    (cwd_stat.st_dev || cwd_stat.st_ino) &&\n-\t\t    !stat(pwd, &pwd_stat) &&\n-\t\t    pwd_stat.st_dev == cwd_stat.st_dev &&\n-\t\t    pwd_stat.st_ino == cwd_stat.st_ino)\n-\t\t\tstrbuf_addstr(sb, pwd);\n-\t\telse\n-\t\t\tstrbuf_addstr(sb, cwd);\n-\t\tif (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))\n-\t\t\tstrbuf_addch(sb, '/');\n-\t\tfree(cwd);\n-\t}\n-\tstrbuf_addstr(sb, path);\n-}\n-\n-void strbuf_add_real_path(struct strbuf *sb, const char *path)\n-{\n-\tif (sb->len) {\n-\t\tstruct strbuf resolved = STRBUF_INIT;\n-\t\tstrbuf_realpath(&resolved, path, 1);\n-\t\tstrbuf_addbuf(sb, &resolved);\n-\t\tstrbuf_release(&resolved);\n-\t} else\n-\t\tstrbuf_realpath(sb, path, 1);\n-}\n-\n int printf_ln(const char *fmt, ...)\n {\n \tint ret;\ndiff --git a/strbuf.h b/strbuf.h\nindex 70778c6e10..207efb4f98 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -535,28 +535,6 @@ int strbuf_getwholeline_fd(struct strbuf *sb, int fd, int term);\n  */\n int strbuf_getcwd(struct strbuf *sb);\n \n-/**\n- * Add a path to a buffer, converting a relative path to an\n- * absolute one in the process.  Symbolic links are not\n- * resolved.\n- */\n-void strbuf_add_absolute_path(struct strbuf *sb, const char *path);\n-\n-/**\n- * Canonize `path` (make it absolute, resolve symlinks, remove extra\n- * slashes) and append it to `sb`.  Die with an informative error\n- * message if there is a problem.\n- *\n- * The directory part of `path` (i.e., everything up to the last\n- * dir_sep) must denote a valid, existing directory, but the last\n- * component need not exist.\n- *\n- * Callers that don't mind links should use the more lightweight\n- * strbuf_add_absolute_path() instead.\n- */\n-void strbuf_add_real_path(struct strbuf *sb, const char *path);\n-\n-\n /**\n  * Normalize in-place the path contained in the strbuf. See\n  * normalize_path_copy() for details. If an error occurs, the contents of \"sb\"\ndiff --git a/tempfile.c b/tempfile.c\nindex 50c377134c..6c88a63b42 100644\n--- a/tempfile.c\n+++ b/tempfile.c\n@@ -43,6 +43,7 @@\n  */\n \n #include \"git-compat-util.h\"\n+#include \"abspath.h\"\n #include \"path.h\"\n #include \"tempfile.h\"\n #include \"sigchain.h\"\n-- \n2.41.0.162.gfafddb0af9-goog\n\n"},{"id":"478112","messageId":"20230606194843.2054314-5-calvinwan@google.com","threadId":"59685","inReplyTo":"20230606194720.2053551-1-calvinwan@google.com","subject":"[PATCH v7 5/7] object-name: move related functions to object-name","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-06-06T19:48:41Z","receivedAt":"2023-06-06T19:49:05Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"Move object-name-related functions from strbuf.[ch] to object-name.[ch]\nso that strbuf is focused on string manipulation routines with minimal\ndependencies.\n\ndir.h relied on the forward declration of the repository struct in\nstrbuf.h. Since that is removed in this patch, add the forward\ndeclaration to dir.h.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n dir.h         |  2 ++\n object-name.c | 15 +++++++++++++++\n object-name.h |  9 +++++++++\n pretty.c      |  1 +\n strbuf.c      | 16 ----------------\n strbuf.h      | 10 ----------\n 6 files changed, 27 insertions(+), 26 deletions(-)\n\ndiff --git a/dir.h b/dir.h\nindex 79b85a01ee..4d83febe9e 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -40,6 +40,8 @@\n  *\n  */\n \n+struct repository;\n+\n struct dir_entry {\n \tunsigned int len;\n \tchar name[FLEX_ARRAY]; /* more */\ndiff --git a/object-name.c b/object-name.c\nindex 6fc3fa595b..34e0f56703 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -768,6 +768,21 @@ static void find_abbrev_len_packed(struct min_abbrev_data *mad)\n \t\tfind_abbrev_len_for_pack(p, mad);\n }\n \n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len)\n+{\n+\tint r;\n+\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n+\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n+\tstrbuf_setlen(sb, sb->len + r);\n+}\n+\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len)\n+{\n+\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n+}\n+\n int repo_find_unique_abbrev_r(struct repository *r, char *hex,\n \t\t\t      const struct object_id *oid, int len)\n {\ndiff --git a/object-name.h b/object-name.h\nindex 1d63698f42..9ae5223071 100644\n--- a/object-name.h\n+++ b/object-name.h\n@@ -40,6 +40,15 @@ struct object_context {\n const char *repo_find_unique_abbrev(struct repository *r, const struct object_id *oid, int len);\n int repo_find_unique_abbrev_r(struct repository *r, char *hex, const struct object_id *oid, int len);\n \n+/**\n+ * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n+ * the strbuf `sb`.\n+ */\n+void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n+\t\t\t\t   const struct object_id *oid, int abbrev_len);\n+void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n+\t\t\t      int abbrev_len);\n+\n int repo_get_oid(struct repository *r, const char *str, struct object_id *oid);\n __attribute__((format (printf, 2, 3)))\n int get_oidf(struct object_id *oid, const char *fmt, ...);\ndiff --git a/pretty.c b/pretty.c\nindex 0bb938021b..78bac2d818 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -18,6 +18,7 @@\n #include \"gpg-interface.h\"\n #include \"trailer.h\"\n #include \"run-command.h\"\n+#include \"object-name.h\"\n \n /*\n  * The limit for formatting directives, which enable the caller to append\ndiff --git a/strbuf.c b/strbuf.c\nindex 5244029d91..80b7e051cd 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -3,7 +3,6 @@\n #include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n-#include \"object-name.h\"\n #include \"repository.h\"\n #include \"strbuf.h\"\n #include \"string-list.h\"\n@@ -1024,21 +1023,6 @@ void strbuf_addftime(struct strbuf *sb, const char *fmt, const struct tm *tm,\n \tstrbuf_setlen(sb, sb->len + len);\n }\n \n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len)\n-{\n-\tint r;\n-\tstrbuf_grow(sb, GIT_MAX_HEXSZ + 1);\n-\tr = repo_find_unique_abbrev_r(repo, sb->buf + sb->len, oid, abbrev_len);\n-\tstrbuf_setlen(sb, sb->len + r);\n-}\n-\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len)\n-{\n-\tstrbuf_repo_add_unique_abbrev(sb, the_repository, oid, abbrev_len);\n-}\n-\n /*\n  * Returns the length of a line, without trailing spaces.\n  *\ndiff --git a/strbuf.h b/strbuf.h\nindex 114ad0c024..5d97e27b99 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -616,16 +616,6 @@ void strbuf_add_separated_string_list(struct strbuf *str,\n  */\n void strbuf_list_free(struct strbuf **list);\n \n-/**\n- * Add the abbreviation, as generated by repo_find_unique_abbrev(), of `sha1` to\n- * the strbuf `sb`.\n- */\n-struct repository;\n-void strbuf_repo_add_unique_abbrev(struct strbuf *sb, struct repository *repo,\n-\t\t\t\t   const struct object_id *oid, int abbrev_len);\n-void strbuf_add_unique_abbrev(struct strbuf *sb, const struct object_id *oid,\n-\t\t\t      int abbrev_len);\n-\n /*\n  * Remove the filename from the provided path string. If the path\n  * contains a trailing separator, then the path is considered a directory\n-- \n2.41.0.162.gfafddb0af9-goog\n\n"},{"id":"478113","messageId":"20230606194843.2054314-4-calvinwan@google.com","threadId":"59685","inReplyTo":"20230606194720.2053551-1-calvinwan@google.com","subject":"[PATCH v7 4/7] credential-store: move related functions to credential-store file","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-06-06T19:48:40Z","receivedAt":"2023-06-06T19:49:07Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"is_rfc3986_unreserved() and is_rfc3986_reserved_or_unreserved() are only\ncalled from builtin/credential-store.c and they are only relevant to that\nfile so move those functions and make them static.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n builtin/credential-store.c | 19 +++++++++++++++++++\n strbuf.c                   | 19 -------------------\n strbuf.h                   |  3 ---\n 3 files changed, 19 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/credential-store.c b/builtin/credential-store.c\nindex 30c6ccf56c..5eea5bdb58 100644\n--- a/builtin/credential-store.c\n+++ b/builtin/credential-store.c\n@@ -74,6 +74,25 @@ static void rewrite_credential_file(const char *fn, struct credential *c,\n \t\tdie_errno(\"unable to write credential store\");\n }\n \n+static int is_rfc3986_unreserved(char ch)\n+{\n+\treturn isalnum(ch) ||\n+\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n+}\n+\n+static int is_rfc3986_reserved_or_unreserved(char ch)\n+{\n+\tif (is_rfc3986_unreserved(ch))\n+\t\treturn 1;\n+\tswitch (ch) {\n+\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n+\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n+\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\n+\n static void store_credential_file(const char *fn, struct credential *c)\n {\n \tstruct strbuf buf = STRBUF_INIT;\ndiff --git a/strbuf.c b/strbuf.c\nindex a2249ae7ed..5244029d91 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -810,25 +810,6 @@ void strbuf_addstr_xml_quoted(struct strbuf *buf, const char *s)\n \t}\n }\n \n-int is_rfc3986_reserved_or_unreserved(char ch)\n-{\n-\tif (is_rfc3986_unreserved(ch))\n-\t\treturn 1;\n-\tswitch (ch) {\n-\t\tcase '!': case '*': case '\\'': case '(': case ')': case ';':\n-\t\tcase ':': case '@': case '&': case '=': case '+': case '$':\n-\t\tcase ',': case '/': case '?': case '#': case '[': case ']':\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n-}\n-\n-int is_rfc3986_unreserved(char ch)\n-{\n-\treturn isalnum(ch) ||\n-\t\tch == '-' || ch == '_' || ch == '.' || ch == '~';\n-}\n-\n static void strbuf_add_urlencode(struct strbuf *sb, const char *s, size_t len,\n \t\t\t\t char_predicate allow_unencoded_fn)\n {\ndiff --git a/strbuf.h b/strbuf.h\nindex 207efb4f98..114ad0c024 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -690,9 +690,6 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name);\n \n typedef int (*char_predicate)(char ch);\n \n-int is_rfc3986_unreserved(char ch);\n-int is_rfc3986_reserved_or_unreserved(char ch);\n-\n void strbuf_addstr_urlencode(struct strbuf *sb, const char *name,\n \t\t\t     char_predicate allow_unencoded_fn);\n \n-- \n2.41.0.162.gfafddb0af9-goog\n\n"},{"id":"478114","messageId":"20230606194843.2054314-7-calvinwan@google.com","threadId":"59685","inReplyTo":"20230606194720.2053551-1-calvinwan@google.com","subject":"[PATCH v7 7/7] strbuf: remove global variable","fromName":"Calvin Wan","fromEmail":"calvinwan@google.com","sentAt":"2023-06-06T19:48:43Z","receivedAt":"2023-06-06T19:49:10Z","isPatch":true,"sender":{"key":"calvinwan@google.com","avatar":"https://avatars.githubusercontent.com/u/92547554?v=4"},"body":"As a library that only interacts with other primitives, strbuf should\nnot utilize the comment_line_char global variable within its\nfunctions. Therefore, add an additional parameter for functions that use\ncomment_line_char and refactor callers to pass it in instead.\nstrbuf_stripspace() removes the skip_comments boolean and checks if\ncomment_line_char is a non-NUL character to determine whether to skip\ncomments or not.\n\nSigned-off-by: Calvin Wan <calvinwan@google.com>\n---\n add-patch.c          | 12 +++++++-----\n builtin/am.c         |  2 +-\n builtin/branch.c     |  4 ++--\n builtin/commit.c     |  2 +-\n builtin/merge.c      | 10 ++++++----\n builtin/notes.c      | 16 +++++++++-------\n builtin/rebase.c     |  2 +-\n builtin/stripspace.c |  6 ++++--\n builtin/tag.c        |  9 ++++++---\n fmt-merge-msg.c      |  9 ++++++---\n gpg-interface.c      |  5 +++--\n rebase-interactive.c | 15 ++++++++-------\n sequencer.c          | 24 +++++++++++++++---------\n strbuf.c             | 18 ++++++++++--------\n strbuf.h             | 14 ++++++++------\n wt-status.c          |  6 +++---\n 16 files changed, 90 insertions(+), 64 deletions(-)\n\ndiff --git a/add-patch.c b/add-patch.c\nindex 8d770d203f..9702c1aabd 100644\n--- a/add-patch.c\n+++ b/add-patch.c\n@@ -1105,10 +1105,11 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \tsize_t i;\n \n \tstrbuf_reset(&s->buf);\n-\tstrbuf_commented_addf(&s->buf, _(\"Manual hunk edit mode -- see bottom for \"\n-\t\t\t\t      \"a quick guide.\\n\"));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n+\t\t\t      _(\"Manual hunk edit mode -- see bottom for \"\n+\t\t\t\t\"a quick guide.\\n\"));\n \trender_hunk(s, hunk, 0, 0, &s->buf);\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"---\\n\"\n \t\t\t\t\"To remove '%c' lines, make them ' ' lines \"\n \t\t\t\t\"(context).\\n\"\n@@ -1117,12 +1118,13 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)\n \t\t\t      s->mode->is_reverse ? '+' : '-',\n \t\t\t      s->mode->is_reverse ? '-' : '+',\n \t\t\t      comment_line_char);\n-\tstrbuf_commented_addf(&s->buf, \"%s\", _(s->mode->edit_hunk_hint));\n+\tstrbuf_commented_addf(&s->buf, comment_line_char, \"%s\",\n+\t\t\t      _(s->mode->edit_hunk_hint));\n \t/*\n \t * TRANSLATORS: 'it' refers to the patch mentioned in the previous\n \t * messages.\n \t */\n-\tstrbuf_commented_addf(&s->buf,\n+\tstrbuf_commented_addf(&s->buf, comment_line_char,\n \t\t\t      _(\"If it does not apply cleanly, you will be \"\n \t\t\t\t\"given an opportunity to\\n\"\n \t\t\t\t\"edit again.  If all lines of the hunk are \"\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 5c83f2e003..9ece2e3066 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -1283,7 +1283,7 @@ static int parse_mail(struct am_state *state, const char *mail)\n \n \tstrbuf_addstr(&msg, \"\\n\\n\");\n \tstrbuf_addbuf(&msg, &mi.log_message);\n-\tstrbuf_stripspace(&msg, 0);\n+\tstrbuf_stripspace(&msg, '\\0');\n \n \tassert(!state->author_name);\n \tstate->author_name = strbuf_detach(&author_name, NULL);\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex e6c2655af6..40a79e60f5 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -674,7 +674,7 @@ static int edit_branch_description(const char *branch_name)\n \texists = !read_branch_desc(&buf, branch_name);\n \tif (!buf.len || buf.buf[buf.len-1] != '\\n')\n \t\tstrbuf_addch(&buf, '\\n');\n-\tstrbuf_commented_addf(&buf,\n+\tstrbuf_commented_addf(&buf, comment_line_char,\n \t\t    _(\"Please edit the description for the branch\\n\"\n \t\t      \"  %s\\n\"\n \t\t      \"Lines starting with '%c' will be stripped.\\n\"),\n@@ -685,7 +685,7 @@ static int edit_branch_description(const char *branch_name)\n \t\tstrbuf_release(&buf);\n \t\treturn -1;\n \t}\n-\tstrbuf_stripspace(&buf, 1);\n+\tstrbuf_stripspace(&buf, comment_line_char);\n \n \tstrbuf_addf(&name, \"branch.%s.description\", branch_name);\n \tif (buf.len || exists)\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex e67c4be221..e002ebf070 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -893,7 +893,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,\n \ts->hints = 0;\n \n \tif (clean_message_contents)\n-\t\tstrbuf_stripspace(&sb, 0);\n+\t\tstrbuf_stripspace(&sb, '\\0');\n \n \tif (signoff)\n \t\tappend_signoff(&sb, ignore_non_trailer(sb.buf, sb.len), 0);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 8da3e46abb..1d14767c0c 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -879,13 +879,15 @@ static void prepare_to_commit(struct commit_list *remoteheads)\n \t\tstrbuf_addch(&msg, '\\n');\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {\n \t\t\twt_status_append_cut_line(&msg);\n-\t\t\tstrbuf_commented_addf(&msg, \"\\n\");\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char, \"\\n\");\n \t\t}\n-\t\tstrbuf_commented_addf(&msg, _(merge_editor_comment));\n+\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t      _(merge_editor_comment));\n \t\tif (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n-\t\t\tstrbuf_commented_addf(&msg, _(scissors_editor_comment));\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n+\t\t\t\t\t      _(scissors_editor_comment));\n \t\telse\n-\t\t\tstrbuf_commented_addf(&msg,\n+\t\t\tstrbuf_commented_addf(&msg, comment_line_char,\n \t\t\t\t_(no_scissors_editor_comment), comment_line_char);\n \t}\n \tif (signoff)\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex d5788352b6..3bad5b458b 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -11,6 +11,7 @@\n #include \"config.h\"\n #include \"builtin.h\"\n #include \"editor.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"notes.h\"\n@@ -157,7 +158,7 @@ static void write_commented_object(int fd, const struct object_id *object)\n \n \tif (strbuf_read(&buf, show.out, 0) < 0)\n \t\tdie_errno(_(\"could not read 'show' output\"));\n-\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_char);\n \twrite_or_die(fd, cbuf.buf, cbuf.len);\n \n \tstrbuf_release(&cbuf);\n@@ -185,9 +186,10 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\t\tcopy_obj_to_fd(fd, old_note);\n \n \t\tstrbuf_addch(&buf, '\\n');\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n-\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)));\n-\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"));\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),\n+\t\t\t\t\t   comment_line_char);\n+\t\tstrbuf_add_commented_lines(&buf, \"\\n\", strlen(\"\\n\"), comment_line_char);\n \t\twrite_or_die(fd, buf.buf, buf.len);\n \n \t\twrite_commented_object(fd, object);\n@@ -199,7 +201,7 @@ static void prepare_note_data(const struct object_id *object, struct note_data *\n \t\tif (launch_editor(d->edit_path, &d->buf, NULL)) {\n \t\t\tdie(_(\"please supply the note contents using either -m or -F option\"));\n \t\t}\n-\t\tstrbuf_stripspace(&d->buf, 1);\n+\t\tstrbuf_stripspace(&d->buf, comment_line_char);\n \t}\n }\n \n@@ -225,7 +227,7 @@ static int parse_msg_arg(const struct option *opt, const char *arg, int unset)\n \tif (d->buf.len)\n \t\tstrbuf_addch(&d->buf, '\\n');\n \tstrbuf_addstr(&d->buf, arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, '\\0');\n \n \td->given = 1;\n \treturn 0;\n@@ -244,7 +246,7 @@ static int parse_file_arg(const struct option *opt, const char *arg, int unset)\n \t\t\tdie_errno(_(\"cannot read '%s'\"), arg);\n \t} else if (strbuf_read_file(&d->buf, arg, 1024) < 0)\n \t\tdie_errno(_(\"could not open or read '%s'\"), arg);\n-\tstrbuf_stripspace(&d->buf, 0);\n+\tstrbuf_stripspace(&d->buf, '\\0');\n \n \td->given = 1;\n \treturn 0;\ndiff --git a/builtin/rebase.c b/builtin/rebase.c\nindex ace1d5e8d1..b1ba9fb05d 100644\n--- a/builtin/rebase.c\n+++ b/builtin/rebase.c\n@@ -209,7 +209,7 @@ static int edit_todo_file(unsigned flags)\n \tif (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)\n \t\treturn error_errno(_(\"could not read '%s'.\"), todo_file);\n \n-\tstrbuf_stripspace(&todo_list.buf, 1);\n+\tstrbuf_stripspace(&todo_list.buf, comment_line_char);\n \tres = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags);\n \tif (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,\n \t\t\t\t\t    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))\ndiff --git a/builtin/stripspace.c b/builtin/stripspace.c\nindex 9451eb69ff..1987752359 100644\n--- a/builtin/stripspace.c\n+++ b/builtin/stripspace.c\n@@ -1,6 +1,7 @@\n #include \"builtin.h\"\n #include \"cache.h\"\n #include \"config.h\"\n+#include \"environment.h\"\n #include \"gettext.h\"\n #include \"parse-options.h\"\n #include \"setup.h\"\n@@ -13,7 +14,7 @@ static void comment_lines(struct strbuf *buf)\n \tsize_t len;\n \n \tmsg = strbuf_detach(buf, &len);\n-\tstrbuf_add_commented_lines(buf, msg, len);\n+\tstrbuf_add_commented_lines(buf, msg, len, comment_line_char);\n \tfree(msg);\n }\n \n@@ -58,7 +59,8 @@ int cmd_stripspace(int argc, const char **argv, const char *prefix)\n \t\tdie_errno(\"could not read the input\");\n \n \tif (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)\n-\t\tstrbuf_stripspace(&buf, mode == STRIP_COMMENTS);\n+\t\tstrbuf_stripspace(&buf,\n+\t\t\t  mode == STRIP_COMMENTS ? comment_line_char : '\\0');\n \telse\n \t\tcomment_lines(&buf);\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex 1850a6a6fd..b79e0a88e6 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -311,9 +311,11 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n \t\t\tstrbuf_addch(&buf, '\\n');\n \t\t\tif (opt->cleanup_mode == CLEANUP_ALL)\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template), tag, comment_line_char);\n \t\t\telse\n-\t\t\t\tstrbuf_commented_addf(&buf, _(tag_template_nocleanup), tag, comment_line_char);\n+\t\t\t\tstrbuf_commented_addf(&buf, comment_line_char,\n+\t\t\t\t      _(tag_template_nocleanup), tag, comment_line_char);\n \t\t\twrite_or_die(fd, buf.buf, buf.len);\n \t\t\tstrbuf_release(&buf);\n \t\t}\n@@ -327,7 +329,8 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \t}\n \n \tif (opt->cleanup_mode != CLEANUP_NONE)\n-\t\tstrbuf_stripspace(buf, opt->cleanup_mode == CLEANUP_ALL);\n+\t\tstrbuf_stripspace(buf,\n+\t\t  opt->cleanup_mode == CLEANUP_ALL ? comment_line_char : '\\0');\n \n \tif (!opt->message_given && !buf->len)\n \t\tdie(_(\"no tag message?\"));\ndiff --git a/fmt-merge-msg.c b/fmt-merge-msg.c\nindex 5af0d4715b..5d15e2387d 100644\n--- a/fmt-merge-msg.c\n+++ b/fmt-merge-msg.c\n@@ -508,7 +508,8 @@ static void fmt_tag_signature(struct strbuf *tagbuf,\n \tstrbuf_complete_line(tagbuf);\n \tif (sig->len) {\n \t\tstrbuf_addch(tagbuf, '\\n');\n-\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len);\n+\t\tstrbuf_add_commented_lines(tagbuf, sig->buf, sig->len,\n+\t\t\t\t\t   comment_line_char);\n \t}\n }\n \n@@ -554,7 +555,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\t\tstrbuf_addch(&tagline, '\\n');\n \t\t\t\tstrbuf_add_commented_lines(&tagline,\n \t\t\t\t\t\torigins.items[first_tag].string,\n-\t\t\t\t\t\tstrlen(origins.items[first_tag].string));\n+\t\t\t\t\t\tstrlen(origins.items[first_tag].string),\n+\t\t\t\t\t\tcomment_line_char);\n \t\t\t\tstrbuf_insert(&tagbuf, 0, tagline.buf,\n \t\t\t\t\t      tagline.len);\n \t\t\t\tstrbuf_release(&tagline);\n@@ -562,7 +564,8 @@ static void fmt_merge_msg_sigs(struct strbuf *out)\n \t\t\tstrbuf_addch(&tagbuf, '\\n');\n \t\t\tstrbuf_add_commented_lines(&tagbuf,\n \t\t\t\t\torigins.items[i].string,\n-\t\t\t\t\tstrlen(origins.items[i].string));\n+\t\t\t\t\tstrlen(origins.items[i].string),\n+\t\t\t\t\tcomment_line_char);\n \t\t\tfmt_tag_signature(&tagbuf, &sig, buf, len);\n \t\t}\n \t\tstrbuf_release(&payload);\ndiff --git a/gpg-interface.c b/gpg-interface.c\nindex 19a3471a0b..6a3817bbca 100644\n--- a/gpg-interface.c\n+++ b/gpg-interface.c\n@@ -13,6 +13,7 @@\n #include \"tempfile.h\"\n #include \"alias.h\"\n #include \"wrapper.h\"\n+#include \"environment.h\"\n \n static int git_gpg_config(const char *, const char *, void *);\n \n@@ -586,8 +587,8 @@ static int verify_ssh_signed_buffer(struct signature_check *sigc,\n \t\t}\n \t}\n \n-\tstrbuf_stripspace(&ssh_keygen_out, 0);\n-\tstrbuf_stripspace(&ssh_keygen_err, 0);\n+\tstrbuf_stripspace(&ssh_keygen_out, '\\0');\n+\tstrbuf_stripspace(&ssh_keygen_err, '\\0');\n \t/* Add stderr outputs to show the user actual ssh-keygen errors */\n \tstrbuf_add(&ssh_keygen_out, ssh_principals_err.buf, ssh_principals_err.len);\n \tstrbuf_add(&ssh_keygen_out, ssh_keygen_err.buf, ssh_keygen_err.len);\ndiff --git a/rebase-interactive.c b/rebase-interactive.c\nindex 852a331318..f286404d4b 100644\n--- a/rebase-interactive.c\n+++ b/rebase-interactive.c\n@@ -72,13 +72,14 @@ void append_todo_help(int command_count,\n \n \tif (!edit_todo) {\n \t\tstrbuf_addch(buf, '\\n');\n-\t\tstrbuf_commented_addf(buf, Q_(\"Rebase %s onto %s (%d command)\",\n-\t\t\t\t\t      \"Rebase %s onto %s (%d commands)\",\n-\t\t\t\t\t      command_count),\n+\t\tstrbuf_commented_addf(buf, comment_line_char,\n+\t\t\t\t      Q_(\"Rebase %s onto %s (%d command)\",\n+\t\t\t\t\t \"Rebase %s onto %s (%d commands)\",\n+\t\t\t\t\t command_count),\n \t\t\t\t      shortrevisions, shortonto, command_count);\n \t}\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (get_missing_commit_check_level() == MISSING_COMMIT_CHECK_ERROR)\n \t\tmsg = _(\"\\nDo not remove any line. Use 'drop' \"\n@@ -87,7 +88,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nIf you remove a line here \"\n \t\t\t \"THAT COMMIT WILL BE LOST.\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n \n \tif (edit_todo)\n \t\tmsg = _(\"\\nYou are editing the todo file \"\n@@ -98,7 +99,7 @@ void append_todo_help(int command_count,\n \t\tmsg = _(\"\\nHowever, if you remove everything, \"\n \t\t\t\"the rebase will be aborted.\\n\\n\");\n \n-\tstrbuf_add_commented_lines(buf, msg, strlen(msg));\n+\tstrbuf_add_commented_lines(buf, msg, strlen(msg), comment_line_char);\n }\n \n int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n@@ -130,7 +131,7 @@ int edit_todo_list(struct repository *r, struct todo_list *todo_list,\n \tif (launch_sequence_editor(todo_file, &new_todo->buf, NULL))\n \t\treturn -2;\n \n-\tstrbuf_stripspace(&new_todo->buf, 1);\n+\tstrbuf_stripspace(&new_todo->buf, comment_line_char);\n \tif (initial && new_todo->buf.len == 0)\n \t\treturn -3;\n \ndiff --git a/sequencer.c b/sequencer.c\nindex bceb6abcb6..a8a70ab235 100644\n--- a/sequencer.c\n+++ b/sequencer.c\n@@ -660,11 +660,12 @@ void append_conflicts_hint(struct index_state *istate,\n \t}\n \n \tstrbuf_addch(msgbuf, '\\n');\n-\tstrbuf_commented_addf(msgbuf, \"Conflicts:\\n\");\n+\tstrbuf_commented_addf(msgbuf, comment_line_char, \"Conflicts:\\n\");\n \tfor (i = 0; i < istate->cache_nr;) {\n \t\tconst struct cache_entry *ce = istate->cache[i++];\n \t\tif (ce_stage(ce)) {\n-\t\t\tstrbuf_commented_addf(msgbuf, \"\\t%s\\n\", ce->name);\n+\t\t\tstrbuf_commented_addf(msgbuf, comment_line_char,\n+\t\t\t\t\t      \"\\t%s\\n\", ce->name);\n \t\t\twhile (i < istate->cache_nr &&\n \t\t\t       !strcmp(ce->name, istate->cache[i]->name))\n \t\t\t\ti++;\n@@ -1143,7 +1144,8 @@ void cleanup_message(struct strbuf *msgbuf,\n \t    cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)\n \t\tstrbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len));\n \tif (cleanup_mode != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msgbuf,\n+\t\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n }\n \n /*\n@@ -1174,7 +1176,8 @@ int template_untouched(const struct strbuf *sb, const char *template_file,\n \tif (!template_file || strbuf_read_file(&tmpl, template_file, 0) <= 0)\n \t\treturn 0;\n \n-\tstrbuf_stripspace(&tmpl, cleanup_mode == COMMIT_MSG_CLEANUP_ALL);\n+\tstrbuf_stripspace(&tmpl,\n+\t  cleanup_mode == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n \tif (!skip_prefix(sb->buf, tmpl.buf, &start))\n \t\tstart = sb->buf;\n \tstrbuf_release(&tmpl);\n@@ -1546,7 +1549,8 @@ static int try_to_commit(struct repository *r,\n \t\tcleanup = opts->default_msg_cleanup;\n \n \tif (cleanup != COMMIT_MSG_CLEANUP_NONE)\n-\t\tstrbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL);\n+\t\tstrbuf_stripspace(msg,\n+\t\t  cleanup == COMMIT_MSG_CLEANUP_ALL ? comment_line_char : '\\0');\n \tif ((flags & EDIT_MSG) && message_is_empty(msg, cleanup)) {\n \t\tres = 1; /* run 'git commit' to display error message */\n \t\tgoto out;\n@@ -1840,7 +1844,7 @@ static void add_commented_lines(struct strbuf *buf, const void *str, size_t len)\n \t\ts += count;\n \t\tlen -= count;\n \t}\n-\tstrbuf_add_commented_lines(buf, s, len);\n+\tstrbuf_add_commented_lines(buf, s, len, comment_line_char);\n }\n \n /* Does the current fixup chain contain a squash command? */\n@@ -1939,7 +1943,7 @@ static int append_squash_message(struct strbuf *buf, const char *body,\n \tstrbuf_addf(buf, _(nth_commit_msg_fmt),\n \t\t    ++opts->current_fixup_count + 1);\n \tstrbuf_addstr(buf, \"\\n\\n\");\n-\tstrbuf_add_commented_lines(buf, body, commented_len);\n+\tstrbuf_add_commented_lines(buf, body, commented_len, comment_line_char);\n \t/* buf->buf may be reallocated so store an offset into the buffer */\n \tfixup_off = buf->len;\n \tstrbuf_addstr(buf, body + commented_len);\n@@ -2029,7 +2033,8 @@ static int update_squash_messages(struct repository *r,\n \t\t\t      _(first_commit_msg_str));\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n \t\tif (is_fixup_flag(command, flag))\n-\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t\t   comment_line_char);\n \t\telse\n \t\t\tstrbuf_addstr(&buf, body);\n \n@@ -2048,7 +2053,8 @@ static int update_squash_messages(struct repository *r,\n \t\tstrbuf_addf(&buf, _(skip_nth_commit_msg_fmt),\n \t\t\t    ++opts->current_fixup_count + 1);\n \t\tstrbuf_addstr(&buf, \"\\n\\n\");\n-\t\tstrbuf_add_commented_lines(&buf, body, strlen(body));\n+\t\tstrbuf_add_commented_lines(&buf, body, strlen(body),\n+\t\t\t\t\t   comment_line_char);\n \t} else\n \t\treturn error(_(\"unknown command: %d\"), command);\n \trepo_unuse_commit_buffer(r, commit, message);\ndiff --git a/strbuf.c b/strbuf.c\nindex d5978fee4e..67e399b60a 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -1,6 +1,5 @@\n #include \"git-compat-util.h\"\n #include \"alloc.h\"\n-#include \"environment.h\"\n #include \"gettext.h\"\n #include \"hex.h\"\n #include \"strbuf.h\"\n@@ -362,7 +361,8 @@ static void add_lines(struct strbuf *out,\n \tstrbuf_complete_line(out);\n }\n \n-void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size)\n+void strbuf_add_commented_lines(struct strbuf *out, const char *buf,\n+\t\t\t\tsize_t size, char comment_line_char)\n {\n \tstatic char prefix1[3];\n \tstatic char prefix2[2];\n@@ -374,7 +374,8 @@ void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size\n \tadd_lines(out, prefix1, prefix2, buf, size);\n }\n \n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char,\n+\t\t\t   const char *fmt, ...)\n {\n \tva_list params;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -384,7 +385,7 @@ void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...)\n \tstrbuf_vaddf(&buf, fmt, params);\n \tva_end(params);\n \n-\tstrbuf_add_commented_lines(sb, buf.buf, buf.len);\n+\tstrbuf_add_commented_lines(sb, buf.buf, buf.len, comment_line_char);\n \tif (incomplete_line)\n \t\tsb->buf[--sb->len] = '\\0';\n \n@@ -1051,10 +1052,10 @@ static size_t cleanup(char *line, size_t len)\n  *\n  * If last line does not have a newline at the end, one is added.\n  *\n- * Enable skip_comments to skip every line starting with comment\n- * character.\n+ * Pass a non-NUL comment_line_char to skip every line starting\n+ * with it.\n  */\n-void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n+void strbuf_stripspace(struct strbuf *sb, char comment_line_char)\n {\n \tsize_t empties = 0;\n \tsize_t i, j, len, newlen;\n@@ -1067,7 +1068,8 @@ void strbuf_stripspace(struct strbuf *sb, int skip_comments)\n \t\teol = memchr(sb->buf + i, '\\n', sb->len - i);\n \t\tlen = eol ? eol - (sb->buf + i) + 1 : sb->len - i;\n \n-\t\tif (skip_comments && len && sb->buf[i] == comment_line_char) {\n+\t\tif (comment_line_char && len &&\n+\t\t    sb->buf[i] == comment_line_char) {\n \t\t\tnewlen = 0;\n \t\t\tcontinue;\n \t\t}\ndiff --git a/strbuf.h b/strbuf.h\nindex 5d97e27b99..da91c17257 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -291,7 +291,8 @@ void strbuf_splice(struct strbuf *sb, size_t pos, size_t len,\n  * by a comment character and a blank.\n  */\n void strbuf_add_commented_lines(struct strbuf *out,\n-\t\t\t\tconst char *buf, size_t size);\n+\t\t\t\tconst char *buf, size_t size,\n+\t\t\t\tchar comment_line_char);\n \n \n /**\n@@ -420,8 +421,8 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...);\n  * Add a formatted string prepended by a comment character and a\n  * blank to the buffer.\n  */\n-__attribute__((format (printf, 2, 3)))\n-void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);\n+__attribute__((format (printf, 3, 4)))\n+void strbuf_commented_addf(struct strbuf *sb, char comment_line_char, const char *fmt, ...);\n \n __attribute__((format (printf,2,0)))\n void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);\n@@ -543,10 +544,11 @@ int strbuf_getcwd(struct strbuf *sb);\n int strbuf_normalize_path(struct strbuf *sb);\n \n /**\n- * Strip whitespace from a buffer. The second parameter controls if\n- * comments are considered contents to be removed or not.\n+ * Strip whitespace from a buffer. If comment_line_char is non-NUL,\n+ * then lines beginning with that character are considered comments,\n+ * thus removed.\n  */\n-void strbuf_stripspace(struct strbuf *buf, int skip_comments);\n+void strbuf_stripspace(struct strbuf *buf, char comment_line_char);\n \n static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)\n {\ndiff --git a/wt-status.c b/wt-status.c\nindex 068b76ef6d..677465b10c 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -1024,7 +1024,7 @@ static void wt_longstatus_print_submodule_summary(struct wt_status *s, int uncom\n \tif (s->display_comment_prefix) {\n \t\tsize_t len;\n \t\tsummary_content = strbuf_detach(&summary, &len);\n-\t\tstrbuf_add_commented_lines(&summary, summary_content, len);\n+\t\tstrbuf_add_commented_lines(&summary, summary_content, len, comment_line_char);\n \t\tfree(summary_content);\n \t}\n \n@@ -1099,8 +1099,8 @@ void wt_status_append_cut_line(struct strbuf *buf)\n {\n \tconst char *explanation = _(\"Do not modify or remove the line above.\\nEverything below it will be ignored.\");\n \n-\tstrbuf_commented_addf(buf, \"%s\", cut_line);\n-\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation));\n+\tstrbuf_commented_addf(buf, comment_line_char, \"%s\", cut_line);\n+\tstrbuf_add_commented_lines(buf, explanation, strlen(explanation), comment_line_char);\n }\n \n void wt_status_add_cut_line(FILE *fp)\n-- \n2.41.0.162.gfafddb0af9-goog\n\n"}]}