summaryrefslogtreecommitdiffstats
path: root/lib/qstring.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/qstring.h')
-rw-r--r--lib/qstring.h529
1 files changed, 242 insertions, 287 deletions
diff --git a/lib/qstring.h b/lib/qstring.h
index 0597eda8..5b1d4932 100644
--- a/lib/qstring.h
+++ b/lib/qstring.h
@@ -22,23 +22,11 @@
#ifndef _ZEBRA_QSTRING_H
#define _ZEBRA_QSTRING_H
-#include "zebra.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
+#include "misc.h"
+#include "vargs.h"
+#include "zassert.h"
#include "memory.h"
-
-#ifndef Inline
-#define Inline static inline
-#endif
-
-/* GCC have printf type attribute check. */
-#ifdef __GNUC__
-#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
-#else
-#define PRINTF_ATTRIBUTE(a,b)
-#endif /* __GNUC__ */
+#include "elstring.h"
/*==============================================================================
* These "qstrings" address address the lack of a flexible length string in 'C'.
@@ -49,24 +37,32 @@
*
* The caller does, however, have to explicitly release the contents of a
* qstring when it is done with.
+ *
+ *
+ *
*/
+struct qstring
+{
+ elstring_t els ; /* *embedded* */
+
+ usize size ; /* of the els body */
-typedef struct qstring qstring_t ;
+ usize cp ;
+
+ usize b_size ;
+ void* b_body ;
+} ;
+
+typedef struct qstring qstring_t[1] ;
typedef struct qstring* qstring ;
-struct qstring
+/* Setting an qstring object to all zeros is enough to initialise it to
+ * an empty string -- including the embedded elstring.
+ */
+CONFIRM(ELSTRING_INIT_ALL_ZEROS) ;
+enum
{
- union
- {
- void* body ;
- const void* const_body ;
- char* char_body ;
- unsigned char* uchar_body ;
- } ;
- size_t size ;
-
- size_t len ;
- size_t cp ;
+ QSTRING_INIT_ALL_ZEROS = true
} ;
/*------------------------------------------------------------------------------
@@ -75,92 +71,139 @@ struct qstring
* NB: if the body has not yet been allocated, these functions will return
* NULL or NULL + the offset.
*/
-Inline char* /* pointer to body of qstring */
-qs_chars(qstring qs)
+Inline elstring
+qs_els_nn(qstring qs)
{
- return (char*)qs->body ;
+ return qs->els ;
} ;
-Inline unsigned char* /* pointer to body of qstring */
-qs_bytes(qstring qs)
+Inline elstring
+qs_els(qstring qs)
{
- return (unsigned char*)qs->body ;
+ return qs->els ;
} ;
-Inline char* /* pointer to given offset in qstring */
-qs_chars_at(qstring qs, size_t off)
+Inline void*
+qs_body_nn(qstring qs) /* pointer to body of qstring (not NULL) */
{
- return qs_chars(qs) + off ;
+ return els_body_nn(qs->els) ;
} ;
-Inline unsigned char* /* pointer to given offset in qstring */
-qs_bytes_at(qstring qs, size_t off)
+Inline void* /* pointer to body of qstring */
+qs_body(qstring qs)
{
- return qs_bytes(qs) + off ;
+ return (qs != NULL) ? qs_body_nn(qs) : NULL ;
} ;
-Inline char* /* pointer to 'cp' offset in qstring */
-qs_cp_char(qstring qs)
+Inline void /* set pointer to body of qstring (not NULL) */
+qs_set_body_nn(qstring qs, const void* body)
+{
+ els_set_body_nn(qs->els, body) ; /* sets term = fase */
+} ;
+
+Inline ulen /* length of qstring (not NULL) */
+qs_len_nn(qstring qs)
+{
+ return els_len_nn(qs->els) ;
+} ;
+
+Inline ulen /* length of qstring */
+qs_len(qstring qs)
+{
+ return (qs != NULL) ? qs_len_nn(qs) : 0 ;
+} ;
+
+Inline void /* set length of qstring (not NULL) */
+qs_do_set_len_nn(qstring qs, ulen len)
+{
+ els_set_len_nn(qs->els, len) ; /* sets term = false */
+} ;
+
+Inline ulen /* cp of qstring (not NULL) */
+qs_cp_nn(qstring qs)
+{
+ return qs->cp ;
+} ;
+
+Inline ulen /* cp of qstring */
+qs_cp(qstring qs)
+{
+ return (qs != NULL) ? qs_cp_nn(qs) : 0 ;
+} ;
+
+Inline void /* set cp of qstring (not NULL) */
+qs_do_set_cp_nn(qstring qs, ulen cp)
+{
+ qs->cp = cp ;
+} ;
+
+Inline char* /* pointer to given offset in qstring */
+qs_char_at_nn(qstring qs, usize off)
+{
+ char* p ;
+ p = qs_body_nn(qs) ;
+ return (p != NULL) ? p + off : NULL ;
+} ;
+
+Inline char* /* pointer to given offset in qstring */
+qs_char_at(qstring qs, usize off)
{
- return qs_chars_at(qs, qs->cp) ;
+ return (qs != NULL) ? qs_char_at_nn(qs, off) : NULL ;
} ;
-Inline unsigned char* /* pointer to 'cp' offset in qstring */
-qs_cp_byte(qstring qs)
+Inline char* /* pointer to 'cp' offset in qstring */
+qs_cp_char(qstring qs)
{
- return qs_bytes_at(qs, qs->cp) ;
+ return (qs != NULL) ? qs_char_at_nn(qs, qs_cp_nn(qs)) : NULL ;
} ;
-Inline char* /* pointer to 'len' offset in qstring */
+Inline char* /* pointer to 'len' offset in qstring */
qs_ep_char(qstring qs)
{
- return qs_chars_at(qs, qs->len) ;
+ return (qs != NULL) ? qs_char_at_nn(qs, qs_len_nn(qs)) : NULL ;
+} ;
+
+Inline bool /* whether qstring is known to be terminated */
+qs_term_nn(qstring qs)
+{
+ return els_term_nn(qs->els) ;
} ;
-Inline unsigned char* /* pointer to 'len' offset in qstring */
-qs_ep_byte(qstring qs)
+Inline void /* set qstring is known to be terminated */
+qs_set_term_nn(qstring qs, bool how)
{
- return qs_bytes_at(qs, qs->len) ;
+ return els_set_term_nn(qs->els, how) ;
} ;
/*==============================================================================
* Functions
*/
-extern qstring qs_init_new(qstring qs, size_t len) ;
-extern qstring qs_make_to_length(qstring qs, size_t len) ;
-extern void qs_free_body(qstring qs) ;
-extern qstring qs_reset(qstring qs, int free_structure) ;
+extern qstring qs_new(void) ;
+extern qstring qs_init_new(qstring qs, usize len) ;
+extern qstring qs_reset(qstring qs, free_keep_b free_structure) ;
-#define qs_reset_keep(qs) qs_reset(qs, 0)
-#define qs_reset_free(qs) qs_reset(qs, 1)
-
-Inline qstring qs_new(void) ;
-Inline qstring qs_dummy(qstring qs, const char* src, int pos) ;
-
-extern qstring qs_printf(qstring qs, const char* format, ...)
- PRINTF_ATTRIBUTE(2, 3) ;
-extern qstring qs_vprintf(qstring qs, const char *format, va_list args) ;
+Private void qs_make_to_size(qstring qs, usize len, free_keep_b free) ;
extern qstring qs_set(qstring qs, const char* src) ;
-extern qstring qs_set_n(qstring qs, const char* src, size_t n) ;
+extern qstring qs_set_n(qstring qs, const char* src, usize n) ;
extern qstring qs_append(qstring qs, const char* src) ;
-extern qstring qs_append_n(qstring qs, const char* src, size_t n) ;
+extern qstring qs_append_n(qstring qs, const char* src, usize n) ;
-Inline qstring qs_need(qstring qs, size_t len) ;
-Inline qstring qs_set_len(qstring qs, size_t len) ;
-extern qstring qs_add_len(qstring qs, size_t n, char** p_ep) ;
-Inline void qs_clear(qstring qs) ;
-Inline size_t qs_len(qstring qs) ;
-Inline size_t qs_size(qstring qs) ;
-Inline void* qs_term(qstring qs) ;
+extern qstring qs_copy(qstring dst, qstring src) ;
-Inline size_t qs_insert(qstring qs, const void* src, size_t n) ;
-Inline void qs_replace(qstring qs, const void* src, size_t n) ;
-Inline size_t qs_delete(qstring qs, size_t n) ;
+extern qstring qs_set_alias(qstring qs, const char* src) ;
+extern qstring qs_set_alias_n(qstring qs, const char* src, usize len) ;
+
+extern qstring qs_printf(qstring qs, const char* format, ...)
+ PRINTF_ATTRIBUTE(2, 3) ;
+extern qstring qs_vprintf(qstring qs, const char *format, va_list args) ;
+
+extern usize qs_insert(qstring qs, const void* src, usize n) ;
+extern void qs_replace(qstring qs, const void* src, usize n) ;
+extern usize qs_delete(qstring qs, usize n) ;
-extern qstring qs_copy(qstring dst, qstring src) ;
extern int qs_cmp_sig(qstring a, qstring b) ;
/*==============================================================================
@@ -168,301 +211,213 @@ extern int qs_cmp_sig(qstring a, qstring b) ;
*/
/*------------------------------------------------------------------------------
- * Make a brand new, completely empty qstring
- */
-Inline qstring
-qs_new(void)
-{
- /* Zeroising has set:
- *
- * body = NULL -- no body
- * size = 0 -- no body
- *
- * len = 0
- * cp = 0
- *
- * Nothing more to do unless initial size != 0
- */
- return XCALLOC(MTYPE_QSTRING, sizeof(qstring_t)) ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Construct a "dummy" qstring from the given string.
+ * Clear contents of qstring -- preserves any qstring body, but sets len = 0.
*
- * Allocates a qstring if required.
+ * Does nothing if qstring is NULL
*
- * This sets: body = the src
- * len = strlen(src) (0 if src is NULL)
- * cp = 0 if 'pos' is zero
- * len otherwise
- * size = 0
+ * Sets 'cp' = 'len' = 0.
*
- * The zero size means that the qstring handling will not attempt to free
- * the body, nor will it write to it... Operations which require the qstring
- * to have a size will allocate a new body, and discard this one.
+ * If is an alias qstring, discard the alias.
*
- * Returns: the address of the dummy qstring.
+ * NB: does not create a qstring body if there isn't one.
*/
-Inline qstring
-qs_dummy(qstring qs, const char* src, int pos)
+Inline void
+qs_clear(qstring qs)
{
- if (qs == NULL)
- qs = qs_new() ;
-
- qs->const_body = src ;
- qs->len = (src != NULL) ? strlen(src) : 0 ;
- qs->cp = (pos == 0) ? 0 : qs->len ;
- qs->size = 0 ;
-
- return qs ;
-}
+ if (qs != NULL)
+ {
+ qs_do_set_len_nn(qs, 0) ; /* sets term == false */
+ if (qs->size == 0)
+ {
+ qs_set_body_nn(qs, qs->b_body) ;
+ qs->size = qs->b_size ;
+ } ;
+ qs->cp = 0 ;
+ } ;
+} ;
/*------------------------------------------------------------------------------
- * Need space for a string of 'len' characters (plus possible '\0').
+ * Need space for a string of 'slen' characters (plus possible '\0').
*
- * Allocates the qstring, if required.
+ * Allocate qstring if required (setting qs->len = qs->cp = 0).
*
- * Returns: address of qstring
+ * Returns: address of qstring -- with body that can be written upto and
+ * including 'slen' + 1.
+ *
+ * NB: has no effect on 'len' -- even if 'len' > 'slen'.
*
- * NB: asking for 0 bytes will cause a body to be allocated, ready for any
- * '\0' !
+ * NB: has no effect on 'cp' -- even if 'cp' > 'len' or 'cp' > 'slen'.
*
- * NB: has no effect on 'cp' or 'len'. (Will be zero if new qstring allocated.)
+ * NB: if this is a aliased qstring, the alias is discarded and term = false.
*/
Inline qstring
-qs_need(qstring qs, size_t len)
+qs_need(qstring qs, usize slen)
{
- if ((qs == NULL) || (len >= qs->size))
- return qs_make_to_length(qs, len) ;
+ if (qs == NULL)
+ qs = qs_init_new(NULL, slen) ; /* Make the qstring if required */
+ else
+ if (slen >= qs->size) /* for alias qs->size == 0 ! */
+ qs_make_to_size(qs, slen, free_it) ;
- assert(qs->body != NULL) ;
return qs ;
} ;
/*------------------------------------------------------------------------------
* Set 'len' -- allocate or extend body as required.
*
- * Allocates the qstring, if required.
+ * Allocate qstring if required (setting qs->len = qs->cp = 0).
*
- * Returns: address of qstring
+ * Returns: address of qstring -- with body that can be written upto and
+ * including 'len' + 1.
*
- * NB: setting len == 0 bytes will cause a body to be allocated, ready for any
- * '\0' !
+ * Sets 'cp' to the (new) 'len' if 'cp' > 'len'.
*
- * NB: has no effect on 'cp' -- even if 'cp' > 'len'.
- *
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * NB: if this is a aliased qstring, a copy is made of all of the original body,
+ * even if that is longer than the required 'slen'. (And term = false.)
*/
Inline qstring
-qs_set_len(qstring qs, size_t len)
+qs_set_len(qstring qs, usize len)
{
- qs = qs_need(qs, len) ;
- qs->len = len ;
+ if (qs == NULL)
+ qs = qs_init_new(NULL, len) ; /* Make the qstring if required */
+ else
+ if (len >= qs->size) /* for alias qs->size == 0 ! */
+ qs_make_to_size(qs, len, keep_it) ;
+
+ qs_do_set_len_nn(qs, len) ;
+
+ if (qs->cp > len)
+ qs->cp = len ;
+
return qs ;
} ;
/*------------------------------------------------------------------------------
- * Reset contents of qstring.
+ * Chop to given length -- will neither allocate nor extend body.
*
- * Does nothing if qstring is NULL
+ * Does nothing if qstring is NULL.
+ *
+ * Does not change the 'len' if it is <= length to chop to.
*
- * Sets 'cp' = 'len' = 0. Sets first byte of body (if any) to NULL.
+ * Sets 'cp' to the (new) 'len' if 'cp' > 'len'.
*
- * For "dummy" qstring, discards the body.
+ * NB: if this is a aliased qstring, then it remains an aliased string, but
+ * shorter and term = false (unless no change made to the length).
*/
Inline void
-qs_clear(qstring qs)
+qs_chop(qstring qs, usize clen)
{
if (qs != NULL)
{
- qs->len = 0 ;
- qs->cp = 0 ;
- if (qs->size > 0)
- *((char*)qs->body) = '\0' ;
- else
- qs->body = NULL ;
+ usize len = qs_len_nn(qs) ;
+ if (len > clen)
+ qs_do_set_len_nn(qs, (len = clen)) ; /* sets term = false */
+ if (qs->cp > len)
+ qs->cp = len ;
} ;
} ;
/*------------------------------------------------------------------------------
- * Get length of qstring -- by doing strlen() -- and record it in qs->len.
+ * Set 'cp' -- allocate or extend body as required.
*
- * Returns: the string length
- *
- * NB: if no body has been allocated, length = 0
- */
-Inline size_t
-qs_len(qstring qs)
-{
- return (qs != NULL) ? (qs->len = (qs->body != NULL) ? strlen(qs_chars(qs))
- : 0)
- : 0 ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Get size of qstring body.
- *
- * NB: if no body has been allocated, size == 0
- * if qstring is NULL, size == 0
- *
- * NB: if this is a "dummy" qstring, size == 0.
- */
-Inline size_t
-qs_size(qstring qs)
-{
- return (qs != NULL) ? qs->size : 0 ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Get address of current end of qstring body -- ie byte at 'len'.
- *
- * NB: allocates body if required.
- *
- * There will be space for '\0' after 'len', so the address returned
- * is within the real body of the string.
- *
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * Allocates the qstring, if required.
*
- * NB: address of qstring may NOT be NULL.
- */
-Inline void*
-qs_end(qstring qs)
-{
- if (qs->len >= qs->size)
- qs_make_to_length(qs, qs->len) ; /* allows for trailing '\0' */
-
- return (char*)qs->body + qs->len ;
-} ;
-
-/*------------------------------------------------------------------------------
- * Set '\0' at qs->len -- allocate or extend body as required.
+ * Returns: address of qstring
*
- * Returns address of body -- NULL if the qstring is NULL
+ * NB: if there was no body, allocates a body for the string, even if 'cp' == 0.
*
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * NB: if new 'cp' > 'len', extends body (or allocates one), and sets 'len' to
+ * 'cp'. If this is an alias qstring, a copy of the string is made.
*/
-Inline void*
-qs_term(qstring qs)
+Inline qstring
+qs_set_cp(qstring qs, usize cp)
{
- size_t len ;
-
if (qs == NULL)
- return NULL ;
+ qs = qs_new(qs) ;
- if ((len = qs->len) >= qs->size)
- qs_make_to_length(qs, len) ;
+ if (qs->size <= cp)
- *qs_chars_at(qs, len) = '\0' ;
- return qs->body ;
+ if ((qs == NULL) || (cp >(cp > qs_len_nn(qs)))
+ qs = qs_set_len(qs, cp) ;
+ qs->cp = cp ;
+ return qs ;
} ;
/*------------------------------------------------------------------------------
- * Insert 'n' bytes at 'cp' -- moves anything cp..len up.
- *
- * Increases 'len'. but does not affect 'cp'.
- *
- * Returns: number of bytes beyond 'cp' that were moved before insert.
+ * If not "term": set '\0' at qs->len -- extending body as required.
*
- * NB: qstring MUST NOT be NULL
+ * Does NOT affect qs->cp or qs->len.
*
- * NB: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce
- * one or more undefined bytes.
- *
- * NB: the string is NOT re-terminated.
+ * Returns address of body -- NULL if the qstring is NULL
*
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * NB: if this is an alias, and it is not terminated, make a copy before adding
+ * terminating '\0'.
*/
-Inline size_t
-qs_insert(qstring qs, const void* src, size_t n)
+Inline void
+qs_terminate_nn(qstring qs)
{
- size_t after ;
- char* p ;
-
- if (qs->len < qs->cp)
- qs->len = qs->cp ;
- after = qs->len - qs->cp ;
+ if (!qs_term_nn(qs))
+ {
+ usize len ;
- qs_set_len(qs, qs->len + n) ; /* set len and ensure have space */
+ len = qs_len_nn(qs) ;
- p = qs_cp_char(qs) ;
- if (after > 0)
- memmove (p + n, p, after) ;
+ if (len >= qs->size) /* alias has size == 0 */
+ qs_make_to_size(qs, len) ; /* make sure can insert '\0' */
- if (n > 0)
- memmove(p, src, n) ;
+ *qs_char_at_nn(qs, len) = '\0' ;
- return after ;
+ qs_set_term_nn(qs, true) ;
+ } ;
} ;
/*------------------------------------------------------------------------------
- * Replace 'n' bytes at 'cp' -- extending if required.
+ * Return pointer to '\0' terminated string value.
*
- * May increase 'len'. but does not affect 'cp'.
+ * If qs is NULL or body is NULL returns pointer to constant empty '\0'
+ * terminated string.
*
- * NB: qstring MUST NOT be NULL
+ * If string is terminated, return address of string, which may be an alias
+ * address.
*
- * NB: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce
- * one or more undefined bytes.
+ * Otherwise, makes sure that there is a '\0' at the qs->len position, making
+ * a copy of any aliased string if required, and returns address of result.
*
- * NB: the string is NOT re-terminated.
- *
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * NB: value returned may be the address of the qstring body, or the address of
+ * an aliased string. In any event, the string should not be changed or
+ * reset until this pointer has been discarded !
*/
-Inline void
-qs_replace(qstring qs, const void* src, size_t n)
+Inline const char*
+qs_string(qstring qs)
{
- if ((qs->len < qs->cp + n) || (qs->size == 0))
- qs_set_len(qs, qs->cp + n) ; /* set len and ensure have space */
+ if ((qs == NULL) || (qs_len_nn(qs) == 0))
+ return "" ;
- if (n > 0)
- memmove(qs_cp_char(qs), src, n) ;
+ qs_terminate_nn(qs) ;
+
+ return qs_body_nn(qs) ;
} ;
/*------------------------------------------------------------------------------
- * Remove 'n' bytes at 'cp' -- extending if required.
- *
- * May change 'len'. but does not affect 'cp'.
+ * Assuming the given address is within the size of the given qstring,
+ * set qs->len and insert '\0' terminator there.
*
- * Returns: number of bytes beyond 'cp' that were moved before insert.
+ * Does NOT affect qs->cp.
*
- * NB: qstring MUST NOT be NULL
+ * NB: must NOT be a NULL qs.
*
- * NB: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce
- * one or more undefined bytes.
+ * NB: must NOT be an aliased qstring.
*
- * NB: the string is NOT re-terminated.
+ * NB: must NOT have a NULL body.
*/
-Inline size_t
-qs_delete(qstring qs, size_t n)
+Inline void
+qs_term_here(qstring qs, char* here)
{
- size_t after ;
- char* p ;
+ assert((here >= qs->s.char_body) && (here < (qs->s.char_body + qs->size))) ;
- /* Watch out for "dummy" */
- if (qs->size == 0)
- qs_make_to_length(qs, qs->len) ;
-
- /* If deleting up to or beyond len, then simply set len == cp */
- if ((qs->cp + n) >= qs->len)
- {
- qs_set_len(qs, qs->cp) ; /* set len, looks after cp > len */
- return 0 ; /* nothing after */
- }
-
- /* There is at least one byte after cp (so body must exist) */
- after = qs->len - (qs->cp + n) ;
-
- if (n > 0)
- {
- p = qs_cp_char(qs) ;
- memmove (p, p + n, after) ;
-
- qs->len -= n ;
- } ;
-
- return after ;
+ qs->len = (here - qs->s.char_body) ;
+ *here = '\0' ;
} ;
-
#endif /* _ZEBRA_QSTRING_H */