diff options
-rw-r--r-- | src/core/wee-string.c | 135 | ||||
-rw-r--r-- | src/plugins/trigger/trigger.c | 2 | ||||
-rw-r--r-- | tests/unit/core/test-core-string.cpp | 98 |
3 files changed, 172 insertions, 63 deletions
diff --git a/src/core/wee-string.c b/src/core/wee-string.c index 04308a451..e75b80400 100644 --- a/src/core/wee-string.c +++ b/src/core/wee-string.c @@ -1795,11 +1795,24 @@ string_replace_regex (const char *string, void *regex, const char *replace, * string_split_shared instead). * * According to keep_eol value: - * 0: standard split - * 1: each argument contains the argument and all the following arguments - * 2: same as 1, and separator is kept at the end of string. + * -1: standard split, keep empty items: don't collapse several separators + * and items at the beginning/end of string are returned if the string + * starts and/or ends with a separator + * 0: standard split, ignore empty items: collapse several separators + * and strip separators at the beginning/end of string before processing + * 1: same as 0 and each argument contains the argument and all the + * following arguments + * 2: same as 1 and separator is kept at the end of string. * * Examples: + * string_split ("abc de fghi ", " ", -1, 0, &argc) + * ==> array[0] == "abc" + * array[1] == "de" + * array[2] == "" + * array[3] == "fghi" + * array[4] == "" + * array[5] == NULL + * argc == 5 * string_split ("abc de fghi ", " ", 0, 0, &argc) * ==> array[0] == "abc" * array[1] == "de" @@ -1824,7 +1837,7 @@ char ** string_split_internal (const char *string, const char *separators, int keep_eol, int num_items_max, int *num_items, int shared) { - int i, j, n_items; + int i, j, count_items; char *string2, **array; char *ptr, *ptr1, *ptr2; const char *str_shared; @@ -1835,7 +1848,10 @@ string_split_internal (const char *string, const char *separators, int keep_eol, if (!string || !string[0] || !separators || !separators[0]) return NULL; - string2 = string_strip (string, 1, (keep_eol == 2) ? 0 : 1, separators); + string2 = string_strip (string, + (keep_eol != -1) ? 1 : 0, + ((keep_eol == 0) || (keep_eol == 1)) ? 1 : 0, + separators); if (!string2) return NULL; if (!string2[0]) @@ -1849,38 +1865,51 @@ string_split_internal (const char *string, const char *separators, int keep_eol, i = 1; while ((ptr = strpbrk (ptr, separators))) { - while (ptr[0] && strchr (separators, ptr[0])) + if (keep_eol == -1) { ptr++; - } - if (ptr[0]) i++; + } + else + { + while (ptr[0] && strchr (separators, ptr[0])) + { + ptr++; + } + if (ptr[0]) + i++; + } } - n_items = i; + count_items = i; - if ((num_items_max != 0) && (n_items > num_items_max)) - n_items = num_items_max; + if ((num_items_max != 0) && (count_items > num_items_max)) + count_items = num_items_max; - array = malloc ((n_items + 1) * sizeof (array[0])); + array = malloc ((count_items + 1) * sizeof (array[0])); if (!array) { free (string2); return NULL; } - for (i = 0; i < n_items + 1; i++) + for (i = 0; i < count_items + 1; i++) { array[i] = NULL; } ptr1 = string2; - for (i = 0; i < n_items; i++) + for (i = 0; i < count_items; i++) { - while (ptr1[0] && strchr (separators, ptr1[0])) + if (keep_eol != -1) { - ptr1++; + /* skip separators to find the beginning of item */ + while (ptr1[0] && strchr (separators, ptr1[0])) + { + ptr1++; + } } - if (i == (n_items - 1)) + /* search the end of item */ + if (i == (count_items - 1)) { ptr2 = strpbrk (ptr1, separators); if (!ptr2) @@ -1900,78 +1929,45 @@ string_split_internal (const char *string, const char *separators, int keep_eol, } } - if ((ptr1 == NULL) || (ptr2 == NULL)) + if (!ptr1 || !ptr2) { array[i] = NULL; } else { - if (ptr2 - ptr1 > 0) + if (ptr2 > ptr1) { - if (keep_eol) + if ((keep_eol == 1) || (keep_eol == 2)) { array[i] = (shared) ? (char *)string_shared_get (ptr1) : strdup (ptr1); if (!array[i]) - { - for (j = 0; j < n_items; j++) - { - if (array[j]) - { - if (shared) - string_shared_free (array[j]); - else - free (array[j]); - } - } - free (array); - free (string2); - return NULL; - } + goto error; } else { array[i] = malloc (ptr2 - ptr1 + 1); if (!array[i]) - { - for (j = 0; j < n_items; j++) - { - if (array[j]) - { - if (shared) - string_shared_free (array[j]); - else - free (array[j]); - } - } - free (array); - free (string2); - return NULL; - } + goto error; strncpy (array[i], ptr1, ptr2 - ptr1); array[i][ptr2 - ptr1] = '\0'; if (shared) { str_shared = string_shared_get (array[i]); if (!str_shared) - { - for (j = 0; j < n_items; j++) - { - if (array[j]) - string_shared_free (array[j]); - } - free (array); - free (string2); - return NULL; - } + goto error; free (array[i]); array[i] = (char *)str_shared; } } - ptr1 = ++ptr2; + if ((keep_eol == -1) && strchr (separators, ptr2[0])) + ptr2++; + ptr1 = ptr2; } else { - array[i] = NULL; + array[i] = (shared) ? (char *)string_shared_get ("") : strdup (""); + if (ptr1[0] != '\0') + ptr1++; } } } @@ -1983,6 +1979,21 @@ string_split_internal (const char *string, const char *separators, int keep_eol, free (string2); return array; + +error: + for (j = 0; j < count_items; j++) + { + if (array[j]) + { + if (shared) + string_shared_free (array[j]); + else + free (array[j]); + } + } + free (array); + free (string2); + return NULL; } /* diff --git a/src/plugins/trigger/trigger.c b/src/plugins/trigger/trigger.c index 85864253f..a0392afdf 100644 --- a/src/plugins/trigger/trigger.c +++ b/src/plugins/trigger/trigger.c @@ -274,7 +274,7 @@ trigger_hook (struct t_trigger *trigger) trigger_unhook (trigger); argv = weechat_string_split (weechat_config_string (trigger->options[TRIGGER_OPTION_ARGUMENTS]), - ";", 0, 0, &argc); + ";", -1, 0, &argc); argv_eol = weechat_string_split (weechat_config_string (trigger->options[TRIGGER_OPTION_ARGUMENTS]), ";", 1, 0, NULL); diff --git a/tests/unit/core/test-core-string.cpp b/tests/unit/core/test-core-string.cpp index 1ccb2fe65..c11d63c36 100644 --- a/tests/unit/core/test-core-string.cpp +++ b/tests/unit/core/test-core-string.cpp @@ -1036,6 +1036,17 @@ TEST(CoreString, Split) /* standard split */ argc = -1; + argv = string_split ("abc de fghi", " ", 0, 0, &argc); + LONGS_EQUAL(3, argc); + CHECK(argv); + STRCMP_EQUAL("abc", argv[0]); + STRCMP_EQUAL("de", argv[1]); + STRCMP_EQUAL("fghi", argv[2]); + POINTERS_EQUAL(NULL, argv[3]); + string_free_split (argv); + + /* standard split */ + argc = -1; argv = string_split (" abc de fghi ", " ", 0, 0, &argc); LONGS_EQUAL(3, argc); CHECK(argv); @@ -1096,6 +1107,93 @@ TEST(CoreString, Split) STRCMP_EQUAL("de fghi ", argv[1]); POINTERS_EQUAL(NULL, argv[2]); string_free_split (argv); + + /* standard split with comma separator */ + argc = -1; + argv = string_split ("abc,de,fghi", ",", 0, 0, &argc); + LONGS_EQUAL(3, argc); + CHECK(argv); + STRCMP_EQUAL("abc", argv[0]); + STRCMP_EQUAL("de", argv[1]); + STRCMP_EQUAL("fghi", argv[2]); + POINTERS_EQUAL(NULL, argv[3]); + string_free_split (argv); + + /* standard split with comma separator and empty item (ignore this item) */ + argc = -1; + argv = string_split ("abc,,fghi", ",", 0, 0, &argc); + LONGS_EQUAL(2, argc); + CHECK(argv); + STRCMP_EQUAL("abc", argv[0]); + STRCMP_EQUAL("fghi", argv[1]); + POINTERS_EQUAL(NULL, argv[2]); + string_free_split (argv); + + /* standard split with comma separtor and empty item (keep this item) */ + argc = -1; + argv = string_split ("abc,,fghi", ",", -1, 0, &argc); + LONGS_EQUAL(3, argc); + CHECK(argv); + STRCMP_EQUAL("abc", argv[0]); + STRCMP_EQUAL("", argv[1]); + STRCMP_EQUAL("fghi", argv[2]); + POINTERS_EQUAL(NULL, argv[3]); + string_free_split (argv); + + /* standard split with comma separtor and empty items (keep them) */ + argc = -1; + argv = string_split (",abc,,fghi,", ",", -1, 0, &argc); + LONGS_EQUAL(5, argc); + CHECK(argv); + STRCMP_EQUAL("", argv[0]); + STRCMP_EQUAL("abc", argv[1]); + STRCMP_EQUAL("", argv[2]); + STRCMP_EQUAL("fghi", argv[3]); + STRCMP_EQUAL("", argv[4]); + POINTERS_EQUAL(NULL, argv[5]); + string_free_split (argv); + + /* + * standard split with comma separtor and empty items (keep them), + * max 2 items + */ + argc = -1; + argv = string_split (",abc,,fghi,", ",", -1, 2, &argc); + LONGS_EQUAL(2, argc); + CHECK(argv); + STRCMP_EQUAL("", argv[0]); + STRCMP_EQUAL("abc", argv[1]); + POINTERS_EQUAL(NULL, argv[2]); + string_free_split (argv); + + /* + * standard split with comma separtor and empty items (keep them), + * max 3 items + */ + argc = -1; + argv = string_split (",abc,,fghi,", ",", -1, 3, &argc); + LONGS_EQUAL(3, argc); + CHECK(argv); + STRCMP_EQUAL("", argv[0]); + STRCMP_EQUAL("abc", argv[1]); + STRCMP_EQUAL("", argv[2]); + POINTERS_EQUAL(NULL, argv[3]); + string_free_split (argv); + + /* + * standard split with comma separtor and empty items (keep them), + * max 4 items + */ + argc = -1; + argv = string_split (",abc,,fghi,", ",", -1, 4, &argc); + LONGS_EQUAL(4, argc); + CHECK(argv); + STRCMP_EQUAL("", argv[0]); + STRCMP_EQUAL("abc", argv[1]); + STRCMP_EQUAL("", argv[2]); + STRCMP_EQUAL("fghi", argv[3]); + POINTERS_EQUAL(NULL, argv[4]); + string_free_split (argv); } /* |