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

[PATCH v4 3/7] string-list: unify string_list_split* functions

From
Junio C Hamano <gitster@pobox.com>
Date
Aug 3, 2025, 06:52 UTC
Message-ID
<20250803065223.3325111-4-gitster@pobox.com>
In-Reply-To
<20250803065223.3325111-1-gitster@pobox.com>

Thanks to the previous step, the only difference between these two related functions is that string_list_split() works on a string without modifying its contents (i.e. taking "const char *") and the resulting pieces of strings are their own copies in a string list, while string_list_split_in_place() works on a mutable string and the resulting pieces of strings come from the original string.

Consolidate their implementations into a single helper function, and make them a thin wrapper around it. We can later add an extra flags parameter to extend both of these functions by updating only the internal helper function.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 string-list.c | 96 ++++++++++++++++++++++++++++++---------------------
 1 file changed, 56 insertions(+), 40 deletions(-)
diff --git a/string-list.c b/string-list.c
index 2284a009cb..65b6ceb259 100644
--- a/string-list.c
+++ b/string-list.c
@@ -276,55 +276,71 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
 	list->nr--;
 }
 
-int string_list_split(struct string_list *list, const char *string,
-		      const char *delim, int maxsplit)
+/*
+ * append a substring [p..end] to list; return number of things it
+ * appended to the list.
+ */
+static int append_one(struct string_list *list,
+		      const char *p, const char *end,
+		      int in_place)
+{
+	if (!end)
+		end = p + strlen(p);
+
+	if (in_place) {
+		*((char *)end) = '\0';
+		string_list_append(list, p);
+	} else {
+		string_list_append_nodup(list, xmemdupz(p, end - p));
+	}
+	return 1;
+}
+
+/*
+ * Unfortunately this cannot become a public interface, as _in_place()
+ * wants to have "const char *string" while the other variant wants to
+ * have "char *string" for type safety.
+ *
+ * This accepts "const char *string" to allow both wrappers to use it;
+ * it internally casts away the constness when in_place is true by
+ * taking advantage of strpbrk() that takes a "const char *" arg and
+ * returns "char *" pointer into that const string.  Yucky but works ;-).
+ */
+static int split_string(struct string_list *list, const char *string, const char *delim,
+			int maxsplit, int in_place)
 {
 	int count = 0;
-	const char *p = string, *end;
+	const char *p = string;
+
+	if (in_place && list->strdup_strings)
+		BUG("string_list_split_in_place() called with strdup_strings");
+	else if (!in_place && !list->strdup_strings)
+		BUG("string_list_split() called without strdup_strings");
 
-	if (!list->strdup_strings)
-		BUG("internal error in string_list_split(): "
-		    "list->strdup_strings must be set");
 	for (;;) {
-		count++;
-		if (maxsplit >= 0 && count > maxsplit) {
-			string_list_append(list, p);
-			return count;
-		}
-		end = strpbrk(p, delim);
-		if (end) {
-			string_list_append_nodup(list, xmemdupz(p, end - p));
-			p = end + 1;
-		} else {
-			string_list_append(list, p);
+		char *end;
+
+		if (0 <= maxsplit && maxsplit <= count)
+			end = NULL;
+		else
+			end = strpbrk(p, delim);
+
+		count += append_one(list, p, end, in_place);
+
+		if (!end)
 			return count;
-		}
+		p = end + 1;
 	}
 }
 
+int string_list_split(struct string_list *list, const char *string,
+		      const char *delim, int maxsplit)
+{
+	return split_string(list, string, delim, maxsplit, 0);
+}
+
 int string_list_split_in_place(struct string_list *list, char *string,
 			       const char *delim, int maxsplit)
 {
-	int count = 0;
-	char *p = string, *end;
-
-	if (list->strdup_strings)
-		BUG("internal error in string_list_split_in_place(): "
-		    "list->strdup_strings must not be set");
-	for (;;) {
-		count++;
-		if (maxsplit >= 0 && count > maxsplit) {
-			string_list_append(list, p);
-			return count;
-		}
-		end = strpbrk(p, delim);
-		if (end) {
-			*end = '\0';
-			string_list_append(list, p);
-			p = end + 1;
-		} else {
-			string_list_append(list, p);
-			return count;
-		}
-	}
+	return split_string(list, string, delim, maxsplit, 1);
 }
