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

[PATCH 4/5] string-list: optionally trim string pieces split by string_list_split()

From
Junio C Hamano <gitster@pobox.com>
Date
Jul 31, 2025, 06:39 UTC
Message-ID
<20250731063949.1601669-5-gitster@pobox.com>
In-Reply-To
<20250731063949.1601669-1-gitster@pobox.com>

Teach the unified split_string() to take an optional "flags" word, and define the first flag STRING_LIST_SPLIT_TRIM to cause the split pieces to be trimmed before they are placed in the string list.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 string-list.c                | 35 +++++++++++++++++---
 string-list.h                | 10 ++++++
 t/unit-tests/u-string-list.c | 64 ++++++++++++++++++++++++++++++++++++
 3 files changed, 104 insertions(+), 5 deletions(-)
diff --git a/string-list.c b/string-list.c
index 893e82be49..c6a3afb15a 100644
--- a/string-list.c
+++ b/string-list.c
@@ -278,11 +278,18 @@ void unsorted_string_list_delete_item(struct string_list *list, int i, int free_
 
 static void append_one(struct string_list *list,
 		       const char *p, const char *end,
-		       int in_place)
+		       int in_place, unsigned flags)
 {
 	if (!end)
 		end = p + strlen(p);
 
+	if ((flags & STRING_LIST_SPLIT_TRIM)) {
+		/* rtrim */
+		for (; p < end; end--)
+			if (!isspace(end[-1]))
+				break;
+	}
+
 	if (in_place) {
 		*((char *)end) = '\0';
 		string_list_append(list, p);
@@ -302,7 +309,7 @@ static void append_one(struct string_list *list,
  * 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 maxsplit, int in_place, unsigned flags)
 {
 	int count = 0;
 	const char *p = string;
@@ -315,13 +322,19 @@ static int split_string(struct string_list *list, const char *string, const char
 	for (;;) {
 		char *end;
 
+		if (flags & STRING_LIST_SPLIT_TRIM) {
+			/* ltrim */
+			while (*p && isspace(*p))
+				p++;
+		}
+
 		count++;
 		if (maxsplit >= 0 && count > maxsplit)
 			end = NULL;
 		else
 			end = strpbrk(p, delim);
 
-		append_one(list, p, end, in_place);
+		append_one(list, p, end, in_place, flags);
 
 		if (!end)
 			return count;
@@ -332,11 +345,23 @@ static int split_string(struct string_list *list, const char *string, const char
 int string_list_split(struct string_list *list, const char *string,
 		      const char *delim, int maxsplit)
 {
-	return split_string(list, string, delim, maxsplit, 0);
+	return split_string(list, string, delim, maxsplit, 0, 0);
 }
 
 int string_list_split_in_place(struct string_list *list, char *string,
 			       const char *delim, int maxsplit)
 {
-	return split_string(list, string, delim, maxsplit, 1);
+	return split_string(list, string, delim, maxsplit, 1, 0);
+}
+
+int string_list_split_f(struct string_list *list, const char *string,
+			const char *delim, int maxsplit, unsigned flags)
+{
+	return split_string(list, string, delim, maxsplit, 0, flags);
+}
+
+int string_list_split_in_place_f(struct string_list *list, char *string,
+			       const char *delim, int maxsplit, unsigned flags)
+{
+	return split_string(list, string, delim, maxsplit, 1, flags);
 }
diff --git a/string-list.h b/string-list.h
index 6c8650efde..ee9922af67 100644
--- a/string-list.h
+++ b/string-list.h
@@ -281,4 +281,14 @@ int string_list_split(struct string_list *list, const char *string,
  */
 int string_list_split_in_place(struct string_list *list, char *string,
 			       const char *delim, int maxsplit);
+
+/* trim() resulting string piece before adding it to the list */
+#define STRING_LIST_SPLIT_TRIM 01
+
+int string_list_split_f(struct string_list *, const char *string,
+			const char *delim, int maxsplit, unsigned flags);
+
+int string_list_split_in_place_f(struct string_list *, char *string,
+				 const char *delim, int maxsplit, unsigned flags);
+
 #endif /* STRING_LIST_H */
diff --git a/t/unit-tests/u-string-list.c b/t/unit-tests/u-string-list.c
index 150a5f505f..daa9307e45 100644
--- a/t/unit-tests/u-string-list.c
+++ b/t/unit-tests/u-string-list.c
@@ -63,6 +63,70 @@ static void t_string_list_split(const char *data, const char *delim, int maxspli
 	string_list_clear(&list, 0);
 }
 
+static void t_string_list_split_f(const char *data, const char *delim,
+				  int maxsplit, unsigned flags, ...)
+{
+	struct string_list expected_strings = STRING_LIST_INIT_DUP;
+	struct string_list list = STRING_LIST_INIT_DUP;
+	va_list ap;
+	int len;
+
+	va_start(ap, flags);
+	t_vcreate_string_list_dup(&expected_strings, 0, ap);
+	va_end(ap);
+
+	string_list_clear(&list, 0);
+	len = string_list_split_f(&list, data, delim, maxsplit, flags);
+	cl_assert_equal_i(len, expected_strings.nr);
+	t_string_list_equal(&list, &expected_strings);
+
+	string_list_clear(&expected_strings, 0);
+	string_list_clear(&list, 0);
+}
+
+void test_string_list__split_f(void)
+{
+	t_string_list_split_f("::foo:bar:baz:", ":", -1, 0,
+			      "", "", "foo", "bar", "baz", "", NULL);
+	t_string_list_split_f(" foo:bar : baz", ":", -1, STRING_LIST_SPLIT_TRIM,
+			      "foo", "bar", "baz", NULL);
+	t_string_list_split_f("  a  b c  ", " ", 1, STRING_LIST_SPLIT_TRIM,
+			      "a", "b c", NULL);
+}
+
+static void t_string_list_split_in_place_f(const char *data_, const char *delim,
+					   int maxsplit, unsigned flags, ...)
+{
+	struct string_list expected_strings = STRING_LIST_INIT_DUP;
+	struct string_list list = STRING_LIST_INIT_NODUP;
+	char *data = xstrdup(data_);
+	va_list ap;
+	int len;
+
+	va_start(ap, flags);
+	t_vcreate_string_list_dup(&expected_strings, 0, ap);
+	va_end(ap);
+
+	string_list_clear(&list, 0);
+	len = string_list_split_in_place_f(&list, data, delim, maxsplit, flags);
+	cl_assert_equal_i(len, expected_strings.nr);
+	t_string_list_equal(&list, &expected_strings);
+
+	free(data);
+	string_list_clear(&expected_strings, 0);
+	string_list_clear(&list, 0);
+}
+
+void test_string_list__split_in_place_f(void)
+{
+	t_string_list_split_in_place_f("::foo:bar:baz:", ":", -1, 0,
+				       "", "", "foo", "bar", "baz", "", NULL);
+	t_string_list_split_in_place_f(" foo:bar : baz", ":", -1, STRING_LIST_SPLIT_TRIM,
+				       "foo", "bar", "baz", NULL);
+	t_string_list_split_in_place_f("  a  b c  ", " ", 1, STRING_LIST_SPLIT_TRIM,
+				       "a", "b c", NULL);
+}
+
 void test_string_list__split(void)
 {
 	t_string_list_split("foo:bar:baz", ":", -1, "foo", "bar", "baz", NULL);
-- 
2.50.1-612-g4756c59422
Previous: Junio C HamanoNext: Junio C Hamano
Message 8 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.