Version 3.3.0.
[pwmd.git] / src / util-string.c
blobf1906489f72934e80b062297cb2d4b7ec018f90c
1 /*
2 Copyright (C) 2012-2021 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 as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
11 Pwmd is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <string.h>
25 #include <ctype.h>
27 #include "util-string.h"
28 #include "mem.h"
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 struct string_s *
77 string_new (const char *str)
79 struct string_s *s = xcalloc (1, sizeof (struct string_s));
81 if (str)
83 s->str = str_dup (str);
84 if (!s->str)
86 xfree (s);
87 return NULL;
90 s->len = strlen (s->str);
91 s->allocated = s->len + 1;
94 return s;
97 struct string_s *
98 string_append (struct string_s *s, const char *str)
100 size_t len = strlen (str);
102 if (s->allocated < len + s->len + 1)
104 char *p = xrealloc (s->str, (len + s->len + 1) * sizeof (char));
106 if (!p)
107 return NULL;
109 s->str = p;
110 s->allocated = s->len + len + 1;
113 memcpy (&s->str[s->len], str, len);
114 s->len += len;
115 s->str[s->len] = 0;
116 return s;
119 struct string_s *
120 string_truncate (struct string_s *s, size_t n)
122 if (!s->str)
123 return s;
125 if (s->len < n)
126 return s;
128 s->str[n] = 0;
129 s->len = n;
130 return s;
133 struct string_s *
134 string_prepend (struct string_s *s, const char *str)
136 size_t len = strlen (str);
138 if (s->allocated < s->len + len + 1)
140 char *p = xrealloc (s->str, (len + s->len + 1) * sizeof (char));
142 if (!p)
143 return NULL;
145 s->str = p;
146 s->allocated = s->len + len + 1;
149 memmove (&s->str[len], s->str, s->len);
150 memcpy (s->str, str, len);
151 s->len += len;
152 s->str[s->len] = 0;
153 return s;
156 struct string_s *
157 string_append_printf (struct string_s *s, const char *fmt, ...)
159 va_list ap;
160 char *buf = NULL;
161 size_t len;
163 va_start (ap, fmt);
164 len = str_vasprintf (&buf, fmt, ap);
165 va_end (ap);
167 if (len == -1)
168 return NULL;
170 s = string_append (s, buf);
171 xfree (buf);
172 return s;
175 struct string_s *
176 string_insert_c (struct string_s *s, ssize_t pos, char c)
178 size_t len = s->len + 2;
180 if (pos >= s->allocated)
181 len = pos + 2;
183 if (s->allocated < len)
185 char *p = xrealloc (s->str, len * sizeof (char));
187 if (!p)
188 return NULL;
190 s->str = p;
191 s->allocated = len;
194 memmove (&s->str[pos + 1], &s->str[pos], s->len - pos);
195 s->str[pos] = c;
196 s->len = pos + 1 == s->allocated ? pos + 1 : s->len + 1;
197 s->str[s->len] = 0;
198 return s;
202 strv_length (char **a)
204 int n = 0;
206 while (a && *a++)
207 n++;
209 return n;
212 /* 'str' must already be allocated. */
213 char **
214 strv_cat (char **a, char *str)
216 int len = a ? strv_length (a) : 0;
217 char **dst;
219 dst = xrealloc (a, (len + 2) * sizeof (char *));
220 if (!dst)
221 return NULL;
223 dst[len++] = str;
224 dst[len] = NULL;
225 return dst;
229 strv_printf (char ***array, const char *fmt, ...)
231 char **a;
232 va_list ap;
233 char *buf;
234 int ret;
236 va_start (ap, fmt);
237 ret = str_vasprintf (&buf, fmt, ap);
238 va_end (ap);
240 if (ret == -1)
241 return 0;
243 a = strv_cat (*array, buf);
244 if (!a)
246 xfree (buf);
247 return 0;
250 *array = a;
251 return 1;
254 void
255 strv_free (char **a)
257 char **p;
259 for (p = a; p && *p; p++)
260 xfree (*p);
262 xfree (a);
265 char **
266 strv_dup (char **src)
268 char **dst = NULL;
269 char **p;
271 for (p = src; p && *p; p++)
273 char **tmp;
274 char *xp = str_dup (*p);
276 if (!xp)
278 strv_free (dst);
279 return NULL;
282 tmp = strv_cat (dst, xp);
283 if (!tmp)
285 xfree (xp);
286 strv_free (dst);
287 return NULL;
290 dst = tmp;
293 return dst;
296 char **
297 strv_catv (char **dst, char **src)
299 char **p;
300 char **d = NULL;
302 if (dst && *dst)
304 d = strv_dup (dst);
305 if (!d)
306 return NULL;
309 for (p = src; p && *p; p++)
311 char **tmp;
312 char *xp = str_dup (*p);
314 if (!xp)
316 strv_free (d);
317 return NULL;
320 tmp = strv_cat (d, xp);
321 if (!tmp)
323 xfree (xp);
324 strv_free (d);
325 return NULL;
328 d = tmp;
331 return d;
334 static char *
335 trim (char *str)
337 size_t len;
338 char *p = str;
340 if (!str || !*str)
341 return str;
343 len = strlen (str);
344 while (len && isspace (str[--len]))
345 str[len] = 0;
347 while (p && *p && isspace (*p))
348 p++;
350 return p;
353 static char **
354 str_split_common (const char *src, const char *delim, int count, int ws)
356 char **dst = NULL;
357 int index = 0;
358 const char *dp = delim;
359 char *str = str_dup (src);
360 char *p = str;
361 size_t dlen = strlen (delim);
362 size_t pos = 0, lastpos = 0;
364 if (!str || !*str)
366 xfree (str);
367 return NULL;
370 for (; *p; p++)
372 if (*p == *dp++)
374 if (!*dp)
376 char **tmp;
377 char *xp, *s;
378 size_t len = pos - lastpos - dlen + 1;
380 index++;
381 xp = xmalloc (len + 1);
382 if (!xp)
384 strv_free (dst);
385 xfree (str);
386 return NULL;
389 memcpy (xp, &str[lastpos], len);
390 xp[len] = 0;
391 s = xp;
393 if (ws)
394 s = trim (xp);
396 tmp = strv_cat (dst, s);
397 if (!tmp)
399 xfree (xp);
400 strv_free (dst);
401 xfree (str);
402 return NULL;
405 dst = tmp;
406 lastpos = pos + 1;
408 if (count > 0 && index+1 == count && *(p + 1))
410 if (!strv_printf (&dst, "%s", p + 1))
412 strv_free (dst);
413 xfree (str);
414 return NULL;
417 xfree (str);
418 return dst;
421 dp = delim;
424 pos++;
425 continue;
428 pos++;
429 dp = delim;
432 p = str + lastpos;
433 if (ws)
434 p = trim (p);
436 if (!strv_printf (&dst, "%s", p))
438 strv_free (dst);
439 xfree (str);
440 return NULL;
443 xfree (str);
444 return dst;
447 /* Like str_split() but trims whitespace between 'delim'. */
448 char **
449 str_split_ws (const char *str, const char *delim, int count)
451 return str_split_common (str, delim, count, 1);
454 char **
455 str_split (const char *str, const char *delim, int count)
457 return str_split_common (str, delim, count, 0);
460 char *
461 strv_join (const char *delim, char **a)
463 char **p;
464 char *dst = NULL;
465 struct string_s *s = string_new ("");
467 if (!s)
468 return NULL;
470 for (p = a; p && *p; p++)
472 struct string_s *sp;
474 sp = string_append_printf (s, "%s%s", *p, delim
475 && *(p + 1) ? delim : "");
476 if (!sp)
478 string_free (s, 1);
479 return NULL;
482 s = sp;
485 dst = s->str;
486 string_free (s, 0);
487 return dst;
490 char *
491 str_down (char *str)
493 char *p;
495 for (p = str; *p; p++)
497 if (isascii (*p))
498 *p = tolower (*p);
501 return str;
504 char *
505 str_chomp (char *str)
507 int len = strlen (str);
508 char *p = str + len - 1;
510 while (len && isspace (*p))
512 *p-- = 0;
513 len--;
516 p = str;
517 while (isspace (*p))
519 p++;
520 len--;
523 memmove (str, p, len);
524 str[len] = 0;
525 return str;
528 char *
529 str_dup (const char *str)
531 char *t;
532 size_t len;
533 register size_t c;
535 len = strlen (str);
536 t = xmalloc ((len + 1) * sizeof (char));
537 if (!t)
538 return NULL;
540 for (c = 0; c < len; c++)
541 t[c] = str[c];
543 t[c] = 0;
544 return t;
547 char *
548 str_asprintf (const char *fmt, ...)
550 va_list ap;
551 char *result;
552 int len;
554 va_start (ap, fmt);
555 len = str_vasprintf (&result, fmt, ap);
556 va_end (ap);
557 return len == -1 ? NULL : result;
561 str_vasprintf (char **result, const char *fmt, va_list ap)
563 char *buf = NULL;
564 int len, len2;
565 va_list cp;
567 va_copy (cp, ap);
568 len = vsnprintf (NULL, 0, fmt, cp);
569 va_end (cp);
571 buf = xmalloc (++len);
572 if (!buf)
573 return -1;
575 va_copy (cp, ap);
576 len2 = vsnprintf (buf, len, fmt, cp);
577 va_end (cp);
578 if (len-1 != len2)
580 xfree (buf);
581 return -1;
583 *result = buf;
584 return len2;