-- 
2.50.1-633-g69dfdd50af
Previous: Junio C HamanoNext: Junio C Hamano
Message 54 of 72 in “string_list_split*() updates”
  1. 0/5 string_list_split*() updatesJunio C Hamano, Jul 31, 2025
  2. 1/5 string-list: report programming error with BUGJunio C Hamano, Jul 31, 2025
  3. Eric SunshineJul 31, 2025
  4. Junio C HamanoJul 31, 2025
  5. 2/5 string-list: align string_list_split() with its _in_place() counterpartJunio C Hamano, Jul 31, 2025
  6. Eric SunshineJul 31, 2025
  7. 3/5 string-list: unify string_list_split* functionsJunio C Hamano, Jul 31, 2025
  8. 4/5 string-list: optionally trim string pieces split by string_list_split()Junio C Hamano, Jul 31, 2025
  9. 5/5 diff: simplify parsing of diff.colormovedwsJunio C Hamano, Jul 31, 2025
  10. Eric SunshineJul 31, 2025
  11. 0/7 string_list_split*() updatesJunio C Hamano, Jul 31, 2025
  12. 1/7 string-list: report programming error with BUGJunio C Hamano, Jul 31, 2025
  13. 2/7 string-list: align string_list_split() with its _in_place() counterpartJunio C Hamano, Jul 31, 2025
  14. shejialuoAug 1, 2025
  15. Junio C HamanoAug 1, 2025
  16. shejialuoAug 1, 2025
  17. Junio C HamanoAug 1, 2025
  18. 3/7 string-list: unify string_list_split* functionsJunio C Hamano, Jul 31, 2025
  19. shejialuoAug 1, 2025
  20. 4/7 string-list: optionally trim string pieces split by string_list_split*()Junio C Hamano, Jul 31, 2025
  21. shejialuoAug 1, 2025
  22. Junio C HamanoAug 1, 2025
  23. shejialuoAug 1, 2025
  24. Junio C HamanoAug 1, 2025
  25. shejialuoAug 2, 2025
  26. Patrick SteinhardtAug 1, 2025
  27. Junio C HamanoAug 1, 2025
  28. 5/7 diff: simplify parsing of diff.colormovedwsJunio C Hamano, Jul 31, 2025
  29. Patrick SteinhardtAug 1, 2025
  30. 6/7 string-list: optionally omit empty string pieces in string_list_split*()Junio C Hamano, Jul 31, 2025
  31. Eric SunshineJul 31, 2025
  32. shejialuoAug 1, 2025
  33. Patrick SteinhardtAug 1, 2025
  34. Junio C HamanoAug 1, 2025
  35. 7/7 string-list: split-then-remove-empty can be done while splittingJunio C Hamano, Jul 31, 2025
  36. Patrick SteinhardtAug 1, 2025
  37. 0/7 string_list_split*() updatesJunio C Hamano, Aug 1, 2025
  38. 1/7 string-list: report programming error with BUGJunio C Hamano, Aug 1, 2025
  39. 2/7 string-list: align string_list_split() with its _in_place() counterpartJunio C Hamano, Aug 1, 2025
  40. Jeff KingAug 2, 2025
  41. Junio C HamanoAug 2, 2025
  42. Jeff KingAug 2, 2025
  43. 3/7 string-list: unify string_list_split* functionsJunio C Hamano, Aug 1, 2025
  44. 4/7 string-list: optionally trim string pieces split by string_list_split*()Junio C Hamano, Aug 1, 2025
  45. Jeff KingAug 2, 2025
  46. Junio C HamanoAug 2, 2025
  47. Jeff KingAug 2, 2025
  48. 5/7 diff: simplify parsing of diff.colormovedwsJunio C Hamano, Aug 1, 2025
  49. 6/7 string-list: optionally omit empty string pieces in string_list_split*()Junio C Hamano, Aug 1, 2025
  50. 7/7 string-list: split-then-remove-empty can be done while splittingJunio C Hamano, Aug 1, 2025
  51. 0/7 string_list_split*() updatesJunio C Hamano, Aug 3, 2025
  52. 1/7 string-list: report programming error with BUGJunio C Hamano, Aug 3, 2025
  53. 2/7 string-list: align string_list_split() with its _in_place() counterpartJunio C Hamano, Aug 3, 2025
  54. 3/7 string-list: unify string_list_split* functionsJunio C Hamano, Aug 3, 2025
  55. 4/7 string-list: optionally trim string pieces split by string_list_split*()Junio C Hamano, Aug 3, 2025
  56. 5/7 diff: simplify parsing of diff.colormovedwsJunio C Hamano, Aug 3, 2025
  57. 6/7 string-list: optionally omit empty string pieces in string_list_split*()Junio C Hamano, Aug 3, 2025
  58. 7/7 string-list: split-then-remove-empty can be done while splittingJunio C Hamano, Aug 3, 2025
  59. Patrick SteinhardtAug 4, 2025
  60. 00/12 do not overuse strbuf_split*()Junio C Hamano, Aug 3, 2025
  61. 01/12 wt-status: avoid strbuf_split*()Junio C Hamano, Aug 3, 2025
  62. 02/12 clean: do not pass strbuf by valueJunio C Hamano, Aug 3, 2025
  63. 03/12 clean: do not use strbuf_split*() [part 1]Junio C Hamano, Aug 3, 2025
  64. 04/12 clean: do not pass the whole structure when it is not necessaryJunio C Hamano, Aug 3, 2025
  65. 05/12 clean: do not use strbuf_split*() [part 2]Junio C Hamano, Aug 3, 2025
  66. 06/12 merge-tree: do not use strbuf_split*()Junio C Hamano, Aug 3, 2025
  67. 07/12 notes: do not use strbuf_split*()Junio C Hamano, Aug 3, 2025
  68. 08/12 config: do not use strbuf_split()Junio C Hamano, Aug 3, 2025
  69. 09/12 environment: do not use strbuf_split*()Junio C Hamano, Aug 3, 2025
  70. 10/12 sub-process: do not use strbuf_split*()Junio C Hamano, Aug 3, 2025
  71. 11/12 trace2: trim_trailing_newline followed by trim is a no-opJunio C Hamano, Aug 3, 2025
  72. 12/12 trace2: do not use strbuf_split*()Junio C Hamano, Aug 3, 2025

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

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