Add copy-on-write support.
[pwmd.git] / src / util-string.c
blob265537f99f140af48f2face70d7b668dd6c8fd6c
1 /*
2 Copyright (C) 2012, 2013, 2014, 2015, 2016
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>
28 #include "util-string.h"
29 #include "mem.h"
31 void
32 string_free (struct string_s *s, int with_data)
34 if (!s)
35 return;
37 if (with_data)
38 xfree (s->str);
40 xfree (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 = xcalloc (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 = xcalloc (1, sizeof (struct string_s));
82 if (str)
84 s->str = str_dup (str);
85 if (!s->str)
87 xfree (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 = xrealloc (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 = xrealloc (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 xfree (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 = xrealloc (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 = xrealloc (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 xfree (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 xfree (*p);
263 xfree (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 xfree (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 xfree (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;
339 char *p = str;
341 if (!str || !*str)
342 return str;
344 len = strlen (str);
345 while (len && isspace (str[--len]))
346 str[len] = 0;
348 while (p && *p && isspace (*p))
349 p++;
351 return p;
354 static char **
355 str_split_common (const char *src, const char *delim, int count, int ws)
357 char **dst = NULL;
358 int index = 0;
359 const char *dp = delim;
360 char *str = str_dup (src);
361 char *p = str;
362 size_t dlen = strlen (delim);
363 size_t pos = 0, lastpos = 0;
365 if (!str || !*str)
367 xfree (str);
368 return NULL;
371 for (; *p; p++)
373 if (*p == *dp++)
375 if (!*dp)
377 char **tmp;
378 char *xp, *s;
379 size_t len = pos - lastpos - dlen + 1;
381 index++;
382 xp = xmalloc (len + 1);
383 if (!xp)
385 strv_free (dst);
386 xfree (str);
387 return NULL;
390 memcpy (xp, &str[lastpos], len);
391 xp[len] = 0;
392 s = xp;
394 if (ws)
395 s = trim (xp);
397 tmp = strv_cat (dst, s);
398 if (!tmp)
400 xfree (xp);
401 strv_free (dst);
402 xfree (str);
403 return NULL;
406 dst = tmp;
407 lastpos = pos + 1;
409 if (count > 0 && index+1 == count && *(p + 1))
411 if (!strv_printf (&dst, "%s", p + 1))
413 strv_free (dst);
414 xfree (str);
415 return NULL;
418 xfree (str);
419 return dst;
422 dp = delim;
425 pos++;
426 continue;
429 pos++;
430 dp = delim;
433 p = str + lastpos;
434 if (ws)
435 p = trim (p);
437 if (!strv_printf (&dst, "%s", p))
439 strv_free (dst);
440 xfree (str);
441 return NULL;
444 xfree (str);
445 return dst;
448 /* Like str_split() but trims whitespace between 'delim'. */
449 char **
450 str_split_ws (const char *str, const char *delim, int count)
452 return str_split_common (str, delim, count, 1);
455 char **
456 str_split (const char *str, const char *delim, int count)
458 return str_split_common (str, delim, count, 0);
461 char *
462 strv_join (const char *delim, char **a)
464 char **p;
465 char *dst = NULL;
466 struct string_s *s = string_new ("");
468 if (!s)
469 return NULL;
471 for (p = a; p && *p; p++)
473 struct string_s *sp;
475 sp = string_append_printf (s, "%s%s", *p, delim
476 && *(p + 1) ? delim : "");
477 if (!sp)
479 string_free (s, 1);
480 return NULL;
483 s = sp;
486 dst = s->str;
487 string_free (s, 0);
488 return dst;
491 char *
492 str_down (char *str)
494 char *p;
496 for (p = str; *p; p++)
498 if (isascii (*p))
499 *p = tolower (*p);
502 return str;
505 char *
506 str_chomp (char *str)
508 int len = strlen (str);
509 char *p = str + len - 1;
511 while (len && isspace (*p))
513 *p-- = 0;
514 len--;
517 p = str;
518 while (isspace (*p))
520 p++;
521 len--;
524 memmove (str, p, len);
525 str[len] = 0;
526 return str;
529 char *
530 str_dup (const char *str)
532 char *t;
533 size_t len;
534 register size_t c;
536 len = strlen (str);
537 t = xmalloc ((len + 1) * sizeof (char));
538 if (!t)
539 return NULL;
541 for (c = 0; c < len; c++)
542 t[c] = str[c];
544 t[c] = 0;
545 return t;
548 char *
549 str_asprintf (const char *fmt, ...)
551 va_list ap;
552 char *result;
553 int len;
555 va_start (ap, fmt);
556 len = str_vasprintf (&result, fmt, ap);
557 va_end (ap);
558 return len == -1 ? NULL : result;
562 str_vasprintf (char **result, const char *fmt, va_list ap)
564 char *buf = NULL;
565 int len;
566 va_list cp;
568 va_copy (cp, ap);
569 len = vsnprintf (NULL, 0, fmt, cp);
570 va_end (cp);
572 buf = xmalloc (++len);
573 if (!buf)
574 return -1;
576 va_copy (cp, ap);
577 len = vsnprintf (buf, len, fmt, cp);
578 va_end (cp);
579 if (len == -1)
581 xfree (buf);
582 return len;
584 *result = buf;
585 return len;