Coverage Report

Created: 2026-03-03 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnupg/common/strlist.c
Line
Count
Source
1
/* strlist.c -  string helpers
2
 * Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
3
 * Copyright (C) 2015, 2024  g10 Code GmbH
4
 *
5
 * This file is part of GnuPG.
6
 *
7
 * GnuPG is free software; you can redistribute and/or modify this
8
 * part of GnuPG under the terms of either
9
 *
10
 *   - the GNU Lesser General Public License as published by the Free
11
 *     Software Foundation; either version 3 of the License, or (at
12
 *     your option) any later version.
13
 *
14
 * or
15
 *
16
 *   - the GNU General Public License as published by the Free
17
 *     Software Foundation; either version 2 of the License, or (at
18
 *     your option) any later version.
19
 *
20
 * or both in parallel, as here.
21
 *
22
 * GnuPG is distributed in the hope that it will be useful, but
23
 * WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25
 * General Public License for more details.
26
 *
27
 * You should have received a copies of the GNU General Public License
28
 * and the GNU Lesser General Public License along with this program;
29
 * if not, see <https://www.gnu.org/licenses/>.
30
 * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
31
 */
32
33
#include <config.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <stdarg.h>
37
#include <ctype.h>
38
39
#include "util.h"
40
#include "common-defs.h"
41
#include "strlist.h"
42
#include "utf8conv.h"
43
#include "mischelp.h"
44
45
void
46
free_strlist( strlist_t sl )
47
1
{
48
1
    strlist_t sl2;
49
50
1
    for(; sl; sl = sl2 ) {
51
0
  sl2 = sl->next;
52
0
  xfree(sl);
53
0
    }
54
1
}
55
56
57
void
58
free_strlist_wipe (strlist_t sl)
59
0
{
60
0
    strlist_t sl2;
61
62
0
    for(; sl; sl = sl2 ) {
63
0
  sl2 = sl->next;
64
0
        wipememory (sl, sizeof *sl + strlen (sl->d));
65
0
  xfree(sl);
66
0
    }
67
0
}
68
69
70
/* Add STRING to the LIST at the front.  This function terminates the
71
   process on memory shortage.  */
72
strlist_t
73
add_to_strlist( strlist_t *list, const char *string )
74
0
{
75
0
    strlist_t sl;
76
77
0
    sl = xmalloc( sizeof *sl + strlen(string));
78
0
    sl->flags = 0;
79
0
    strcpy(sl->d, string);
80
0
    sl->next = *list;
81
0
    *list = sl;
82
0
    return sl;
83
0
}
84
85
86
/* Add STRING to the LIST at the front.  This function returns NULL
87
   and sets ERRNO on memory shortage.  */
88
strlist_t
89
add_to_strlist_try (strlist_t *list, const char *string)
90
0
{
91
0
  strlist_t sl;
92
93
0
  sl = xtrymalloc (sizeof *sl + strlen (string));
94
0
  if (sl)
95
0
    {
96
0
      sl->flags = 0;
97
0
      strcpy (sl->d, string);
98
0
      sl->next = *list;
99
0
      *list = sl;
100
0
    }
101
0
  return sl;
102
0
}
103
104
105
/* Same as add_to_strlist() but if IS_UTF8 is *not* set, a conversion
106
   to UTF-8 is done.  This function terminates the process on memory
107
   shortage.  */
108
strlist_t
109
add_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
110
0
{
111
0
  strlist_t sl;
112
113
0
  if (is_utf8)
114
0
    sl = add_to_strlist( list, string );
115
0
  else
116
0
    {
117
0
      char *p = native_to_utf8( string );
118
0
      sl = add_to_strlist( list, p );
119
0
      xfree ( p );
120
0
    }
121
0
  return sl;
122
0
}
123
124
125
/* Add STRING to the LIST at the end.  This function terminates the
126
   process on memory shortage.  */
127
strlist_t
128
append_to_strlist( strlist_t *list, const char *string )
129
0
{
130
0
  strlist_t sl;
131
0
  sl = append_to_strlist_try (list, string);
132
0
  if (!sl)
133
0
    xoutofcore ();
134
0
  return sl;
135
0
}
136
137
138
/* Core of append_to_strlist_try which take the length of the string.
139
 * Return the item added to the end of the list.  Or NULL in case of
140
 * an error.  */
141
static strlist_t
142
do_append_to_strlist (strlist_t *list, const char *string, size_t stringlen)
143
0
{
144
0
  strlist_t r, sl;
145
146
0
  sl = xtrymalloc (sizeof *sl + stringlen);
147
0
  if (!sl)
148
0
    return NULL;
149
150
0
  sl->flags = 0;
151
0
  memcpy (sl->d, string, stringlen);
152
0
  sl->d[stringlen] = 0;
153
0
  sl->next = NULL;
154
0
  if (!*list)
155
0
    *list = sl;
156
0
  else
157
0
    {
158
0
      for (r = *list; r->next; r = r->next)
159
0
        ;
160
0
      r->next = sl;
161
0
    }
162
0
  return sl;
163
0
}
164
165
166
/* Add STRING to the LIST at the end.  */
167
strlist_t
168
append_to_strlist_try (strlist_t *list, const char *string)
169
0
{
170
0
  return do_append_to_strlist (list, string, strlen (string));
171
0
}
172
173
174
strlist_t
175
append_to_strlist2( strlist_t *list, const char *string, int is_utf8 )
176
0
{
177
0
  strlist_t sl;
178
179
0
  if( is_utf8 )
180
0
    sl = append_to_strlist( list, string );
181
0
  else
182
0
    {
183
0
      char *p = native_to_utf8 (string);
184
0
      sl = append_to_strlist( list, p );
185
0
      xfree( p );
186
0
    }
187
0
  return sl;
188
0
}
189
190
191
/* Tokenize STRING using the delimiters from DELIM and append each
192
 * token to the string list LIST.  On success a pinter into LIST with
193
 * the first new token is returned.  Returns NULL on error and sets
194
 * ERRNO.  Take care, an error with ENOENT set mean that no tokens
195
 * were found in STRING.  */
