Commit e4eba7f3 authored by Pekka Pessi's avatar Pekka Pessi

More string manipulation functions

Added:
- su_strcat_all()
- su_slprintf(), su_slvprintf()
- su_strlst_create_with(), su_strlst_vcreate_with()
- su_strlst_create_with_dup(), su_strlst_vcreate_with_dup()

darcs-hash:20060315135105-65a35-4caeb11f3f16c296740b987cc0d9b2c4c772fcbf.gz
parent d7ded169
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
* Copyright (C) 2006 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
......@@ -114,6 +114,9 @@ SU_DLL char *su_strcat(su_home_t *home, char const *s1, char const *s2)
SU_DLL char *su_strndup(su_home_t *home, char const *s, int n)
__attribute__((__malloc__));
SU_DLL char *su_strcat_all(su_home_t *home, ...)
__attribute__((__malloc__));
SU_DLL char *su_sprintf(su_home_t *home, char const *fmt, ...)
__attribute__ ((__malloc__, __format__ (printf, 2, 3)));
......
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
* Copyright (C) 2006 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
......@@ -46,6 +46,22 @@ SU_DLL su_strlst_t *su_strlst_create(su_home_t *home)
/** Destroy a string list. */
SU_DLL void su_strlst_destroy(su_strlst_t *);
SU_DLL su_strlst_t *su_strlst_create_with(su_home_t *, char const *, ...)
__attribute__((__malloc__));
SU_DLL su_strlst_t *su_strlst_create_with_dup(su_home_t *, char const *, ...)
__attribute__((__malloc__));
SU_DLL su_strlst_t *su_strlst_vcreate_with(su_home_t *,
char const *,
va_list va)
__attribute__((__malloc__));
SU_DLL su_strlst_t *su_strlst_vcreate_with_dup(su_home_t *,
char const *,
va_list va)
__attribute__((__malloc__));
/** Shallow copy a string list. */
SU_DLL su_strlst_t *su_strlst_copy(su_home_t *home, su_strlst_t const *orig);
......@@ -58,6 +74,12 @@ SU_DLL char *su_strlst_dup_append(su_strlst_t *, char const *str);
/** Append a string to list. */
SU_DLL char const *su_strlst_append(su_strlst_t *, char const *str);
/** Append a formatted string to the list. */
char const *su_slprintf(su_strlst_t *self, char const *fmt, ...);
/** Append a formatted string to the list. */
char const *su_slvprintf(su_strlst_t *self, char const *fmt, va_list ap);
/** Get a numbered item from list. */
SU_DLL char const *su_strlst_item(su_strlst_t const *, unsigned i);
......
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
* Copyright (C) 2006 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
......@@ -23,13 +23,13 @@
*/
/**@ingroup su_alloc
*
*
* @file su_alloc_test.c
*
* Testing functions for su_alloc functions.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
*
* @date Created: Thu May 2 18:17:46 2002 ppessi
*/
......@@ -65,7 +65,7 @@ void exdestructor(void *arg)
}
/** Test basic memory home operations */
int test_alloc(void)
static int test_alloc(void)
{
exhome_t *h0, *h1, *h2, *h3;
su_home_t home[1] = { SU_HOME_INIT(home) };
......@@ -116,9 +116,9 @@ int test_alloc(void)
su_home_preload(home, 1, 1024 + 2 * 8);
TEST_1(c = su_zalloc(home, 64)); p0 = c; p1 = c + 1024;
TEST(c = su_realloc(home, c0 = c, 127), c0);
TEST(c = su_realloc(home, c0 = c, 127), c0);
TEST_1(c = c0 = su_zalloc(home, 1024 - 128));
TEST_1(c = c0 = su_zalloc(home, 1024 - 128));
TEST_1(p0 <= c); TEST_1(c < p1);
TEST(c = su_realloc(home, c, 128), c0);
TEST(c = su_realloc(home, c, 1023 - 128), c0);
......@@ -151,8 +151,11 @@ static int test_strdupcat(void)
TEST_S(su_strcat(home, "foo", "bar"), "foobar");
TEST_S(su_strndup(home, "foobar", 3), "foo");
TEST_S(su_strcat_all(home, NULL), "");
TEST_S(su_strcat_all(home, "a", "", "b", "", NULL), "ab");
su_home_deinit(home);
END();
}
......@@ -170,14 +173,14 @@ static int test_sprintf(char const *fmt, ...)
va_start(va, fmt);
TEST_S(su_vsprintf(home, fmt, va), "foo.bar");
TEST_S(su_sprintf(home, "foo%200s", "bar"),
TEST_S(su_sprintf(home, "foo%200s", "bar"),
"foo "
" "
" "
" bar");
su_home_deinit(home);
END();
}
......@@ -197,7 +200,7 @@ static int test_strlst(void)
parent->hs_size = (sizeof parent);
kids[0].hs_size = (sizeof kids[0]);
kids[1].hs_size = (sizeof kids[1]);
su_home_init_stats(home);
/* Test API for invalid arguments */
......@@ -249,12 +252,12 @@ static int test_strlst(void)
TEST_1(l = su_strlst_create(home));
su_home_init_stats(su_strlst_home(l));
TEST_S(su_strlst_join(l, home, "bar"), "");
TEST_S(su_strlst_join(l, home, "bar"), "");
TEST_S(su_strlst_append(l, foo), "foo");
TEST_S(su_strlst_dup_append(l, bar), "bar");
TEST_S(su_strlst_append(l, baz), "baz");
TEST_S((s = su_strlst_join(l, home, "!")), "foo!bar!baz");
TEST_S((s = su_strlst_join(l, home, "!")), "foo!bar!baz");
TEST_S(su_strlst_item(l, 0), foo);
TEST_S(su_strlst_item(l, 1), bar);
......@@ -264,15 +267,15 @@ static int test_strlst(void)
TEST_1(l1 = su_strlst_copy(su_strlst_home(l), l));
TEST_1(l2 = su_strlst_dup(su_strlst_home(l), l));
strcpy(foo, "hum"); strcpy(bar, "pah"); strcpy(baz, "hah");
TEST_S(su_strlst_dup_append(l1, "kuik"), "kuik");
TEST_S(su_strlst_dup_append(l2, "uik"), "uik");
TEST_S((s = su_strlst_join(l, home, ".")), "hum.bar.hah");
TEST_S((su_strlst_join(l1, home, ".")), "hum.bar.hah.kuik");
TEST_S((su_strlst_join(l2, home, ".")), "foo.bar.baz.uik");
TEST_S((s = su_strlst_join(l, home, ".")), "hum.bar.hah");
TEST_S((su_strlst_join(l1, home, ".")), "hum.bar.hah.kuik");
TEST_S((su_strlst_join(l2, home, ".")), "foo.bar.baz.uik");
su_strlst_destroy(l2);
......@@ -302,7 +305,7 @@ static int test_strlst(void)
TEST_S(su_strlst_append(l, "i"), "i");
TEST_S(su_strlst_append(l, "j"), "j");
TEST_S((s = su_strlst_join(l, home, "")), "abcdefghij");
TEST_S((s = su_strlst_join(l, home, "")), "abcdefghij");
TEST_S(su_strlst_append(l, "a"), "a");
TEST_S(su_strlst_append(l, "b"), "b");
TEST_S(su_strlst_append(l, "c"), "c");
......@@ -314,7 +317,7 @@ static int test_strlst(void)
TEST_S(su_strlst_append(l, "i"), "i");
TEST_S(su_strlst_append(l, "j"), "j");
TEST_S((s = su_strlst_join(l, home, "")), "abcdefghijabcdefghij");
TEST_S((s = su_strlst_join(l, home, "")), "abcdefghijabcdefghij");
su_home_get_stats(su_strlst_home(l), 0, kids + 1, (sizeof kids[1]));
su_home_stat_add(kids, kids + 1);
......@@ -322,7 +325,7 @@ static int test_strlst(void)
su_strlst_destroy(l);
su_home_get_stats(home, 1, parent, (sizeof parent));
su_home_check(home);
su_home_deinit(home);
......@@ -353,7 +356,7 @@ static int test_strlst(void)
TEST_1((l = su_strlst_split(home, s, "\n")));
TEST(su_strlst_len(l), 1);
}
{
int i;
......@@ -382,6 +385,45 @@ static int test_strlst(void)
TEST(su_strlst_len(l), 0);
}
{
char const *s0;
TEST_1(l = su_strlst_create_with(NULL, s0 = "a", "b", NULL));
TEST_1(su_strlst_item(l, 0) == s0);
TEST_S(su_strlst_item(l, 0), "a");
TEST_S(su_strlst_item(l, 1), "b");
TEST_1(su_strlst_item(l, 2) == NULL);
TEST_S(su_slprintf(l, "1: %u", 1), "1: 1");
TEST_S(su_slprintf(l, "1.0: %g", 1.0), "1.0: 1");
TEST_1(su_strlst_append(l, ""));
TEST_S(su_strlst_join(l, home, "\n"),
"a\n" "b\n" "1: 1\n" "1.0: 1\n");
TEST_VOID(su_strlst_destroy(l));
TEST_1(l2 = su_strlst_create_with_dup(NULL,
s0 = "0", "1", "2", "3",
"4", "5", "6", "7",
NULL));
TEST_1(su_strlst_item(l2, 0) != s0);
TEST_S(su_strlst_item(l2, 0), "0");
TEST_S(su_strlst_item(l2, 1), "1");
TEST_S(su_strlst_item(l2, 2), "2");
TEST_S(su_strlst_item(l2, 3), "3");
TEST_S(su_strlst_item(l2, 4), "4");
TEST_S(su_strlst_item(l2, 5), "5");
TEST_S(su_strlst_item(l2, 6), "6");
TEST_S(su_strlst_item(l2, 7), "7");
TEST_1(su_strlst_item(l2, 8) == NULL);
TEST_S(su_strlst_join(l2, home, ""), "01234567");
TEST_VOID(su_strlst_destroy(l2));
}
su_home_check(home);
su_home_deinit(home);
END();
......@@ -424,7 +466,7 @@ static int test_vectors(void)
TEST(su_vector_item(v, 3), NULL);
TEST(su_vector_item(v, (unsigned)-1), NULL);
TEST_1(!su_vector_is_empty(v));
su_vector_destroy(v);
TEST_1(v = su_vector_create(home, NULL));
......@@ -472,7 +514,7 @@ static int test_vectors(void)
su_vector_destroy(v);
su_vector_destroy(w);
TEST_1(v = su_vector_create(home, test_vector_free));
data1 = su_home_clone(home, sizeof(test_data_t));
data1->data = 1;
......@@ -489,7 +531,7 @@ static int test_vectors(void)
TEST(su_vector_append(v, data1), 0);
TEST(su_vector_append(v, data2), 0);
TEST(su_vector_append(v, data3), 0);
TEST(su_vector_append(v, data4), 0);
TEST(su_vector_append(v, data4), 0);
TEST(su_vector_len(v), 4);
......@@ -537,20 +579,20 @@ static int test_auto(void)
TEST_1(!su_home_auto(tmphome, sizeof tmphome[0]));
TEST_1(su_home_auto(tmphome, sizeof tmphome));
for (i = 0; i < 8192; i++)
TEST_1(su_alloc(tmphome, 12));
TEST_VOID(su_home_deinit(tmphome));
TEST_1(su_home_auto(tmphome, sizeof tmphome));
su_home_init_stats(tmphome);
for (i = 1; i < 8192; i++) {
TEST_1(b = su_realloc(tmphome, b, i));
b[i - 1] = (char)0xaa;
if ((i % 32) == 0)
TEST_1(b = su_realloc(tmphome, b, 1));
}
......@@ -563,7 +605,7 @@ static int test_auto(void)
This test depends on macro SU_HOME_AUTO_SIZE() calculating
offsetof(su_block_t, sub_nodes[7]) correctly with
((3 * sizeof (void *) + 4 * sizeof(unsigned) +
((3 * sizeof (void *) + 4 * sizeof(unsigned) +
7 * (sizeof (long) + sizeof(void *)) + 7)
*/
TEST_1(hs->hs_frees.hsf_preload == hs->hs_allocs.hsa_preload);
......@@ -574,7 +616,7 @@ static int test_auto(void)
TEST_1(b = su_alloc(tmphome, 1));
TEST_VOID(su_home_deinit(tmphome));
END();
}
......@@ -594,7 +636,7 @@ int main(int argc, char *argv[])
else
usage();
}
retval |= test_alloc();
retval |= test_strdupcat();
retval |= test_sprintf("%s.%s", "foo", "bar");
......
......@@ -101,7 +101,7 @@ char *su_vsprintf(su_home_t *home, char const *fmt, va_list ap)
*
* The function su_sprintf() print a string according to a @a fmt like
* printf() or snprintf(). The resulting string is copied to a memory area
* fresly allocated from a memory @a home. The returned string is reclaimed
* freshly allocated from a memory @a home. The returned string is reclaimed
* when @a home is destroyed. It can explicitly be freed with su_free() or
* free() if @a home is NULL.
*
......
......@@ -62,17 +62,17 @@ char *su_strdup(su_home_t *home, char const *s)
/**Concate two strings, allocate memory for result from @a home.
*
* The function su_strcat() concatenates the strings @a s1 and @a s2. It
* allocates @c strlen(s1)+strlen(s2)+1 bytes from @a home, copies the
* contents of @a s1 and @a s2 to the newly allocated memory, and returns
* pointer to the concatenated string.
* Concatenate the strings @a s1 and @a s2. The @c strlen(s1)+strlen(s2)+1
* bytes is allocated from @a home, the contents of @a s1 and @a s2 is
* copied to the newly allocated memory area, and pointer to the
* concatenated string is returned.
*
* @param home pointer to memory home
* @param s1 string to be first string
* @param s2 string to be first string
*
* @return The function su_strcat() returns pointer to the newly created
* string, or @c NULL upon an error.
* @return Pointer to the newly created string is returned, or @c NULL upon
* an error.
*/
char *su_strcat(su_home_t *home, char const *s1, char const *s2)
{
......@@ -95,6 +95,53 @@ char *su_strcat(su_home_t *home, char const *s1, char const *s2)
return retval;
}
/**Concate multiple strings, allocate memory for result from @a home.
*
* Concatenate the strings in list. The lenght of result is calculate,
* result is allocated from @a home, the contents of strings is copied to
* the newly allocated memory arex, and pointer to the concatenated string is
* returned.
*
* @param home pointer to memory home
* @param s,... strings to be concatenated
*
* @return Pointer to the newly created string is returned, or @c NULL upon
* an error.
*/
char *su_strcat_all(su_home_t *home, ...)
{
int i, n;
size_t size = 0;
va_list va;
char *s, *retval, *end;
/* Count number arguments and their size */
va_start(va, home);
s = va_arg(va, char *);
for (n = 0; s; s = va_arg(va, char *), n++)
size += strlen(s);
va_end(va);
retval = su_alloc(home, size + 1);
if (retval) {
s = retval;
end = s + size + 1;
va_start(va, home);
for (i = 0; i < n; i++)
s = memccpy(s, va_arg(va, char const *), '\0', end - s) - 1;
va_end(va);
retval[size] = '\0';
}
return retval;
}
/** Duplicate a string with given size, allocate memory from @a home.
*
* The function su_strndup() duplicates the string @a s. It allocates @c n+1
......
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
* Copyright (C) 2006 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
*
......@@ -40,12 +40,13 @@
* Example of concatenating a number of strings to @a s:
* @code
* su_strlst_t *l = su_strlist_create(home);
* su_strlst_append(l, su_sprintf(su_strlst_home(l), "a is: %d", a));
* su_strlst_append(l, su_sprintf(su_strlst_home(l), "b is: %d", b));
* su_strlst_append(l, su_sprintf(su_strlst_home(l), "c is: %d", c));
* 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_strlst_append(l, su_sprintf(su_strlst_home(l), "total: %d", a + b + c));
* su_strlst_append(l, "");
* su_slprintf(l, "total: %d", a + b + c));
* su_strlst_append(l, "=============");
* s = su_strlst_join(l, "\n");
* @endcode
*
......@@ -73,6 +74,9 @@
#include "config.h"
#include "sofia-sip/su_config.h"
#include "sofia-sip/su_strlst.h"
#include <stdlib.h>
#include <stddef.h>
#include <memory.h>
......@@ -81,8 +85,13 @@
#include <assert.h>
#include "sofia-sip/su_config.h"
#include "sofia-sip/su_strlst.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 };
......@@ -95,24 +104,141 @@ struct su_strlst_s
char const **sl_list;
};
/** Create a string list.
*
* The function su_strlst_create() creates a list of strings. The list is
* initially empty. It clones a memory home for the list from @a home.
*
*/
su_strlst_t *su_strlst_create(su_home_t *home)
/** 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;
int i, n, m;
size_t total, size;
m = 0, total = 0;
/* Count arguments and their length */
if (value) {
char const *s;
va_list va0;
self = su_home_clone(home, sizeof(*self) + N * sizeof(*self->sl_list));
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_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)
{
va_list va;
return su_strlst_vcreate_with_by(home, NULL, va, 0);
}
/** 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,
......@@ -209,9 +335,6 @@ static int su_strlst_increase(su_strlst_t *self)
}
/**Duplicate and append a string to list.
*
* The function su_strlst_append() duplicates and appends a string to a
* list.
*
* @param self pointer to a string list object
* @param str string to be duplicated and appended
......@@ -238,10 +361,10 @@ char *su_strlst_dup_append(su_strlst_t *self, char const *str)
return NULL;
}
/**Append a string to list.
/**Append a string to list.
*
* The function su_strlst_append() appends a string to a list. The string is
* not copied, and it @b must not be modified while string list exists.
* 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
......@@ -262,6 +385,57 @@ char const *su_strlst_append(su_strlst_t *self, char const *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 ... 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.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment