summaryrefslogtreecommitdiffstats
path: root/lib/qstring.c
diff options
context:
space:
mode:
authorChris Hall <GMCH@hestia.halldom.com>2010-04-06 02:10:30 +0100
committerChris Hall <GMCH@hestia.halldom.com>2010-04-06 02:10:30 +0100
commit8fea5ca7104c0d95108947661a4991b61b2ee06e (patch)
tree7ad44a658a61d4a8dfb43ca5b6122c5626f68ea0 /lib/qstring.c
parentc933cf7233f51f677ab01689f175ceb3dc5361f6 (diff)
downloadquagga-8fea5ca7104c0d95108947661a4991b61b2ee06e.tar.bz2
quagga-8fea5ca7104c0d95108947661a4991b61b2ee06e.tar.xz
First beta release
Various bug fixes and improvements. Running with a fair amount of debug/assert code, which must be removed at some date.
Diffstat (limited to 'lib/qstring.c')
-rw-r--r--lib/qstring.c434
1 files changed, 359 insertions, 75 deletions
diff --git a/lib/qstring.c b/lib/qstring.c
index f847e0b0..a3dc95cd 100644
--- a/lib/qstring.c
+++ b/lib/qstring.c
@@ -35,29 +35,18 @@
* Returns: address of qstring
*
* NB: assumes initialising a new structure. If not, then caller should
- * use qs_reset() or qs_set_empty().
+ * use qs_reset() or qs_clear().
*/
extern qstring
qs_init_new(qstring qs, size_t len)
{
if (qs == NULL)
- qs = XCALLOC(MTYPE_QSTRING, sizeof(qstring_t)) ;
+ qs = qs_new() ;
else
- memset(qs, 0, sizeof(qstring_t)) ;
-
- /* Zeroising has set:
- *
- * body = NULL -- no body
- * size = 0 -- no body
- *
- * len = 0
- * cp = 0
- *
- * Nothing more to do unless initial size != 0
- */
+ memset(qs, 0, sizeof(qstring_t)) ; /* see qs_new() */
if (len != 0)
- qs_alloc(qs, len) ;
+ return qs_make_to_length(qs, len) ;
return qs ;
} ;
@@ -65,48 +54,102 @@ qs_init_new(qstring qs, size_t len)
/*------------------------------------------------------------------------------
* Allocate or reallocate so that string is big enough for the given length.
*
- * Allocates to 16 byte boundaries.
+ * Allocate qstring if required. Returns with a body with size > 0.
*
- * Returns: the number of bytes *allocated*, which includes the byte for
- * possible trailing '\0'.
+ * Allocates to 16 byte boundaries with space for '\0' beyond given length.
*
- * NB: allocates EXTRA space for trailing '\0' beyond given length.
+ * Returns: address of qstring
+ *
+ * NB: allocates new body if the size == 0.
+ *
+ * If the qstring is a "dummy", its contents are now copied to the new
+ * real qstring body -- up to a maximum of the new length.
*/
-extern size_t
-qs_alloc(qstring qs, size_t len)
+extern qstring
+qs_make_to_length(qstring qs, size_t len)
{
- len = (len + 0x10) & ~(size_t)(0x10 - 1) ;
+ size_t size = (len + 0x10) & ~(size_t)(0x10 - 1) ;
- if (qs->body == NULL)
- {
- assert(qs->size == 0) ;
- qs->size = len ;
- qs->body = XMALLOC(MTYPE_QSTRING_BODY, qs->size) ;
- }
- else
+ if (qs == NULL)
+ qs = qs_new() ;
+
+ if (size > qs->size)
{
- assert(qs->size > 0) ;
- qs->size *= 2 ;
- if (qs->size < len)
- qs->size = len ;
- qs->body = XREALLOC(MTYPE_QSTRING_BODY, qs->body, qs->size) ;
- } ;
+ if (qs->size == 0)
+ {
+ void* old ;
+ old = qs->body ;
+
+ qs->size = size ;
+ qs->body = XMALLOC(MTYPE_QSTRING_BODY, qs->size) ;
+
+ if ((qs->len != 0) && (old != NULL))
+ memcpy(qs->body, old, (qs->len <= len) ? qs->len : len) ;
+ }
+ else
+ {
+ qs->size *= 2 ;
+ if (qs->size < size)
+ qs->size = size ;
+ qs->body = XREALLOC(MTYPE_QSTRING_BODY, qs->body, qs->size) ;
+ } ;
+ };
- return qs->size ;
+ return qs ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Add 'n' to the current string length, allocating or extending the body as
+ * required.
+ *
+ * Allocate qstring if required. Returns with a body with size > 0.
+ *
+ * Allocates to 16 byte boundaries with space for '\0' beyond new length.
+ *
+ * Returns: address of qstring
+ *
+ * also: sets char** p_ep to point at the *end* of the new len.
+ *
+ * NB: allocates new body if the size == 0.
+ *
+ * If the qstring is a "dummy", its contents are now copied to the new
+ * real qstring body -- up to a maximum of the new length.
+ */
+extern qstring
+qs_add_len(qstring qs, size_t n, char** p_ep)
+{
+ size_t len ;
+ len = (qs != NULL) ? qs->len + n : n ;
+
+ qs = qs_make_to_length(qs, len) ;
+
+ qs->len = len ;
+
+ *p_ep = (char*)qs->body + len ;
+
+ return qs ;
} ;
/*------------------------------------------------------------------------------
* Free body of qstring -- zeroise size, len and cp
+ *
+ * Does nothing if qstring is NULL
+ *
+ * NB: frees the body if the size != 0. So, a "dummy" qstring will not retain
+ * the old body.
*/
extern void
qs_free_body(qstring qs)
{
- if (qs->body != NULL)
- XFREE(MTYPE_QSTRING_BODY, qs->body) ; /* sets qs->body = NULL */
+ if (qs != NULL)
+ {
+ if (qs->size != 0)
+ XFREE(MTYPE_QSTRING_BODY, qs->body) ; /* sets qs->body = NULL */
- qs->size = 0 ;
- qs->len = 0 ;
- qs->cp = 0 ;
+ qs->size = 0 ;
+ qs->len = 0 ;
+ qs->cp = 0 ;
+ } ;
} ;
/*------------------------------------------------------------------------------
@@ -115,73 +158,102 @@ qs_free_body(qstring qs)
* If not freeing the structure, zeroise size, len and cp -- qs_free_body()
*
* Returns: NULL if freed the structure
- * address of structure, otherwise
+ * address of structure (if any), otherwise
+ *
+ * NB: frees the body if the size != 0. So, a "dummy" qstring will not retain
+ * the old body.
*/
extern qstring
qs_reset(qstring qs, int free_structure)
{
- if (qs->body != NULL)
- XFREE(MTYPE_QSTRING_BODY, qs->body) ; /* sets qs->body = NULL */
-
- if (free_structure)
- XFREE(MTYPE_QSTRING, qs) ; /* sets qs = NULL */
- else
+ if (qs != NULL)
{
- qs->size = 0 ;
- qs->len = 0 ;
- qs->cp = 0 ;
- } ;
+ if (qs->size != 0)
+ XFREE(MTYPE_QSTRING_BODY, qs->body) ; /* sets qs->body = NULL */
+ if (free_structure)
+ XFREE(MTYPE_QSTRING, qs) ; /* sets qs = NULL */
+ else
+ {
+ qs->size = 0 ;
+ qs->len = 0 ;
+ qs->cp = 0 ;
+ } ;
+ } ;
return qs ;
} ;
/*==============================================================================
- * printf(0 and vprintf() type functions
+ * printf() and vprintf() type functions
*/
/*------------------------------------------------------------------------------
* Formatted print to qstring -- cf printf()
+ *
+ * Allocate qstring if required.
+ *
+ * Returns: address of qstring if OK
+ * NULL if failed (unlikely though that is)
*/
-extern int
+extern qstring
qs_printf(qstring qs, const char* format, ...)
{
va_list args;
- int result ;
va_start (args, format);
- result = qs_vprintf(qs, format, args);
+ qs = qs_vprintf(qs, format, args);
va_end (args);
- return result;
+ return qs;
} ;
/*------------------------------------------------------------------------------
* Formatted print to qstring -- cf vprintf()
*
- * Note that vsnprintf() returns the length of what it would like to have
- * produced, if it had the space. That length does not include the trailing
- * '\0'.
+ * Allocate qstring if required.
*
- * Also note that given a zero length the string address may be NULL, and the
- * result is still the length required.
+ * Returns: address of qstring if OK
+ * NULL if failed (unlikely though that is)
*/
-extern int
+extern qstring
qs_vprintf(qstring qs, const char *format, va_list args)
{
va_list ac ;
- int len ;
+ int len ;
+ qstring qqs ;
+
+ qqs = qs ;
+ if (qs == NULL)
+ qs = qs_new() ;
while (1)
{
+ /* Note that vsnprintf() returns the length of what it would like to have
+ * produced, if it had the space. That length does not include the
+ * trailing '\0'.
+ *
+ * Also note that given a zero length the string address may be NULL, and
+ * the result is still the length required.
+ */
va_copy(ac, args);
qs->len = len = vsnprintf (qs->body, qs->size, format, ac) ;
va_end(ac);
+ if (len < 0)
+ break ;
+
if (len < (int)qs->size)
- return len ; /* quit if done (or error) */
+ return qs ;
- qs_alloc(qs, len) ;
+ qs_make_to_length(qs, len) ;
} ;
+
+ if (qqs == NULL)
+ qs_reset_free(qs) ; /* discard what was allocated */
+ else
+ qs->len = 0 ;
+
+ return NULL ;
} ;
/*==============================================================================
@@ -191,37 +263,249 @@ qs_vprintf(qstring qs, const char *format, va_list args)
/*------------------------------------------------------------------------------
* Set qstring to be copy of the given string.
*
+ * Allocates a qstring, if required.
+ *
* Sets qs->len to the length of the string (excluding trailing '\0')
*
- * NB: if stc == NULL, sets qstring to be zero length string.
+ * NB: if src == NULL, sets qstring to be zero length string.
+ *
+ * Returns: address of the qstring copied to.
+ *
+ * NB: if copying to a dummy qstring, the old body is simply discarded.
*/
-extern size_t
+extern qstring
qs_set(qstring qs, const char* src)
{
- qs_set_len(qs, (src != NULL) ? strlen(src) : 0) ;
+ qs = qs_set_len(qs, (src != NULL) ? strlen(src) : 0) ;
if (qs->len != 0)
memcpy(qs->body, src, qs->len + 1) ;
else
*((char*)qs->body) = '\0' ;
- return qs->len ;
+ return qs ;
} ;
/*------------------------------------------------------------------------------
* Set qstring to be leading 'n' bytes of given string.
*
- * NB: src string MUST be at least that long.
+ * Allocates qstring if required.
+ *
+ * Inserts '\0' terminator after the 'n' bytes copied.
+ *
+ * Returns: address of the qstring copied to.
*
- * NB: src may not be NULL unless len == 0.
+ * NB: src string MUST be at least 'n' bytes long.
+ *
+ * NB: src may not be NULL unless n == 0.
+ *
+ * NB: if copying to a dummy qstring, the old body is simply discarded.
*/
-extern size_t
+extern qstring
qs_set_n(qstring qs, const char* src, size_t n)
{
- qs_need(qs, n) ; /* sets qs->len */
+ qs = qs_set_len(qs, n) ; /* ensures have body > n */
if (n != 0)
memcpy(qs->body, src, n) ;
*((char*)qs->body + n) = '\0' ;
- return n ;
+ return qs ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Append given string to a qstring.
+ *
+ * Allocates a qstring, if required.
+ *
+ * Sets qs->len to the length of the result (excluding trailing '\0')
+ *
+ * NB: if src == NULL, appends nothing -- but result will be '\0' terminated.
+ *
+ * Returns: address of the qstring copied to.
+ *
+ * NB: if copying to a dummy qstring, the old body is simply discarded.
+ */
+extern qstring qs_append(qstring qs, const char* src)
+{
+ size_t n ;
+ char* ep ;
+
+ n = (src != NULL) ? strlen(src) : 0 ;
+
+ qs = qs_add_len(qs, n, &ep) ;
+ ep = (char*)qs->body + qs->len ;
+
+ if (n != 0)
+ memcpy(ep - n, src, n + 1) ;
+ else
+ *ep = '\0' ;
+
+ return qs ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set qstring to be leading 'n' bytes of given string.
+ *
+ * Allocates qstring if required.
+ *
+ * Returns: address of the qstring copied to.
+ *
+ * NB: src string MUST be at least 'n' bytes long.
+ *
+ * NB: src may not be NULL unless n == 0.
+ *
+ * NB: if n == 0, appends nothing -- but result will be '\0' terminated.
+ *
+ * NB: if copying to a dummy qstring, the old body is simply discarded.
+ *
+ * NB: if copying to a dummy qstring, the old body is simply discarded.
+ */
+extern qstring
+qs_append_n(qstring qs, const char* src, size_t n)
+{
+ char* ep ;
+
+ qs = qs_add_len(qs, n, &ep) ;
+
+ if (n != 0)
+ memcpy(ep - n, src, n) ;
+
+ *ep = '\0' ;
+
+ return qs ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Copy one qstring to another
+ *
+ * If both are NULL, returns NULL.
+ *
+ * Otherwise if dst is NULL, creates a new qstring.
+ *
+ * Sets dst: body = copy of src->len bytes of src->body -- '\0' terminated.
+ * cp = src->cp
+ * len = src->len
+ *
+ * Where a NULL src has zero cp and len.
+ *
+ * If not NULL, the destination is guaranteed to have a body, and that will be
+ * '\0' terminated.
+ *
+ * Returns: the destination qstring
+ *
+ * NB: if copying to a dummy qstring, the old body is simply discarded.
+ */
+extern qstring
+qs_copy(qstring dst, qstring src)
+{
+ size_t n ;
+
+ if (src == NULL)
+ {
+ if (dst == NULL)
+ return dst ;
+
+ n = 0 ;
+ dst->cp = 0 ;
+ }
+ else
+ {
+ if (dst == NULL)
+ dst = qs_new() ;
+
+ n = src->len ;
+ dst->cp = src->cp ;
+ } ;
+
+ qs_set_len(dst, n) ;
+
+ if (n > 0)
+ memcpy(dst->body, src->body, n) ;
+
+ *((char*)dst->body + n) = '\0' ;
+
+ return dst ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Compare significant parts of two qstrings.
+ *
+ * By significant, mean excluding leading/trailing isspace() and treating
+ * multiple isspace() as single isspace().
+ *
+ * Compares the 'len' portions of the strings.
+ *
+ * If either is NULL, it is deemed to be an empty string.
+ *
+ * Returns: -1 => a < b
+ * 0 => a == b
+ * +1 => a > b
+ */
+extern int
+qs_cmp_sig(qstring a, qstring b)
+{
+ const unsigned char* p_a ;
+ const unsigned char* e_a ;
+ const unsigned char* p_b ;
+ const unsigned char* e_b ;
+
+ /* Set up pointers and dispense with leading and trailing isspace()
+ *
+ * Dummy up if NULL
+ */
+ if (a != NULL)
+ {
+ p_a = a->body ;
+ e_a = p_a + a->len ;
+
+ while ((p_a < e_a) && isspace(*p_a))
+ ++p_a ;
+ while ((p_a < e_a) && isspace(*(e_a - 1)))
+ --e_a ;
+ }
+ else
+ {
+ p_a = NULL ;
+ e_a = NULL ;
+ }
+
+ if (b != NULL)
+ {
+ p_b = b->body ;
+ e_b = p_b + b->len ;
+
+ while ((p_b < e_b) && isspace(*p_b))
+ ++p_b ;
+ while ((p_b < e_b) && isspace(*(e_b - 1)))
+ --e_b ;
+ }
+ else
+ {
+ p_b = NULL ;
+ e_b = NULL ;
+ } ;
+
+ /* Now set about finding the first difference */
+ while ((p_a != e_a) && (p_b != e_b))
+ {
+ if (isspace(*p_a) && isspace(*p_b))
+ {
+ do { ++p_a ; } while isspace(*p_a) ;
+ do { ++p_b ; } while isspace(*p_b) ;
+ } ;
+
+ if (*p_a != *p_b)
+ return (*p_a < *p_b) ? -1 : +1 ;
+
+ ++p_a ;
+ ++p_b ;
+ } ;
+
+ /* No difference before ran out of one or both */
+ if (p_a != e_a)
+ return +1 ;
+ else if (p_b != e_b)
+ return -1 ;
+ else
+ return 0 ;
} ;