196
strlist_t
197
tokenize_to_strlist (strlist_t *list, const char *string, const char *delim)
198
0
{
199
0
  const char *s, *se;
200
0
  size_t n;
201
0
  strlist_t newlist = NULL;
202
0
  strlist_t tail;
203
204
0
  s = string;
205
0
  do
206
0
    {
207
0
      se = strpbrk (s, delim);
208
0
      if (se)
209
0
        n = se - s;
210
0
      else
211
0
        n = strlen (s);
212
0
      if (!n)
213
0
        continue;  /* Skip empty string.  */
214
0
      tail = do_append_to_strlist (&newlist, s, n);
215
0
      if (!tail)
216
0
        {
217
0
          free_strlist (newlist);
218
0
          return NULL;
219
0
        }
220
0
      trim_spaces (tail->d);
221
0
      if (!*tail->d)  /* Remove new but empty item from the list.  */
222
0
        {
223
0
          tail = strlist_prev (newlist, tail);
224
0
          if (tail)
225
0
            {
226
0
              free_strlist (tail->next);
227
0
              tail->next = NULL;
228
0
            }
229
0
          else if (newlist)
230
0
            {
231
0
              free_strlist (newlist);
232
0
              newlist = NULL;
233
0
            }
234
0
          continue;
235
0
        }
236
0
    }
237
0
  while (se && (s = se + 1));
238
239
0
  if (!newlist)
240
0
    {
241
      /* Not items found.  Indicate this by returnning NULL with errno
242
       * set to ENOENT.  */
243
0
      gpg_err_set_errno (ENOENT);
244
0
      return NULL;
245
0
    }
246
247
  /* Append NEWLIST to LIST.  */
248
0
  if (!*list)
249
0
    *list = newlist;
250
0
  else
251
0
    {
252
0
      for (tail = *list; tail->next; tail = tail->next)
253
0
        ;
254
0
      tail->next = newlist;
255
0
    }
256
0
  return newlist;
257
0
}
258
259
260
/* Return a copy of LIST.  This function terminates the process on
261
   memory shortage.*/
262
strlist_t
263
strlist_copy (strlist_t list)
264
0
{
265
0
  strlist_t newlist = NULL, sl, *last;
266
267
0
  last = &newlist;
268
0
  for (; list; list = list->next)
269
0
    {
270
0
      sl = xmalloc (sizeof *sl + strlen (list->d));
271
0
      sl->flags = list->flags;
272
0
      strcpy(sl->d, list->d);
273
0
      sl->next = NULL;
274
0
      *last = sl;
275
0
      last = &sl;
276
0
    }
277
0
  return newlist;
278
0
}
279
280
281
282
strlist_t
283
strlist_prev( strlist_t head, strlist_t node )
284
0
{
285
0
    strlist_t n;
286
287
0
    for(n=NULL; head && head != node; head = head->next )
288
0
  n = head;
289
0
    return n;
290
0
}
291
292
strlist_t
293
strlist_last( strlist_t node )
294
0
{
295
0
    if( node )
296
0
  for( ; node->next ; node = node->next )
297
0
      ;
298
0
    return node;
299
0
}
300
301
302
/* Remove the first item from LIST and return its content in an
303
   allocated buffer.  This function terminates the process on memory
304
   shortage.  */
305
char *
306
strlist_pop (strlist_t *list)
307
0
{
308
0
  char *str=NULL;
309
0
  strlist_t sl=*list;
310
311
0
  if(sl)
312
0
    {
313
0
      str = xmalloc(strlen(sl->d)+1);
314
0
      strcpy(str,sl->d);
315
316
0
      *list=sl->next;
317
0
      xfree(sl);
318
0
    }
319
320
0
  return str;
321
0
}
322
323
/* Return the first element of the string list HAYSTACK whose string
324
   matches NEEDLE.  If no elements match, return NULL.  */
325
strlist_t
326
strlist_find (strlist_t haystack, const char *needle)
327
0
{
328
0
  for (;
329
0
       haystack;
330
0
       haystack = haystack->next)
331
0
    if (strcmp (haystack->d, needle) == 0)
332
0
      return haystack;
333
0
  return NULL;
334
0
}
335
336
int
337
strlist_length (strlist_t list)
338
0
{
339
0
  int i;
340
0
  for (i = 0; list; list = list->next)
341
0
    i ++;
342
343
0
  return i;
344
0
}
345
346
/* Reverse the list *LIST in place.  */
347
strlist_t
348
strlist_rev (strlist_t *list)
349
0
{
350
0
  strlist_t l = *list;
351
0
  strlist_t lrev = NULL;
352
353
0
  while (l)
354
0
    {
355
0
      strlist_t tail = l->next;
356
0
      l->next = lrev;
357
0
      lrev = l;
358
0
      l = tail;
359
0
    }
360
361
0
  *list = lrev;
362
0
  return lrev;
363
0
}