diff --git a/common/stringhelp.c b/common/stringhelp.c index 8b47a1c7b..0e96c9e54 100644 --- a/common/stringhelp.c +++ b/common/stringhelp.c @@ -1329,6 +1329,44 @@ strtokenize (const char *string, const char *delim) } +/* Split a string into space delimited fields and remove leading and + * trailing spaces from each field. A pointer to each field is stored + * in ARRAY. Stop splitting at ARRAYSIZE fields. The function + * modifies STRING. The number of parsed fields is returned. + * Example: + * + * char *fields[2]; + * if (split_fields (string, fields, DIM (fields)) < 2) + * return // Not enough args. + * foo (fields[0]); + * foo (fields[1]); + */ +int +split_fields (char *string, char **array, int arraysize) +{ + int n = 0; + char *p, *pend; + + for (p = string; *p == ' '; p++) + ; + do + { + if (n == arraysize) + break; + array[n++] = p; + pend = strchr (p, ' '); + if (!pend) + break; + *pend++ = 0; + for (p = pend; *p == ' '; p++) + ; + } + while (*p); + + return n; +} + + /* Version number parsing. */ diff --git a/common/stringhelp.h b/common/stringhelp.h index d9225a3bb..b6f4167f7 100644 --- a/common/stringhelp.h +++ b/common/stringhelp.h @@ -148,6 +148,10 @@ char **strsplit (char *string, char delim, char replacement, int *count); /* Tokenize STRING using the set of delimiters in DELIM. */ char **strtokenize (const char *string, const char *delim); +/* Split STRING into space delimited fields and store them in the + * provided ARRAY. */ +int split_fields (char *string, char **array, int arraysize); + /* Return True if MYVERSION is greater or equal than REQ_VERSION. */ int compare_version_strings (const char *my_version, const char *req_version); diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c index b4a41ac39..db0e811d7 100644 --- a/common/t-stringhelp.c +++ b/common/t-stringhelp.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef HAVE_PWD_H # include #endif @@ -676,6 +677,82 @@ test_strtokenize (void) } } + +static void +test_split_fields (void) +{ + struct { + const char *s; + int nfields; + const char *fields_expected[10]; + } tv[] = { + { + "a bc cde fghi jklmn foo ", 6, + { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL } + }, + { + " a bc def ", 2, + { "a", "bc", "def", NULL } + }, + { + " a bc def ", 3, + { "a", "bc", "def", NULL } + }, + { + " a bc def ", 4, + { "a", "bc", "def", NULL } + }, + { + "", 0, + { NULL } + } + }; + + int tidx; + char *fields[10]; + int field_count_expected, nfields, field_count, i; + char *s2; + + for (tidx = 0; tidx < DIM(tv); tidx++) + { + nfields = tv[tidx].nfields; + assert (nfields <= DIM (fields)); + + /* Count the fields. */ + for (field_count_expected = 0; + tv[tidx].fields_expected[field_count_expected]; + field_count_expected ++) + ; + if (field_count_expected > nfields) + field_count_expected = nfields; + + /* We need to copy s since split_fields modifies in place. */ + s2 = xstrdup (tv[tidx].s); + field_count = split_fields (s2, fields, nfields); + + if (field_count != field_count_expected) + { + printf ("%s: tidx %d: expected %d, got %d\n", + __func__, tidx, i, field_count_expected, field_count); + fail (tidx * 1000); + } + else + { + for (i = 0; i < field_count_expected; i ++) + if (strcmp (tv[tidx].fields_expected[i], fields[i])) + { + printf ("%s: tidx %d, field %d: expected '%s', got '%s'\n", + __func__, + tidx, i, tv[tidx].fields_expected[i], fields[i]); + fail (tidx * 1000 + i + 1); + } + } + + xfree (s2); + } +} + + static char * stresc (char *s) { @@ -887,6 +964,7 @@ main (int argc, char **argv) test_make_absfilename_try (); test_strsplit (); test_strtokenize (); + test_split_fields (); test_compare_version_strings (); test_format_text ();