123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713 |
- /*
- * This file is part of the Sofia-SIP package
- *
- * Copyright (C) 2006 Nokia Corporation.
- *
- * Contact: Pekka Pessi <pekka.pessi@nokia.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
- /**@defgroup su_strlst String Lists
- *
- * Lists of strings.
- *
- * String lists using #su_home_t.
- *
- */
- /**@ingroup su_strlst
- * @CFILE su_strlst.c
- * @brief String lists.
- *
- * The string lists can be used to concatenate a large number of strings, or
- * split a string to smaller pieces (e.g., lines).
- *
- * Example of concatenating a number of strings to @a s:
- * @code
- * su_strlst_t *l = su_strlist_create(home);
- * su_strlst_append(l, "=============");
- * su_slprintf(l, "a is: %d", a)
- * su_slprintf(l, "b is: %d", b)
- * su_slprintf(l, "c is: %d", c)
- * su_strlst_append(l, "------------");
- * su_slprintf(l, "total: %d", a + b + c));
- * su_strlst_append(l, "=============");
- * s = su_strlst_join(l, "\n");
- * @endcode
- *
- * Another example, splitting a string into lines and counting the number of
- * non-empty ones:
- * @code
- * usize_t i, n;
- * su_strlst_t *l;
- *
- * l = su_strlst_split(NULL, buf, "\n");
- *
- * nonempty = 0;
- *
- * for (i = 0; i < su_strlst_len(l); i++) {
- * n = strcspn(su_strlst_item(l, i), " \t");
- * if (su_strlst_item(l, i)[n])
- * nonempty++;
- * }
- *
- * su_strlst_destroy(l);
- * @endcode
- *
- * @author Pekka Pessi <Pekka.Pessi@nokia.com>
- *
- * @date Created: Fri May 3 09:22:59 2002 ppessi
- */
- #include "config.h"
- #include "sofia-sip/su_config.h"
- #include "sofia-sip/su_strlst.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <stddef.h>
- #include <memory.h>
- #include <limits.h>
- #include <string.h>
- #include <assert.h>
- #if defined(va_copy)
- /* Xyzzy */
- #elif defined(__va_copy)
- #define va_copy(dst, src) __va_copy((dst), (src))
- #else
- #define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
- #endif
- enum { N = 8 };
- struct su_strlst_s
- {
- su_home_t sl_home[1];
- size_t sl_size;
- size_t sl_len;
- size_t sl_total;
- char const **sl_list;
- };
- /** Create a list with initial values */
- static
- su_strlst_t *su_strlst_vcreate_with_by(su_home_t *home,
- char const *value,
- va_list va,
- int deeply)
- {
- su_strlst_t *self;
- size_t i, n, m;
- size_t total, size;
- m = 0, total = 0;
- /* Count arguments and their length */
- if (value) {
- char const *s;
- va_list va0;
- va_copy(va0, va);
- for (s = value; s; m++, s = va_arg(va0, char *))
- total += strlen(s);
- va_end(va0);
- }
- for (n = N; m > n; n *= 2)
- ;
- size = sizeof(*self) + n * sizeof(*self->sl_list);
- if (deeply)
- size += total + m;
- self = su_home_clone(home, size);
- if (self) {
- self->sl_size = n;
- self->sl_list = (char const **)(self + 1);
- self->sl_len = m;
- self->sl_total = total;
- if (deeply) {
- char *s = (char *)(self->sl_list + self->sl_size);
- char *end = s + total + m;
- for (i = 0; i < m; i++) {
- assert(s);
- self->sl_list[i] = s;
- s = memccpy(s, value, '\0', end - s);
- value = va_arg(va, char const *);
- }
- }
- else {
- for (i = 0; i < m; i++) {
- self->sl_list[i] = value;
- value = va_arg(va, char const *);
- }
- }
- }
- return self;
- }
- /** Create an empty string list.
- *
- * The list is initially empty. The memory home for the list is cloned from
- * @a home.
- *
- */
- su_strlst_t *su_strlst_create(su_home_t *home)
- {
- su_strlst_t *self;
- self = su_home_clone(home, sizeof(*self) + N * sizeof(*self->sl_list));
- if (self) {
- self->sl_size = N;
- self->sl_list = (char const **)(self + 1);
- }
- return self;
- }
- /** Create a string list with initial values.
- *
- * The list is initialized with strings in argument. The argument list is
- * terminated with NULL. The memory home for the list is cloned from @a
- * home.
- */
- su_strlst_t *su_strlst_create_with(su_home_t *home, char const *value, ...)
- {
- va_list va;
- su_strlst_t *l;
- va_start(va, value);
- l = su_strlst_vcreate_with_by(home, value, va, 0);
- va_end(va);
- return l;
- }
- /** Create a string list with initial values.
- *
- * The string list is initialized with strings from @a va_list @a va. The
- * argument list is terminated with NULL. The memory home for the list is
- * cloned from @a home.
- */
- su_strlst_t *su_strlst_vcreate_with(su_home_t *home,
- char const *value,
- va_list va)
- {
- return su_strlst_vcreate_with_by(home, value, va, 0);
- }
- /** Create a string list with duplicatedd initial values.
- *
- * The list is initialized with copies of strings in argument list. The
- * argument list is terminated with NULL. The memory home for the list is
- * cloned from @a home.
- */
- su_strlst_t *su_strlst_create_with_dup(su_home_t *home, char const *value, ...)
- {
- va_list va;
- su_strlst_t *l;
- va_start(va, value);
- l = su_strlst_vcreate_with_by(home, value, va, 1);
- va_end(va);
- return l;
- }
- /** Create a string list with duplicates of initial values.
- *
- * The string list is initialized with copies of strings from @a va_list @a
- * va. The argument list is terminated with NULL. The memory home for the
- * list is cloned from @a home.
- */
- su_strlst_t *su_strlst_vcreate_with_dup(su_home_t *home,
- char const *value,
- va_list va)
- {
- return su_strlst_vcreate_with_by(home, value, va, 1);
- }
- /** Copy a string list */
- static
- su_strlst_t *su_strlst_copy_by(su_home_t *home,
- su_strlst_t const *orig,
- int deeply)
- {
- su_strlst_t *self;
- size_t N, i, size, deepsize = 0;
- if (orig == NULL)
- return NULL;
- N = orig->sl_size;
- if (deeply)
- deepsize = orig->sl_len + orig->sl_total;
- size = sizeof(*self) + N * sizeof(self->sl_list[0]) + deepsize;
- self = su_home_clone(home, size);
- if (self) {
- self->sl_size = N;
- self->sl_list = (char const **)(self + 1);
- self->sl_len = N = orig->sl_len;
- self->sl_total = orig->sl_total;
- if (deeply) {
- char *s = (char *)(self->sl_list + self->sl_size);
- char *end = s + deepsize;
- for (i = 0; i < N; i++) {
- self->sl_list[i] = s;
- s = memccpy(s, orig->sl_list[i], '\0', end - s);
- assert(s);
- }
- }
- else {
- for (i = 0; i < N; i++) {
- self->sl_list[i] = orig->sl_list[i];
- }
- }
- }
- return self;
- }
- /** Shallow copy a string list. */
- su_strlst_t *su_strlst_copy(su_home_t *home, su_strlst_t const *orig)
- {
- return su_strlst_copy_by(home, orig, 0);
- }
- /** Deep copy a string list. */
- su_strlst_t *su_strlst_dup(su_home_t *home, su_strlst_t const *orig)
- {
- return su_strlst_copy_by(home, orig, 1);
- }
- /** Destroy a string list.
- *
- * The function su_strlst_destroy() destroys a list of strings and frees all
- * duplicated strings belonging to it.
- */
- void su_strlst_destroy(su_strlst_t *self)
- {
- su_home_zap(self->sl_home);
- }
- /** Increase the list size for next item, if necessary. */
- static int su_strlst_increase(su_strlst_t *self)
- {
- if (self->sl_size <= self->sl_len + 1) {
- size_t size = 2 * self->sl_size * sizeof(self->sl_list[0]);
- char const **list;
- if (self->sl_list != (char const **)(self + 1)) {
- list = su_realloc(self->sl_home, (void *)self->sl_list, size);
- } else {
- list = su_alloc(self->sl_home, size);
- if (list)
- memcpy(list, self->sl_list, self->sl_len * sizeof(*self->sl_list));
- }
- if (!list)
- return 0;
- self->sl_list = list;
- self->sl_size = 2 * self->sl_size;
- }
- return 1;
- }
- /**Duplicate and append a string to list.
- *
- * @param self pointer to a string list object
- * @param str string to be duplicated and appended
- *
- * @return
- * Pointer to duplicated string, if successful, or NULL upon an error.
- */
- char *su_strlst_dup_append(su_strlst_t *self, char const *str)
- {
- size_t len;
- if (str == NULL)
- str = "";
- len = strlen(str);
- if (self && su_strlst_increase(self)) {
- char *retval = su_alloc(self->sl_home, len + 1);
- if (retval) {
- memcpy(retval, str, len);
- retval[len] = 0;
- self->sl_list[self->sl_len++] = retval;
- self->sl_total += len;
- }
- return retval;
- }
- return NULL;
- }
- /**Append a string to list.
- *
- * The string is not copied, and it @b must not be modified while string
- * list exists.
- *
- * @param self pointer to a string list object
- * @param str string to be appended
- *
- * @return
- * Pointer to string, if successful, or NULL upon an error.
- */
- char const *su_strlst_append(su_strlst_t *self, char const *str)
- {
- if (str == NULL)
- str = "";
- if (self && su_strlst_increase(self)) {
- self->sl_list[self->sl_len++] = str;
- self->sl_total += strlen(str);
- return str;
- }
- return NULL;
- }
- /**Append a formatted string to the list.
- *
- * Format a string according to a @a fmt like printf(). The resulting string
- * is copied to a memory area freshly allocated from a the memory home of
- * the list and appended to the string list.
- *
- * @param self pointer to a string list object
- * @param fmt format string
- * @param ... argument list (must match with the @a fmt format string)
- *
- * @return A pointer to a fresh copy of formatting result, or NULL upon an
- * error.
- */
- char const *su_slprintf(su_strlst_t *self, char const *fmt, ...)
- {
- char const *str;
- va_list ap;
- va_start(ap, fmt);
- str = su_slvprintf(self, fmt, ap);
- va_end(ap);
- return str;
- }
- /**Append a formatted string to the list.
- *
- * Format a string according to a @a fmt like vprintf(). The resulting
- * string is copied to a memory area freshly allocated from a the memory
- * home of the list and appended to the string list.
- *
- * @param self pointer to a string list object
- * @param fmt format string
- * @param ap stdarg argument list (must match with the @a fmt format string)
- *
- * @return A pointer to a fresh copy of formatting result, or NULL upon an
- * error.
- */
- char const *su_slvprintf(su_strlst_t *self, char const *fmt, va_list ap)
- {
- char *str = NULL;
- if (self && su_strlst_increase(self)) {
- str = su_vsprintf(self->sl_home, fmt, ap);
- if (str) {
- self->sl_list[self->sl_len++] = str;
- self->sl_total += strlen(str);
- }
- }
- return str;
- }
- /**Returns a numbered item from the list of strings. The numbering starts from
- * 0.
- *
- * @param self pointer to a string list object
- * @param i string index
- *
- * @return
- * Pointer to string, if item exists, or NULL if index is out of bounds or
- * list does not exist.
- */
- char const *su_strlst_item(su_strlst_t const *self, usize_t i)
- {
- if (self && i < self->sl_len)
- return self->sl_list[i];
- else
- return NULL;
- }
- /**Sets a item to the list of strings.
- *
- * Note that the item numbering starts from 0.
- *
- * @param self pointer to a string list object
- * @param i string index
- * @param s string to be set as item @a i
- *
- * @return
- * Pointer to string, if item exists, or NULL if index is out of bounds or
- * list does not exist.
- */
- char const *su_strlst_set_item(su_strlst_t *self, usize_t i, char const *s)
- {
- char const *old = NULL;
- if (self == NULL)
- return NULL;
- else if (i == self->sl_len)
- return (void)su_strlst_append(self, s), NULL;
- else if (i > self->sl_len)
- return NULL;
- if (s == NULL)
- s = "";
- old = self->sl_list[i];
- self->sl_list[i] = s;
- return old;
- }
- /**Removes a numbered item from the list of strings. The numbering starts from
- * 0. The caller is responsible of reclaiming memory used by the removed string.
- *
- * @param self pointer to a string list object
- * @param i string index
- *
- * @return
- * Pointer to string, if item exists, or NULL if index is out of bounds or
- * list does not exist.
- */
- SU_DLL char const *su_strlst_remove(su_strlst_t *self, usize_t i)
- {
- if (self && i < self->sl_len) {
- char const *s = self->sl_list[i];
- memmove(&self->sl_list[i], &self->sl_list[i + 1],
- &self->sl_list[self->sl_len] - &self->sl_list[i]);
- self->sl_len--;
- return s;
- }
- else
- return NULL;
- }
- /** Concatenate list of strings to one string.
- *
- * The function su_strlst_join() concatenates the list of strings. Between
- * each string in list it uses @a sep. The separator is not inserted after
- * the last string in list, but one can always append an empty string to the
- * list.
- *
- * The string is allocated from the memory @a home. If @a home is NULL, the
- * string is allocated using malloc().
- *
- * @param self pointer to a string list object
- * @param home home pointer
- * @param sep separator (may be NULL)
- *
- * @return
- *
- * The function su_strlst_join() returns a concatenation of the strings in
- * list, or NULL upon an error.
- */
- char *su_strlst_join(su_strlst_t *self, su_home_t *home, char const *sep)
- {
- if (!sep)
- sep = "";
- if (self && self->sl_len > 0) {
- size_t seplen = strlen(sep);
- size_t total = self->sl_total + seplen * (self->sl_len - 1);
- char *retval;
- retval = su_alloc(home, total + 1);
- if (retval) {
- char *s = retval;
- size_t i = 0, len;
- for (;;) {
- len = strlen(self->sl_list[i]);
- memcpy(s, self->sl_list[i], len), s += len;
- if (++i >= self->sl_len)
- break;
- memcpy(s, sep, seplen), s += seplen;
- }
- *s = '\0';
- assert(s == retval + total);
- }
- return retval;
- }
- return su_strdup(home, "");
- }
- su_inline
- su_strlst_t *
- su_strlst_split0(su_strlst_t *l, char *str, char const *sep)
- {
- size_t n = sep ? strlen(sep) : 0;
- char *s;
- if (n > 0) {
- while ((s = strstr(str, sep))) {
- *s = '\0';
- if (!su_strlst_append(l, str))
- return NULL;
- str = s + n;
- }
- }
- if (!su_strlst_append(l, str))
- return NULL;
- return l;
- }
- /**Split a string.
- *
- * Splits a string to substrings. It returns a string list object. The
- * string to be split is not copied but instead modified in place. Use
- * su_strlst_dup_split() if you do not want to modify @a str.
- *
- * @param home home pointer
- * @param str string to be split
- * @param sep separator between substrings
- *
- * @return
- * Pointer to list of strings, if successful, or NULL upon an error.
- */
- su_strlst_t *
- su_strlst_split(su_home_t *home, char *str, char const *sep)
- {
- if (str) {
- su_strlst_t *l = su_strlst_create(home);
- if (!su_strlst_split0(l, str, sep))
- su_strlst_destroy(l), l = NULL;
- return l;
- }
- return NULL;
- }
- /**Duplicate and split a string.
- *
- * Duplicates a string and splits the result to substrings. It returns a
- * string list object. The string to be splitted is not modified.
- *
- * @param home home pointer
- * @param cstr string to be split
- * @param sep separator between substrings
- *
- * @return
- * Pointer to list of strings, if successful, or NULL upon an error.
- */
- su_strlst_t *su_strlst_dup_split(su_home_t *home,
- char const *cstr,
- char const *sep)
- {
- if (cstr) {
- su_strlst_t *l = su_strlst_create(home);
- if (l) {
- char *s = su_strdup(su_strlst_home(l), cstr);
- if (s && !su_strlst_split0(l, s, sep))
- su_strlst_destroy(l), l = NULL;
- }
- return l;
- }
- return NULL;
- }
- /** Get number of items in list.
- *
- * The function su_strlst_len() returns the number of items in the
- * string list.
- *
- */
- usize_t su_strlst_len(su_strlst_t const *l)
- {
- return l ? l->sl_len : 0;
- }
- /**Get a string array from list.
- *
- * The function su_strlst_get_array() returns an array of strings. The
- * length of the array is always one longer than the length of the string
- * list, and the last string in the returned array is always NULL.
- *
- * @param self pointer to a string list object
- *
- * @return
- * Pointer to array of strings, or NULL if error occurred.
- */
- char const **su_strlst_get_array(su_strlst_t *self)
- {
- if (self) {
- char const **retval;
- size_t size = sizeof(retval[0]) * (self->sl_len + 1);
- retval = su_alloc(self->sl_home, size);
- if (retval) {
- memcpy(retval, self->sl_list, sizeof(retval[0]) * self->sl_len);
- retval[self->sl_len] = NULL;
- return retval;
- }
- }
- return NULL;
- }
- /**Free a string array.
- *
- * The function su_strlst_free_array() discards a string array allocated
- * with su_strlst_get_array().
- *
- * @param self pointer to a string list object
- * @param array string array to be freed
- *
- */
- void su_strlst_free_array(su_strlst_t *self, char const **array)
- {
- if (array)
- su_free(self->sl_home, (void *)array);
- }
|