Wed, 17 Jul 2013 15:56:01 +0200
some fixes and some documentation
test/string_tests.c | file | annotate | diff | comparison | revisions | |
ucx/map.c | file | annotate | diff | comparison | revisions | |
ucx/mempool.c | file | annotate | diff | comparison | revisions | |
ucx/properties.c | file | annotate | diff | comparison | revisions | |
ucx/string.c | file | annotate | diff | comparison | revisions | |
ucx/string.h | file | annotate | diff | comparison | revisions | |
ucx/ucx.h | file | annotate | diff | comparison | revisions |
--- a/test/string_tests.c Wed Jul 17 12:32:03 2013 +0200 +++ b/test/string_tests.c Wed Jul 17 15:56:01 2013 +0200 @@ -41,9 +41,9 @@ } UCX_TEST_IMPLEMENT(test_sstr_len_cat) { - sstr_t s1 = S("1234"); - sstr_t s2 = S(".:.:."); - sstr_t s3 = S("X"); + sstr_t s1 = ST("1234"); + sstr_t s2 = ST(".:.:."); + sstr_t s3 = ST("X"); size_t len = sstrnlen(3, s1, s2, s3); sstr_t cat; @@ -72,7 +72,7 @@ UCX_TEST_IMPLEMENT(test_sstrsplit) { const char *original = "this,is,a,csv,string"; - sstr_t test = S("this,is,a,csv,string"); /* use copy of original here */ + sstr_t test = ST("this,is,a,csv,string"); /* use copy of original here */ size_t n; sstr_t *list; @@ -80,12 +80,12 @@ /* Nullpointer check */ n = 0; - UCX_TEST_ASSERT(sstrsplit(test, ST(""), &n) == NULL, + UCX_TEST_ASSERT(sstrsplit(test, S(""), &n) == NULL, "empty delimiter must return NULL"); /* no delimiter occurence (ndo) */ n = 0; - list = sstrsplit(test, ST("z"), &n); + list = sstrsplit(test, S("z"), &n); UCX_TEST_ASSERT(n == 1, "ndo, list length must be 1"); UCX_TEST_ASSERT(strcmp(list[0].ptr, original) == 0, "ndo, " "original string shall be returned as single list element"); @@ -95,7 +95,7 @@ /* partially matching delimiter (pmd) */ n = 0; - list = sstrsplit(test, ST("stringbuilder"), &n); + list = sstrsplit(test, S("stringbuilder"), &n); UCX_TEST_ASSERT(n == 1, "pmd, list length must be 1"); UCX_TEST_ASSERT(strcmp(list[0].ptr, original) == 0, "pmd, " "original string shall be returned as single list element"); @@ -105,7 +105,7 @@ /* matching single-char delimiter (mscd) */ n = 0; - list = sstrsplit(test, ST(","), &n); + list = sstrsplit(test, S(","), &n); UCX_TEST_ASSERT(n == 5, "mscd, list length must be 5"); UCX_TEST_ASSERT(strcmp(list[0].ptr, "this") == 0, "mscd, item 0 mismatch"); UCX_TEST_ASSERT(strcmp(list[1].ptr, "is") == 0, "mscd, item 1 mismatch"); @@ -118,7 +118,7 @@ /* matching multi-char delimiter (mmcd) */ n = 0; - list = sstrsplit(test, ST("is"), &n); + list = sstrsplit(test, S("is"), &n); UCX_TEST_ASSERT(n == 3, "mscd, list length must be 3"); UCX_TEST_ASSERT(strcmp(list[0].ptr, "th") == 0, "mmcd, item 0 mismatch"); UCX_TEST_ASSERT(strcmp(list[1].ptr, ",") == 0, "mmcd, item 1 mismatch"); @@ -130,7 +130,7 @@ /* bounded list using single-char delimiter (blsc) */ n = 3; - list = sstrsplit(test, ST(","), &n); + list = sstrsplit(test, S(","), &n); UCX_TEST_ASSERT(n == 3, "blsc, list length must be 3"); UCX_TEST_ASSERT(strcmp(list[0].ptr, "this") == 0, "blsc, item 0 mismatch"); UCX_TEST_ASSERT(strcmp(list[1].ptr, "is") == 0, "blsc, item 1 mismatch"); @@ -142,7 +142,7 @@ /* bounded list using multi-char delimiter (blmc) */ n = 2; - list = sstrsplit(test, ST("is"), &n); + list = sstrsplit(test, S("is"), &n); UCX_TEST_ASSERT(n == 2, "blmc, list length must be 2"); UCX_TEST_ASSERT(strcmp(list[0].ptr, "th") == 0, "blmc, item 0 mismatch"); UCX_TEST_ASSERT(strcmp(list[1].ptr, ",is,a,csv,string") == 0, @@ -153,7 +153,7 @@ /* start with delimiter (swd) */ n = 0; - list = sstrsplit(test, ST("this"), &n); + list = sstrsplit(test, S("this"), &n); UCX_TEST_ASSERT(n == 2, "swd, list length must be 2"); UCX_TEST_ASSERT(list[0].length == 0, "swd, first item must be empty"); UCX_TEST_ASSERT(strcmp(list[1].ptr, ",is,a,csv,string") == 0, @@ -164,7 +164,7 @@ /* end with delimiter (ewd) */ n = 0; - list = sstrsplit(test, ST("string"), &n); + list = sstrsplit(test, S("string"), &n); UCX_TEST_ASSERT(n == 2, "ewd, list length must be 2"); UCX_TEST_ASSERT(strcmp(list[0].ptr, "this,is,a,csv,") == 0, "swd, first item corrupt"); @@ -175,14 +175,14 @@ /* exact match (exm) */ n = 0; - list = sstrsplit(test, ST("this,is,a,csv,string"), &n); + list = sstrsplit(test, S("this,is,a,csv,string"), &n); UCX_TEST_ASSERT(n == 0, "exm, list length must be 0"); UCX_TEST_ASSERT(list == NULL, "exm, list must be NULL"); free(list); /* substring (subs) */ n = 0; - list = sstrsplit(test, ST("this,is,a,csv,string,with,extension"), &n); + list = sstrsplit(test, S("this,is,a,csv,string,with,extension"), &n); UCX_TEST_ASSERT(n == 1, "subs, list length must be 1"); UCX_TEST_ASSERT(strcmp(list[0].ptr, original) == 0, "subs, single item must be the original string");
--- a/ucx/map.c Wed Jul 17 12:32:03 2013 +0200 +++ b/ucx/map.c Wed Jul 17 15:56:01 2013 +0200 @@ -64,7 +64,7 @@ return map; } -void ucx_map_free_elmlist(UcxMap *map) { +static void ucx_map_free_elmlist(UcxMap *map) { for (size_t n = 0 ; n < map->size ; n++) { UcxMapElement *elem = map->map[n]; if (elem != NULL) {
--- a/ucx/mempool.c Wed Jul 17 12:32:03 2013 +0200 +++ b/ucx/mempool.c Wed Jul 17 15:56:01 2013 +0200 @@ -112,7 +112,7 @@ return newm + sizeof(ucx_destructor); } } - fprintf(stderr, "FATAL: 0x%08"PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", + fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", (intptr_t)ptr, (intptr_t)pool); exit(1); } else { @@ -136,7 +136,7 @@ return; } } - fprintf(stderr, "FATAL: 0x%08"PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", + fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", (intptr_t)ptr, (intptr_t)pool); exit(1); }
--- a/ucx/properties.c Wed Jul 17 12:32:03 2013 +0200 +++ b/ucx/properties.c Wed Jul 17 15:56:01 2013 +0200 @@ -199,17 +199,11 @@ sstr_t name; sstr_t value; while(ucx_properties_next(parser, &name, &value)) { - name = sstrdup_alloc(map->allocator, name); - if(!name.ptr) { - return 1; - } - value = sstrdup_alloc(map->allocator, value); + value = sstrdupa(map->allocator, value); if(!value.ptr) { - map->allocator->free(map->allocator->pool, value.ptr); return 1; } if(ucx_map_sstr_put(map, name, value.ptr)) { - map->allocator->free(map->allocator->pool, name.ptr); map->allocator->free(map->allocator->pool, value.ptr); return 1; }
--- a/ucx/string.c Wed Jul 17 12:32:03 2013 +0200 +++ b/ucx/string.c Wed Jul 17 15:56:01 2013 +0200 @@ -33,17 +33,17 @@ #include "string.h" #include "allocator.h" -sstr_t sstr(char *s) { +sstr_t sstr(char *cstring) { sstr_t string; - string.ptr = s; - string.length = strlen(s); + string.ptr = cstring; + string.length = strlen(cstring); return string; } -sstr_t sstrn(char *s, size_t n) { +sstr_t sstrn(char *cstring, size_t length) { sstr_t string; - string.ptr = s; - string.length = n; + string.ptr = cstring; + string.length = length; return string; } @@ -52,7 +52,7 @@ size_t size = s.length; va_start(ap, s); - for (size_t i = 0 ; i < n-1 ; i++) { + for (size_t i = 1 ; i < n ; i++) { sstr_t str = va_arg(ap, sstr_t); size += str.length; } @@ -175,25 +175,20 @@ } int sstrcmp(sstr_t s1, sstr_t s2) { - return strncmp(s1.ptr, s2.ptr, s1.length>s2.length ? s2.length: s1.length); + if (s1.length == s2.length) { + return memcmp(s1.ptr, s2.ptr, s1.length); + } else if (s1.length > s2.length) { + return 1; + } else { + return -1; + } } sstr_t sstrdup(sstr_t s) { - sstr_t newstring; - newstring.ptr = (char*) malloc(s.length + 1); - if (newstring.ptr) { - newstring.length = s.length; - newstring.ptr[newstring.length] = 0; - - memcpy(newstring.ptr, s.ptr, s.length); - } else { - newstring.length = 0; - } - - return newstring; + return sstrdupa(ucx_default_allocator(), s); } -sstr_t sstrdup_alloc(UcxAllocator *allocator, sstr_t s) { +sstr_t sstrdupa(UcxAllocator *allocator, sstr_t s) { sstr_t newstring; newstring.ptr = (char*)allocator->malloc(allocator->pool, s.length + 1); if (newstring.ptr) {
--- a/ucx/string.h Wed Jul 17 12:32:03 2013 +0200 +++ b/ucx/string.h Wed Jul 17 15:56:01 2013 +0200 @@ -25,51 +25,98 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ +/** + * Bounded string implementation. + * + * The UCX strings (<code>sstr_t</code>) provide an alternative to C strings. + * The main difference to C strings is, that <code>sstr_t</code> does <b>not + * need to be <code>NULL</code>-terminated</b>. Instead the length is stored + * within the structure. + * + * When using <code>sstr_t</code>, developers must be full aware of what type + * of string (<code>NULL</code>-terminated) or not) they are using, when + * accessing the <code>char* ptr</code> directly. + * + * The UCX string module provides some common string functions, known from + * standard libc, working with <code>sstr_t</code>. + * + * @file string.h + * @author Mike Becker + * @author Olaf Wintermann + */ -#ifndef _SSTRING_H -#define _SSTRING_H +#ifndef UCX_STRING_H +#define UCX_STRING_H #include "ucx.h" #include "allocator.h" #include <stddef.h> -/* use macros for literals only */ -#define S(s) { (char*)s, sizeof(s)-1 } -#define ST(s) sstrn((char*)s, sizeof(s)-1) +/** Shortcut for a <code>sstr_t struct</code> literal. */ +#define ST(s) { (char*)s, sizeof(s)-1 } +/** Shortcut for the conversion of a C string to a <code>sstr_t</code>. */ +#define S(s) sstrn((char*)s, sizeof(s)-1) #ifdef __cplusplus extern "C" { #endif -typedef struct sstring { +/** + * The UCX string structure. + */ +typedef struct { + /** A reference to the string (<b>not necessarily <code>NULL</code> + * -terminated</b>) */ char *ptr; + /** The length of the string */ size_t length; } sstr_t; -/* - * creates a new sstr_t from a null terminated string +/** + * Creates a new sstr_t based on a C string. + * + * The length is implicitly inferred by using a call to <code>strlen()</code>. * - * s null terminated string + * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you + * do want a copy, use sstrdup() on the return value of this function. + * + * @param cstring the C string to wrap + * @return a new sstr_t containing the C string + * + * @see sstrn() */ -sstr_t sstr(char *s); +sstr_t sstr(char *cstring); -/* - * creates a new sstr_t from a string and length +/** + * Creates a new sstr_t of the specified length based on a C string. * - * s string - * n length of string + * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you + * do want a copy, use sstrdup() on the return value of this function. + * + * @param cstring the C string to wrap + * @param length the length of the string + * @return a new sstr_t containing the C string + * + * @see sstr() + * @see S() */ -sstr_t sstrn(char *s, size_t n); +sstr_t sstrn(char *cstring, size_t length); -/* - * gets the length of n sstr_t strings +/** + * Returns the cumulated length of all specified strings. * - * n number of strings - * s string - * ... strings + * At least one string must be specified. + * + * <b>Attention:</b> if the count argument does not match the count of the + * specified strings, the behavior is undefined. + * + * @param count the total number of specified strings (so at least 1) + * @param string the first string + * @param ... all other strings + * @return the cumulated length of all strings */ -size_t sstrnlen(size_t n, sstr_t s, ...); +size_t sstrnlen(size_t count, sstr_t string, ...); /* @@ -115,10 +162,32 @@ */ sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n); +/** + * Compares two UCX strings with standard <code>memcmp()</code>. + * + * At first it compares the sstr_t.length attribute of the two strings. The + * <code>memcmp()</code> function is called, if and only if the lengths match. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the result of + * <code>memcmp()</code> otherwise (i.e. 0 if the strings match) + */ int sstrcmp(sstr_t s1, sstr_t s2); -sstr_t sstrdup(sstr_t s); -sstr_t sstrdup_alloc(UcxAllocator *allocator, sstr_t s); +/** + * Creates a duplicate of the specified string. + * + * The new sstr_t will contain a copy allocated by standard + * <code>malloc()</code>. So developers <b>MUST</b> pass the sstr_t.ptr to + * <code>free()</code>. + * + * @param string the string to duplicate + * @return a duplicate of the argument + */ +sstr_t sstrdup(sstr_t string); +sstr_t sstrdupa(UcxAllocator *allocator, sstr_t s); sstr_t sstrtrim(sstr_t string); @@ -126,4 +195,4 @@ } #endif -#endif /* _SSTRING_H */ +#endif /* UCX_STRING_H */
--- a/ucx/ucx.h Wed Jul 17 12:32:03 2013 +0200 +++ b/ucx/ucx.h Wed Jul 17 15:56:01 2013 +0200 @@ -51,7 +51,6 @@ * * The first argument is the type of the list and its elements (e.g. UcxList). * The structure invariant of the list must be as follows: - * * <ul> * <li>a first (non-<code>NULL</code>) element</li> * <li>for each element a reference to the <code>next</code> element (the @@ -107,7 +106,8 @@ * source and destination. * * The arguments shall contain (in ascending order): a pointer to the source, - * the length of one element, the element count, a pointer to the destination. + * the length of one element, the element count and a pointer to the + * destination. */ typedef size_t(*write_func)(const void*, size_t, size_t, void*); @@ -119,8 +119,8 @@ * source and destination. * * The arguments shall contain (in ascending order): a pointer to the - * destination, the length of one element, the element count, a pointer to the - * source. + * destination, the length of one element, the element count and a pointer to + * the source. */ typedef size_t(*read_func)(void*, size_t, size_t, void*);