1 /* String functions which allocate strings on the pool.
2 * By Richard W.M. Jones <rich@annexia.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 * $Id: pstring.c,v 1.24 2003/01/22 14:29:37 rich Exp $
42 #define MIN(a,b) ((a)<(b)?(a):(b))
44 /* Duplicate a string. */
46 pstrdup (pool pool, const char *str)
48 int len = strlen (str);
49 char *ptr = pmalloc (pool, (len+1) * sizeof (char));
50 return memcpy (ptr, str, len+1);
53 /* Duplicate up to the first N characters of a string. */
55 pstrndup (pool pool, const char *str, int n)
57 int len = MIN (strlen (str), n);
58 char *ptr = pmalloc (pool, (len+1) * sizeof (char));
59 memcpy (ptr, str, len);
64 /* Duplicate a fixed-size area of memory. */
66 pmemdup (pool pool, const void *data, size_t size)
68 void *ptr = pmalloc (pool, size);
69 return memcpy (ptr, data, size);
72 static vector generic_split (pool pool, const char *str, const void *sep, const char *(*find) (const char *str, const void *sep, const char **end_match), int keep);
75 find_strstr (const char *str, const void *sep, const char **end_match)
77 const char *csep = (const char *) sep;
78 const char *t = strstr (str, csep);
79 if (t) *end_match = t + strlen (csep);
84 pstrsplit (pool pool, const char *str, const char *sep)
86 return generic_split (pool, str, sep, find_strstr, 0);
90 find_strchr (const char *str, const void *sep, const char **end_match)
92 char c = * (const char *) sep;
93 const char *t = strchr (str, c);
94 if (t) *end_match = t+1;
99 pstrcsplit (pool pool, const char *str, char c)
101 return generic_split (pool, str, &c, find_strchr, 0);
105 find_re (const char *str, const void *sep, const char **end_match)
107 const pcre *re = (const pcre *) sep;
109 int ovector[ovecsize];
110 int r = pcre_exec (re, 0, str, strlen (str), 0, 0, ovector, ovecsize);
112 if (r >= 0) /* Successful match. */
117 if (so == -1) abort (); /* Bad pattern. */
118 *end_match = str + eo;
121 else if (r == PCRE_ERROR_NOMATCH)
124 abort (); /* Some other error reported by PCRE. */
129 pstrresplit (pool pool, const char *str, const pcre *re)
131 return generic_split (pool, str, re, find_re, 0);
135 pstrsplit2 (pool pool, const char *str, const char *sep)
137 return generic_split (pool, str, sep, find_strstr, 1);
141 pstrcsplit2 (pool pool, const char *str, char c)
143 return generic_split (pool, str, &c, find_strchr, 1);
147 pstrresplit2 (pool pool, const char *str, const pcre *re)
149 return generic_split (pool, str, re, find_re, 1);
152 /* Generic split function. */
154 generic_split (pool pool, const char *str, const void *sep,
155 const char *(*find) (const char *str, const void *sep,
156 const char **end_match),
159 const char *start_match, *end_match;
163 /* If the string is zero length, always return a zero length vector. */
164 if (strcmp (str, "") == 0) return new_vector (pool, char *);
166 /* Find the splitting point. */
167 start_match = find (str, sep, &end_match);
169 if (start_match != 0) /* Successful match. */
171 s = start_match > str ? pstrndup (pool, str, start_match - str) : 0;
172 v = generic_split (pool, end_match, sep, find, keep);
173 if (keep) /* Keep the matching text. */
177 match = pstrndup (pool, start_match, end_match - start_match);
178 vector_push_front (v, match);
180 if (s) vector_push_front (v, s);
182 else /* Not successful match. */
184 s = pstrdup (pool, str);
185 v = new_vector (pool, char *);
186 vector_push_back (v, s);
192 /* Concatenate a vector of strings to form a string. */
194 pconcat (pool pool, vector v)
197 char *s = pstrdup (pool, "");
199 for (i = 0; i < vector_size (v); ++i)
203 vector_get (v, i, t);
204 s = pstrcat (pool, s, t);
210 /* Join a vector of strings, separating each string by the given string. */
212 pjoin (pool pool, vector v, const char *sep)
215 char *s = pstrdup (pool, "");
217 for (i = 0; i < vector_size (v); ++i)
221 vector_get (v, i, t);
222 s = pstrcat (pool, s, t);
223 if (i < vector_size (v) - 1) s = pstrcat (pool, s, sep);
230 pchrs (pool pool, char c, int n)
232 char *s = pmalloc (pool, sizeof (char) * (n + 1));
235 for (i = 0; i < n; ++i)
243 pstrs (pool pool, const char *str, int n)
245 int len = strlen (str);
246 char *s = pmalloc (pool, sizeof (char) * (len * n + 1));
249 for (i = j = 0; i < n; ++i, j += len)
250 memcpy (&s[j], str, len);
258 pvector (pool pool, ...)
262 vector v = new_vector (pool, const char *);
264 va_start (args, pool);
265 while ((s = va_arg (args, const char *)) != 0)
266 vector_push_back (v, s);
273 pvectora (pool pool, const char *array[], int n)
276 vector v = new_vector (pool, const char *);
278 for (i = 0; i < n; ++i)
279 vector_push_back (v, array[i]);
284 /* Sort a vector of strings. */
286 psort (vector v, int (*compare_fn) (const char **, const char **))
288 vector_sort (v, (int (*) (const void *, const void *)) compare_fn);
291 /* Remove line endings (either CR, CRLF or LF) from the string. */
295 int len = strlen (line);
297 while (line[len-1] == '\n' || line[len-1] == '\r')
304 ptrimfront (char *str)
309 for (p = str; *p && isspace ((int) *p); ++p)
313 memmove (str, p, len + 1);
319 ptrimback (char *str)
325 for (p = str + len - 1; p >= str && isspace ((int) *p); --p)
341 /* This is equivalent to sprintf but it allocates the result string in POOL.*/
343 psprintf (pool pool, const char *format, ...)
348 va_start (args, format);
349 s = pvsprintf (pool, format, args);
355 /* Similar to vsprintf. */
357 pvsprintf (pool pool, const char *format, va_list args)
359 #ifdef HAVE_VASPRINTF
363 vasprintf (&s, format, args);
364 if (s == 0) abort (); /* XXX Should call bad_malloc_handler. */
366 /* The pool will clean up the malloc when it goes. */
367 pool_register_malloc (pool, s);
371 #else /* !HAVE_VASPRINTF */
374 char *s = alloca (n), *t;
376 /* Note: according to the manual page, a return value of -1 indicates
377 * that the string was truncated. We have found that this is not
378 * actually true however. In fact, the library seems to return the
379 * number of characters which would have been written into the string
380 * excluding the '\0' (ie. r > n).
382 r = vsnprintf (s, n, format, args);
386 /* Copy the string into a pool-allocated area of the correct size
390 t = pmalloc (pool, n);
397 /* String was truncated. Allocate enough space for the string
398 * in the pool and repeat the vsnprintf into this buffer.
401 t = pmalloc (pool, n);
403 vsnprintf (t, n, format, args);
408 #endif /* !HAVE_VASPRINTF */
411 /* Convert various number types to strings. */
413 pitoa (pool pool, int n)
415 char *s = pmalloc (pool, 16);
416 snprintf (s, 16, "%d", n);
421 pdtoa (pool pool, double n)
423 char *s = pmalloc (pool, 16);
424 snprintf (s, 16, "%f", n);
429 pxtoa (pool pool, unsigned n)
431 char *s = pmalloc (pool, 16);
432 snprintf (s, 16, "%x", n);
436 /* Promote vector of numbers to vector of strings. */
438 pvitostr (pool pool, vector v)
440 vector nv = new_vector (pool, char *);
443 vector_reallocate (nv, vector_size (v));
445 for (i = 0; i < vector_size (v); ++i)
450 vector_get (v, i, j);
452 vector_push_back (nv, s);
459 pvdtostr (pool pool, vector v)
461 vector nv = new_vector (pool, char *);
464 vector_reallocate (nv, vector_size (v));
466 for (i = 0; i < vector_size (v); ++i)
471 vector_get (v, i, j);
473 vector_push_back (nv, s);
480 pvxtostr (pool pool, vector v)
482 vector nv = new_vector (pool, char *);
485 vector_reallocate (nv, vector_size (v));
487 for (i = 0; i < vector_size (v); ++i)
492 vector_get (v, i, j);
494 vector_push_back (nv, s);
500 /* STR is a string allocated in POOL. Append ENDING to STR, reallocating
504 pstrcat (pool pool, char *str, const char *ending)
506 /* There are probably more efficient ways to implement this ... */
507 int slen = strlen (str);
508 int elen = strlen (ending);
510 str = prealloc (pool, str, slen + elen + 1);
511 strcat (str, ending);
516 pstrncat (pool pool, char *str, const char *ending, size_t n)
518 int slen = strlen (str);
519 int elen = strlen (ending);
521 elen = elen > n ? n : elen;
523 str = prealloc (pool, str, slen + elen + 1);
524 strncat (str, ending, n);
528 /* Return the substring starting at OFFSET and of length LEN of STR, allocated
529 * as a new string. If LEN is negative, everything up to the end of STR
533 psubstr (pool pool, const char *str, int offset, int len)
539 new_str = pmalloc (pool, len + 1);
540 memcpy (new_str, str + offset, len);
546 len = strlen (str + offset);
547 new_str = pmalloc (pool, len + 1);
548 memcpy (new_str, str + offset, len);
558 while (*s) { *s = toupper (*s); s++; }
566 while (*s) { *s = tolower (*s); s++; }
570 /* NB. The following figures were derived by examining a large number
571 * of configuration files in /etc/ on a Red Hat Linux box.
573 #define _PGETL_INITIAL_BUFFER 96
574 #define _PGETL_INCR_BUFFER 32
577 pgetline (pool pool, FILE *fp, char *line)
579 int allocated = _PGETL_INITIAL_BUFFER;
583 /* Reallocate the buffer. */
584 line = prealloc (pool, line, _PGETL_INITIAL_BUFFER);
586 /* Read in the line until we reach EOF or a '\n' character. */
587 while ((c = getc (fp)) != EOF && c != '\n')
589 if (len == allocated)
590 line = prealloc (pool, line, allocated += _PGETL_INCR_BUFFER);
594 /* EOF and no content? */
595 if (c == EOF && len == 0)
598 /* Last character is '\r'? Remove it. */
599 if (line[len-1] == '\r')
602 /* Append a '\0' character to the buffer. */
603 if (len == allocated)
604 line = prealloc (pool, line, ++allocated);
611 pgetlinex (pool pool, FILE *fp, char *line, const char *comment_set,
617 /* Read a single line. */
618 line = pgetline (pool, fp, line);
619 if (line == 0) return 0;
624 if (!(flags & PGETL_NO_CONCAT))
627 if (line[len-1] == '\\')
631 line[--len] = '\0'; /* Remove backslash char from first line. */
633 next = pgetline (pool, fp, 0);
636 line = pstrcat (pool, line, next);
643 /* Remove comments? */
644 if (!(flags & PGETL_INLINE_COMMENTS))
646 /* No inline comments. We're searching for whitespace followed
647 * by a comment character. If we find it, remove the line following
648 * the comment character.
650 for (i = 0; i < len; ++i)
651 if (!isspace ((int) line[i]))
653 if (strchr (comment_set, line[i]) != 0)
663 /* Inline comments. Search for the first occurance of any
664 * comment character and just remove the rest of the line
667 for (i = 0; i < len; ++i)
668 if (strchr (comment_set, line[i]) != 0)
679 /* Ignore blank lines. */
687 pmap (pool p, const vector v, char *(*map_fn) (pool, const char *))
690 vector nv = new_vector (p, char *);
692 for (i = 0; i < vector_size (v); ++i)
697 vector_get (v, i, s);
699 vector_push_back (nv, r);
706 pgrep (pool p, const vector v, int (*grep_fn) (pool, const char *))
709 vector nv = new_vector (p, char *);
711 for (i = 0; i < vector_size (v); ++i)
715 vector_get (v, i, s);
717 vector_push_back (nv, s);