Rework str_vasprintf().
[libpwmd.git] / src / util-string.c
blob480356912526721c4a8a9cbcd575f041d795e1ba
1 /*
2 Copyright (C) 2012, 2013, 2014, 2015, 2016, 2017
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <libpwmd.h>
29 #include "util-string.h"
31 void
32 string_free (struct string_s *s, int with_data)
34 if (!s)
35 return;
37 if (with_data)
38 pwmd_free (s->str);
40 pwmd_free (s);
43 struct string_s *
44 string_erase (struct string_s *s, ssize_t pos, ssize_t len)
46 if (pos > s->len)
47 return s;
49 if (len == -1)
51 s->str[pos] = 0;
52 s->len = s->len - pos;
53 return s;
56 int n = s->len - pos;
57 n -= len;
58 memmove (&s->str[pos], &s->str[pos + len], n);
59 s->len -= len;
60 s->str[s->len] = 0;
61 return s;
64 /* Be careful about allocations since other string_ functions may
65 * realloc the 'str' pointer. */
66 struct string_s *
67 string_new_content (char *str)
69 struct string_s *s = pwmd_calloc (1, sizeof (struct string_s));
71 s->str = str;
72 s->len = strlen (s->str);
73 s->allocated = s->len + 1;
74 return s;
77 struct string_s *
78 string_new (const char *str)
80 struct string_s *s = pwmd_calloc (1, sizeof (struct string_s));
82 if (str)
84 s->str = str_dup (str);
85 if (!s->str)
87 pwmd_free (s);
88 return NULL;
91 s->len = strlen (s->str);
92 s->allocated = s->len + 1;
95 return s;
98 struct string_s *
99 string_append (struct string_s *s, const char *str)
101 size_t len = strlen (str);
103 if (s->allocated < len + s->len + 1)
105 char *p = pwmd_realloc (s->str, (len + s->len + 1) * sizeof (char));
107 if (!p)
108 return NULL;
110 s->str = p;
111 s->allocated = s->len + len + 1;
114 memcpy (&s->str[s->len], str, len);
115 s->len += len;
116 s->str[s->len] = 0;
117 return s;
120 struct string_s *
121 string_truncate (struct string_s *s, size_t n)
123 if (!s->str)
124 return s;
126 if (s->len < n)
127 return s;
129 s->str[n] = 0;
130 s->len = n;
131 return s;
134 struct string_s *
135 string_prepend (struct string_s *s, const char *str)
137 size_t len = strlen (str);
139 if (s->allocated < s->len + len + 1)
141 char *p = pwmd_realloc (s->str, (len + s->len + 1) * sizeof (char));
143 if (!p)
144 return NULL;
146 s->str = p;
147 s->allocated = s->len + len + 1;
150 memmove (&s->str[len], s->str, s->len);
151 memcpy (s->str, str, len);
152 s->len += len;
153 s->str[s->len] = 0;
154 return s;
157 struct string_s *
158 string_append_printf (struct string_s *s, const char *fmt, ...)
160 va_list ap;
161 char *buf = NULL;
162 size_t len;
164 va_start (ap, fmt);
165 len = str_vasprintf (&buf, fmt, ap);
166 va_end (ap);
168 if (len == -1)
169 return NULL;
171 s = string_append (s, buf);
172 pwmd_free (buf);
173 return s;
176 struct string_s *
177 string_insert_c (struct string_s *s, ssize_t pos, char c)
179 size_t len = s->len + 2;
181 if (pos >= s->allocated)
182 len = pos + 2;
184 if (s->allocated < len)
186 char *p = pwmd_realloc (s->str, len * sizeof (char));
188 if (!p)
189 return NULL;
191 s->str = p;
192 s->allocated = len;
195 memmove (&s->str[pos + 1], &s->str[pos], s->len - pos);
196 s->str[pos] = c;
197 s->len = pos + 1 == s->allocated ? pos + 1 : s->len + 1;
198 s->str[s->len] = 0;
199 return s;
203 strv_length (char **a)
205 int n = 0;
207 while (a && *a++)
208 n++;
210 return n;
213 /* 'str' must already be allocated. */
214 char **
215 strv_cat (char **a, char *str)
217 int len = a ? strv_length (a) : 0;
218 char **dst;
220 dst = pwmd_realloc (a, (len + 2) * sizeof (char *));
221 if (!dst)
222 return NULL;
224 dst[len++] = str;
225 dst[len] = NULL;
226 return dst;
230 strv_printf (char ***array, const char *fmt, ...)
232 char **a;
233 va_list ap;
234 char *buf;
235 int ret;
237 va_start (ap, fmt);
238 ret = str_vasprintf (&buf, fmt, ap);
239 va_end (ap);
241 if (ret == -1)
242 return 0;
244 a = strv_cat (*array, buf);
245 if (!a)
247 pwmd_free (buf);
248 return 0;
251 *array = a;
252 return 1;
255 void
256 strv_free (char **a)
258 char **p;
260 for (p = a; p && *p; p++)
261 pwmd_free (*p);
263 pwmd_free (a);
266 char **
267 strv_dup (char **src)
269 char **dst = NULL;
270 char **p;
272 for (p = src; p && *p; p++)
274 char **tmp;
275 char *xp = str_dup (*p);
277 if (!xp)
279 strv_free (dst);
280 return NULL;
283 tmp = strv_cat (dst, xp);
284 if (!tmp)
286 pwmd_free (xp);
287 strv_free (dst);
288 return NULL;
291 dst = tmp;
294 return dst;
297 char **
298 strv_catv (char **dst, char **src)
300 char **p;
301 char **d = NULL;
303 if (dst && *dst)
305 d = strv_dup (dst);
306 if (!d)
307 return NULL;
310 for (p = src; p && *p; p++)
312 char **tmp;
313 char *xp = str_dup (*p);
315 if (!xp)
317 strv_free (d);
318 return NULL;
321 tmp = strv_cat (d, xp);
322 if (!tmp)
324 pwmd_free (xp);
325 strv_free (d);
326 return NULL;
329 d = tmp;
332 return d;
335 static char *
336 trim (char *str)
338 size_t len = strlen (str);
339 char *p = str;
341 while (isspace (str[--len]))
342 str[len] = 0;
344 while (isspace (*p))
345 p++;
347 return p;
350 static char **
351 str_split_common (const char *src, const char *delim, int count, int ws)
353 char **dst = NULL;
354 int index = 0;
355 const char *dp = delim;
356 char *str = str_dup (src);
357 char *p = str;
358 size_t dlen = strlen (delim);
359 size_t pos = 0, lastpos = 0;
361 if (!str || !*str)
363 pwmd_free (str);
364 return NULL;
367 for (; *p; p++)
369 if (*p == *dp++)
371 if (!*dp)
373 char **tmp;
374 char *xp, *s;
375 size_t len = pos - lastpos - dlen + 1;
377 index++;
378 xp = pwmd_malloc (len + 1);
379 if (!xp)
381 strv_free (dst);
382 pwmd_free (str);
383 return NULL;
386 memcpy (xp, &str[lastpos], len);
387 xp[len] = 0;
388 s = xp;
390 if (ws)
391 s = trim (xp);
393 tmp = strv_cat (dst, s);
394 if (!tmp)
396 pwmd_free (xp);
397 strv_free (dst);
398 pwmd_free (str);
399 return NULL;
402 dst = tmp;
403 lastpos = pos + 1;
405 if (count > 0 && index+1 == count && *(p + 1))
407 if (!strv_printf (&dst, "%s", p + 1))
409 strv_free (dst);
410 pwmd_free (str);
411 return NULL;
414 pwmd_free (str);
415 return dst;
418 dp = delim;
421 pos++;
422 continue;
425 pos++;
426 dp = delim;
429 p = str + lastpos;
430 if (ws)
431 p = trim (p);
433 if (!strv_printf (&dst, "%s", p))
435 strv_free (dst);
436 pwmd_free (str);
437 return NULL;
440 pwmd_free (str);
441 return dst;
444 /* Like str_split() but trims whitespace between 'delim'. */
445 char **
446 str_split_ws (const char *str, const char *delim, int count)
448 return str_split_common (str, delim, count, 1);
451 char **
452 str_split (const char *str, const char *delim, int count)
454 return str_split_common (str, delim, count, 0);
457 char *
458 strv_join (char *delim, char **a)
460 char **p;
461 char *dst = NULL;
462 struct string_s *s = string_new ("");
464 if (!s)
465 return NULL;
467 for (p = a; *p; p++)
469 struct string_s *sp;
471 sp = string_append_printf (s, "%s%s", *p, delim
472 && *(p + 1) ? delim : "");
473 if (!sp)
475 string_free (s, 1);
476 return NULL;
479 s = sp;
482 dst = s->str;
483 string_free (s, 0);
484 return dst;
487 char *
488 str_down (char *str)
490 char *p;
492 for (p = str; *p; p++)
494 if (isascii (*p))
495 *p = tolower (*p);
498 return str;
501 char *
502 str_chomp (char *str)
504 int len = strlen (str);
505 char *p = str + len - 1;
507 while (len && isspace (*p))
509 *p-- = 0;
510 len--;
513 p = str;
514 while (isspace (*p))
516 p++;
517 len--;
520 memmove (str, p, len);
521 str[len] = 0;
522 return str;
525 char *
526 str_dup (const char *str)
528 char *t;
529 size_t len;
530 register size_t c;
532 len = strlen (str);
533 t = pwmd_malloc ((len + 1) * sizeof (char));
534 if (!t)
535 return NULL;
537 for (c = 0; c < len; c++)
538 t[c] = str[c];
540 t[c] = 0;
541 return t;
544 char *
545 str_asprintf (const char *fmt, ...)
547 va_list ap;
548 char *result;
549 int len;
551 va_start (ap, fmt);
552 len = str_vasprintf (&result, fmt, ap);
553 va_end (ap);
554 return len == -1 ? NULL : result;
558 str_vasprintf (char **result, const char *fmt, va_list ap)
560 char *buf = NULL;
561 int len, len2;
562 va_list cp;
564 va_copy (cp, ap);
565 len = vsnprintf (NULL, 0, fmt, cp);
566 va_end (cp);
568 buf = pwmd_malloc (++len);
569 if (!buf)
570 return -1;
572 va_copy (cp, ap);
573 len2 = vsnprintf (buf, len, fmt, cp);
574 va_end (cp);
575 if (len-1 != len2)
577 pwmd_free (buf);
578 return -1;
580 *result = buf;
581 return len2;