mirror of
git://git.gnupg.org/gnupg.git
synced 2024-11-10 21:38:50 +01:00
common: New function tokenize_to_strlist.
* common/strlist.c (append_to_strlist_try): Factor code out to ...
(do_append_to_strlist): new.
(tokenize_to_strlist): New.
* common/t-strlist.c (test_tokenize_to_strlist): New.
(cherry picked from commit d2dca58338
)
This commit is contained in:
parent
6551281ca3
commit
28dd05a079
118
common/strlist.c
118
common/strlist.c
@ -1,6 +1,6 @@
|
|||||||
/* strlist.c - string helpers
|
/* strlist.c - string helpers
|
||||||
* Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
|
* Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 2015 g10 Code GmbH
|
* Copyright (C) 2015, 2024 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -27,6 +27,7 @@
|
|||||||
* You should have received a copies of the GNU General Public License
|
* You should have received a copies of the GNU General Public License
|
||||||
* and the GNU Lesser General Public License along with this program;
|
* and the GNU Lesser General Public License along with this program;
|
||||||
* if not, see <https://www.gnu.org/licenses/>.
|
* if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@ -134,27 +135,39 @@ append_to_strlist( strlist_t *list, const char *string )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Core of append_to_strlist_try which take the length of the string.
|
||||||
|
* Return the item added to the end of the list. Or NULL in case of
|
||||||
|
* an error. */
|
||||||
|
static strlist_t
|
||||||
|
do_append_to_strlist (strlist_t *list, const char *string, size_t stringlen)
|
||||||
|
{
|
||||||
|
strlist_t r, sl;
|
||||||
|
|
||||||
|
sl = xtrymalloc (sizeof *sl + stringlen);
|
||||||
|
if (!sl)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sl->flags = 0;
|
||||||
|
memcpy (sl->d, string, stringlen);
|
||||||
|
sl->d[stringlen] = 0;
|
||||||
|
sl->next = NULL;
|
||||||
|
if (!*list)
|
||||||
|
*list = sl;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (r = *list; r->next; r = r->next)
|
||||||
|
;
|
||||||
|
r->next = sl;
|
||||||
|
}
|
||||||
|
return sl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Add STRING to the LIST at the end. */
|
/* Add STRING to the LIST at the end. */
|
||||||
strlist_t
|
strlist_t
|
||||||
append_to_strlist_try (strlist_t *list, const char *string)
|
append_to_strlist_try (strlist_t *list, const char *string)
|
||||||
{
|
{
|
||||||
strlist_t r, sl;
|
return do_append_to_strlist (list, string, strlen (string));
|
||||||
|
|
||||||
sl = xtrymalloc( sizeof *sl + strlen(string));
|
|
||||||
if (sl == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
sl->flags = 0;
|
|
||||||
strcpy(sl->d, string);
|
|
||||||
sl->next = NULL;
|
|
||||||
if( !*list )
|
|
||||||
*list = sl;
|
|
||||||
else {
|
|
||||||
for( r = *list; r->next; r = r->next )
|
|
||||||
;
|
|
||||||
r->next = sl;
|
|
||||||
}
|
|
||||||
return sl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -175,6 +188,75 @@ append_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Tokenize STRING using the delimiters from DELIM and append each
|
||||||
|
* token to the string list LIST. On success a pinter into LIST with
|
||||||
|
* the first new token is returned. Returns NULL on error and sets
|
||||||
|
* ERRNO. Take care, an error with ENOENT set mean that no tokens
|
||||||
|
* were found in STRING. */
|
||||||
|
strlist_t
|
||||||
|
tokenize_to_strlist (strlist_t *list, const char *string, const char *delim)
|
||||||
|
{
|
||||||
|
const char *s, *se;
|
||||||
|
size_t n;
|
||||||
|
strlist_t newlist = NULL;
|
||||||
|
strlist_t tail;
|
||||||
|
|
||||||
|
s = string;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
se = strpbrk (s, delim);
|
||||||
|
if (se)
|
||||||
|
n = se - s;
|
||||||
|
else
|
||||||
|
n = strlen (s);
|
||||||
|
if (!n)
|
||||||
|
continue; /* Skip empty string. */
|
||||||
|
tail = do_append_to_strlist (&newlist, s, n);
|
||||||
|
if (!tail)
|
||||||
|
{
|
||||||
|
free_strlist (newlist);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
trim_spaces (tail->d);
|
||||||
|
if (!*tail->d) /* Remove new but empty item from the list. */
|
||||||
|
{
|
||||||
|
tail = strlist_prev (newlist, tail);
|
||||||
|
if (tail)
|
||||||
|
{
|
||||||
|
free_strlist (tail->next);
|
||||||
|
tail->next = NULL;
|
||||||
|
}
|
||||||
|
else if (newlist)
|
||||||
|
{
|
||||||
|
free_strlist (newlist);
|
||||||
|
newlist = NULL;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (se && (s = se + 1));
|
||||||
|
|
||||||
|
if (!newlist)
|
||||||
|
{
|
||||||
|
/* Not items found. Indicate this by returnning NULL with errno
|
||||||
|
* set to ENOENT. */
|
||||||
|
gpg_err_set_errno (ENOENT);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Append NEWLIST to LIST. */
|
||||||
|
if (!*list)
|
||||||
|
*list = newlist;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (tail = *list; tail->next; tail = tail->next)
|
||||||
|
;
|
||||||
|
tail->next = newlist;
|
||||||
|
}
|
||||||
|
return newlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a copy of LIST. This function terminates the process on
|
/* Return a copy of LIST. This function terminates the process on
|
||||||
memory shortage.*/
|
memory shortage.*/
|
||||||
strlist_t
|
strlist_t
|
||||||
|
@ -52,6 +52,9 @@ strlist_t append_to_strlist_try (strlist_t *list, const char *string);
|
|||||||
strlist_t append_to_strlist2 (strlist_t *list, const char *string,
|
strlist_t append_to_strlist2 (strlist_t *list, const char *string,
|
||||||
int is_utf8);
|
int is_utf8);
|
||||||
|
|
||||||
|
strlist_t tokenize_to_strlist (strlist_t *list,
|
||||||
|
const char *string, const char *delim);
|
||||||
|
|
||||||
strlist_t strlist_copy (strlist_t list);
|
strlist_t strlist_copy (strlist_t list);
|
||||||
|
|
||||||
strlist_t strlist_prev (strlist_t head, strlist_t node);
|
strlist_t strlist_prev (strlist_t head, strlist_t node);
|
||||||
|
@ -72,6 +72,194 @@ test_strlist_rev (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_tokenize_to_strlist (void)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
const char *s;
|
||||||
|
const char *delim;
|
||||||
|
int error_expected;
|
||||||
|
const char *items_expected[10];
|
||||||
|
} tv[] = {
|
||||||
|
{
|
||||||
|
"", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a", ":",
|
||||||
|
0, { "a", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
":", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"::", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:b:c", ":",
|
||||||
|
0, { "a", "b", "c", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:b:", ":",
|
||||||
|
0, { "a", "b", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:b", ":",
|
||||||
|
0, { "a", "b", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aa:b:cd", ":",
|
||||||
|
0, { "aa", "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aa::b:cd", ":",
|
||||||
|
0, { "aa", "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"::b:cd", ":",
|
||||||
|
0, { "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aa: : b:cd ", ":",
|
||||||
|
0, { "aa", "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" aa: : b: cd ", ":",
|
||||||
|
0, { "aa", "b", "cd", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" :", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" : ", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
": ", ":",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
": x ", ":",
|
||||||
|
0, { "x", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:bc:cde:fghi:jklmn::foo:", ":",
|
||||||
|
0, { "a", "bc", "cde", "fghi", "jklmn", "foo", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
",a,bc,,def,", ",",
|
||||||
|
0, { "a", "bc", "def", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" a ", " ",
|
||||||
|
0, { "a", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
" ", " ",
|
||||||
|
1, { NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"a:bc:c de:fg hi:jklmn::foo :", ":",
|
||||||
|
0, { "a", "bc", "c de", "fg hi", "jklmn", "foo", NULL }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"", " ",
|
||||||
|
1, { NULL }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const char *prefixes[3] = { "abc", "bcd", "efg" };
|
||||||
|
int tidx;
|
||||||
|
int nprefixes; /* Number of items in already in the list. */
|
||||||
|
strlist_t list = NULL;
|
||||||
|
|
||||||
|
for (nprefixes = 0; nprefixes < DIM (prefixes); nprefixes++)
|
||||||
|
for (tidx = 0; tidx < DIM(tv); tidx++)
|
||||||
|
{
|
||||||
|
int item_count_expected;
|
||||||
|
int i;
|
||||||
|
strlist_t sl, newitems;
|
||||||
|
|
||||||
|
for (item_count_expected = 0;
|
||||||
|
tv[tidx].items_expected[item_count_expected];
|
||||||
|
item_count_expected++)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* printf ("np=%d testing %d \"%s\" delim=\"%s\"\n", */
|
||||||
|
/* nprefixes, tidx, tv[tidx].s, tv[tidx].delim); */
|
||||||
|
for (i=0; i < nprefixes; i++)
|
||||||
|
append_to_strlist (&list, prefixes[i]);
|
||||||
|
|
||||||
|
newitems = tokenize_to_strlist (&list, tv[tidx].s, tv[tidx].delim);
|
||||||
|
if (!newitems)
|
||||||
|
{
|
||||||
|
if (gpg_err_code_from_syserror () == GPG_ERR_ENOENT
|
||||||
|
&& tv[tidx].error_expected)
|
||||||
|
{
|
||||||
|
/* Good. But need to check the prefixes. */
|
||||||
|
for (sl=list, i=0; i < nprefixes; i++, sl=sl->next)
|
||||||
|
{
|
||||||
|
if (!sl || strcmp (prefixes[i], sl->d))
|
||||||
|
{
|
||||||
|
printf ("For item %d prefix item %d, expected '%s'\n",
|
||||||
|
tidx, i, prefixes[i]);
|
||||||
|
fail (tidx * 1000 + 40 + i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fail (tidx * 1000);
|
||||||
|
}
|
||||||
|
else if (tv[tidx].error_expected)
|
||||||
|
{
|
||||||
|
printf ("got items");
|
||||||
|
for (sl = list; sl; sl = sl->next)
|
||||||
|
printf (" \"%s\"", sl->d);
|
||||||
|
printf ("\n");
|
||||||
|
fail (tidx * 1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strlist_length (list) != nprefixes + item_count_expected)
|
||||||
|
fail (tidx * 1000);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (sl=list, i=0; i < nprefixes; i++, sl=sl->next)
|
||||||
|
{
|
||||||
|
if (!sl || strcmp (prefixes[i], sl->d))
|
||||||
|
{
|
||||||
|
printf ("For item %d prefix item %d, expected '%s'\n",
|
||||||
|
tidx, i, prefixes[i]);
|
||||||
|
fail (tidx * 1000 + 50 + i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=0; i < item_count_expected; i++, sl=sl->next)
|
||||||
|
{
|
||||||
|
if (!sl)
|
||||||
|
{
|
||||||
|
printf ("No item at item index %d\n", i);
|
||||||
|
fail (tidx * 1000 + i + 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (strcmp (tv[tidx].items_expected[i], sl->d))
|
||||||
|
{
|
||||||
|
printf ("For item %d, expected '%s', but got '%s'\n",
|
||||||
|
i, tv[tidx].items_expected[i], sl->d);
|
||||||
|
fail (tidx * 1000 + 10 + i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_strlist (list);
|
||||||
|
list = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -79,6 +267,7 @@ main (int argc, char **argv)
|
|||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
test_strlist_rev ();
|
test_strlist_rev ();
|
||||||
|
test_tokenize_to_strlist ();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user