Add STATUS_MODIFIED.
[pwmd.git] / src / util-string.c
blob7483ed5a2018b70d73625f739118404008a9a4f9
1 /*
2 Copyright (C) 2012-2022 Ben Kibbey <bjk@luxsci.net>
4 This file is part of pwmd.
6 Pwmd is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 Pwmd is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <stdio.h>
23 #include <ctype.h>
25 #include "util-string.h"
26 #include "mem.h"
28 #define ALLOC_LARGE 4096
30 void
31 string_free (struct string_s *s, int with_data)
33 if (!s)
34 return;
36 if (with_data)
37 xfree (s->str);
39 xfree (s);
42 struct string_s *
43 string_erase (struct string_s *s, ssize_t pos, ssize_t len)
45 if (pos > s->len)
46 return s;
48 if (len == -1)
50 s->str[pos] = 0;
51 s->len = s->len - pos;
52 return s;
55 int n = s->len - pos;
56 n -= len;
57 memmove (&s->str[pos], &s->str[pos + len], n);
58 s->len -= len;
59 s->str[s->len] = 0;
60 return s;
63 /* Be careful about allocations since other string_ functions may
64 * realloc the 'str' pointer. */
65 struct string_s *
66 string_new_content (char *str)
68 struct string_s *s = xcalloc (1, sizeof (struct string_s));
70 s->str = str;
71 s->len = strlen (s->str);
72 s->allocated = s->len + 1;
73 return s;
76 gpg_error_t
77 string_large (struct string_s *str)
79 char *s;
81 if (!str)
82 return GPG_ERR_INV_ARG;
84 s = xrealloc (str->str, (str->len + ALLOC_LARGE) * sizeof (char));
85 if (!s)
86 return GPG_ERR_ENOMEM;
88 str->str = s;
89 str->large = 1;
90 return 0;
93 struct string_s *
94 string_new (const char *str)
96 struct string_s *s = xcalloc (1, sizeof (struct string_s));
98 if (str)
100 s->str = str_dup (str);
101 if (!s->str)
103 xfree (s);
104 return NULL;
107 s->len = strlen (s->str);
108 s->allocated = s->len + 1;
111 return s;
114 struct string_s *
115 string_append (struct string_s *s, const char *str)
117 size_t len = strlen (str);
119 if (s->allocated < len + s->len + 1)
121 char *p;
122 size_t size = len + s->len + 1;
124 size += s->large ? ALLOC_LARGE : 0;
126 p = xrealloc (s->str, size * sizeof (char));
127 if (!p)
128 return NULL;
130 s->str = p;
131 s->allocated = size;
134 memcpy (&s->str[s->len], str, len);
135 s->len += len;
136 s->str[s->len] = 0;
137 return s;
140 struct string_s *
141 string_truncate (struct string_s *s, size_t n)
143 if (!s->str)
144 return s;
146 if (s->len < n)
147 return s;
149 s->str[n] = 0;
150 s->len = n;
151 return s;
154 struct string_s *
155 string_prepend (struct string_s *s, const char *str)
157 size_t len = strlen (str);
159 if (s->allocated < s->len + len + 1)
161 size_t size = len + s->len + 1;
163 size += s->large ? ALLOC_LARGE : 0;
164 char *p = xrealloc (s->str, size * sizeof (char));
166 if (!p)
167 return NULL;
169 s->str = p;
170 s->allocated = size;
173 memmove (&s->str[len], s->str, s->len);
174 memcpy (s->str, str, len);
175 s->len += len;
176 s->str[s->len] = 0;
177 return s;
180 struct string_s *
181 string_append_printf (struct string_s *s, const char *fmt, ...)
183 char *buf = NULL;
184 size_t len;
185 va_list ap;
187 va_start (ap, fmt);
188 len = str_vasprintf (&buf, fmt, ap);
189 va_end (ap);
190 if (len == -1)
191 return NULL;
193 s = string_append (s, buf);
194 xfree (buf);
195 return s;
198 struct string_s *
199 string_insert_c (struct string_s *s, ssize_t pos, char c)
201 size_t len = s->len + 2;
203 if (pos >= s->allocated)
204 len = pos + 2;
206 if (s->allocated < len)
208 size_t size = s->large ? len + ALLOC_LARGE : len;
209 char *p = xrealloc (s->str, size * sizeof (char));
211 if (!p)
212 return NULL;
214 s->str = p;
215 s->len = len;
216 s->allocated = size;
219 memmove (&s->str[pos + 1], &s->str[pos], s->len - pos);
220 s->str[pos] = c;
221 s->len = pos + 1 == s->allocated ? pos + 1 : s->len + 1;
222 s->str[s->len] = 0;
223 return s;
227 strv_length (char **a)
229 int n = 0;
231 while (a && *a++)
232 n++;
234 return n;
237 /* 'str' must already be allocated. */
238 char **
239 strv_cat (char **a, char *str)
241 int len = a ? strv_length (a) : 0;
242 char **dst;
244 dst = xrealloc (a, (len + 2) * sizeof (char *));
245 if (!dst)
246 return NULL;
248 dst[len++] = str;
249 dst[len] = NULL;
250 return dst;
254 strv_printf (char ***array, const char *fmt, ...)
256 char **a;
257 va_list ap;
258 char *buf;
259 int ret;
261 va_start (ap, fmt);
262 ret = str_vasprintf (&buf, fmt, ap);
263 va_end (ap);
265 if (ret == -1)
266 return 0;
268 a = strv_cat (*array, buf);
269 if (!a)
271 xfree (buf);
272 return 0;
275 *array = a;
276 return 1;
279 void
280 strv_free (char **a)
282 char **p;
284 for (p = a; p && *p; p++)
285 xfree (*p);
287 xfree (a);
290 char **
291 strv_dup (char **src)
293 char **dst = NULL;
294 char **p;
296 for (p = src; p && *p; p++)
298 char **tmp;
299 char *xp = str_dup (*p);
301 if (!xp)
303 strv_free (dst);
304 return NULL;
307 tmp = strv_cat (dst, xp);
308 if (!tmp)
310 xfree (xp);
311 strv_free (dst);
312 return NULL;
315 dst = tmp;
318 return dst;
321 char **
322 strv_catv (char **dst, char **src)
324 char **p;
325 char **d = NULL;
327 if (dst && *dst)
329 d = strv_dup (dst);
330 if (!d)
331 return NULL;
334 for (p = src; p && *p; p++)
336 char **tmp;
337 char *xp = str_dup (*p);
339 if (!xp)
341 strv_free (d);
342 return NULL;
345 tmp = strv_cat (d, xp);
346 if (!tmp)
348 xfree (xp);
349 strv_free (d);
350 return NULL;
353 d = tmp;
356 return d;
359 static char *
360 trim (char *str)
362 size_t len;
363 char *p = str;
365 if (!str || !*str)
366 return str;
368 len = strlen (str);
369 while (len && isspace (str[--len]))
370 str[len] = 0;
372 while (p && *p && isspace (*p))
373 p++;
375 return p;
378 static char **
379 str_split_common (const char *src, const char *delim, int count, int ws)
381 char **dst = NULL;
382 int index = 0;
383 const char *dp = delim;
384 char *str = str_dup (src);
385 char *p = str;
386 size_t dlen = strlen (delim);
387 size_t pos = 0, lastpos = 0;
389 if (!str || !*str)
391 xfree (str);
392 return NULL;
395 for (; *p; p++)
397 if (*p == *dp++)
399 if (!*dp)
401 char **tmp;
402 char *xp, *s;
403 size_t len = pos - lastpos - dlen + 1;
405 index++;
406 xp = xmalloc (len + 1);
407 if (!xp)
409 strv_free (dst);
410 xfree (str);
411 return NULL;
414 memcpy (xp, &str[lastpos], len);
415 xp[len] = 0;
416 s = xp;
418 if (ws)
419 s = trim (xp);
421 tmp = strv_cat (dst, s);
422 if (!tmp)
424 xfree (xp);
425 strv_free (dst);
426 xfree (str);
427 return NULL;
430 dst = tmp;
431 lastpos = pos + 1;
433 if (count > 0 && index+1 == count && *(p + 1))
435 if (!strv_printf (&dst, "%s", p + 1))
437 strv_free (dst);
438 xfree (str);
439 return NULL;
442 xfree (str);
443 return dst;
446 dp = delim;
449 pos++;
450 continue;
453 pos++;
454 dp = delim;
457 p = str + lastpos;
458 if (ws)
459 p = trim (p);
461 if (!strv_printf (&dst, "%s", p))
463 strv_free (dst);
464 xfree (str);
465 return NULL;
468 xfree (str);
469 return dst;
472 /* Like str_split() but trims whitespace between 'delim'. */
473 char **
474 str_split_ws (const char *str, const char *delim, int count)
476 return str_split_common (str, delim, count, 1);
479 char **
480 str_split (const char *str, const char *delim, int count)
482 return str_split_common (str, delim, count, 0);
485 char *
486 strv_join (const char *delim, char **a)
488 char **p;
489 char *dst = NULL;
490 struct string_s *s = string_new ("");
492 if (!s)
493 return NULL;
495 string_large (s);
497 for (p = a; p && *p; p++)
499 struct string_s *sp;
501 sp = string_append_printf (s, "%s%s", *p, delim
502 && *(p + 1) ? delim : "");
503 if (!sp)
505 string_free (s, 1);
506 return NULL;
509 s = sp;
512 dst = s->str;
513 string_free (s, 0);
514 return dst;
517 char *
518 str_down (char *str)
520 char *p;
522 for (p = str; *p; p++)
524 if (isascii (*p))
525 *p = tolower (*p);
528 return str;
531 char *
532 str_chomp (char *str)
534 int len = strlen (str);
535 char *p = str + len - 1;
537 while (len && isspace (*p))
539 *p-- = 0;
540 len--;
543 p = str;
544 while (isspace (*p))
546 p++;
547 len--;
550 memmove (str, p, len);
551 str[len] = 0;
552 return str;
555 char *
556 str_dup (const char *str)
558 char *t;
559 size_t len;
560 register size_t c;
562 len = strlen (str);
563 t = xmalloc ((len + 1) * sizeof (char));
564 if (!t)
565 return NULL;
567 for (c = 0; c < len; c++)
568 t[c] = str[c];
570 t[c] = 0;
571 return t;
574 char *
575 str_asprintf (const char *fmt, ...)
577 va_list ap;
578 char *result;
579 int len;
581 va_start (ap, fmt);
582 len = str_vasprintf (&result, fmt, ap);
583 va_end (ap);
584 return len == -1 ? NULL : result;
588 str_vasprintf (char **result, const char *fmt, va_list ap)
590 char *buf = NULL;
591 int len, len2;
592 va_list cp;
594 va_copy (cp, ap);
595 len = vsnprintf (NULL, 0, fmt, cp);
596 va_end (cp);
598 buf = xmalloc (++len);
599 if (!buf)
600 return -1;
602 va_copy (cp, ap);
603 len2 = vsnprintf (buf, len, fmt, cp);
604 va_end (cp);
605 if (len-1 != len2)
607 xfree (buf);
608 return -1;
610 *result = buf;
611 return len2;