summaryrefslogtreecommitdiffstats
path: root/lib/qstring.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/qstring.h')
-rw-r--r--lib/qstring.h823
1 files changed, 536 insertions, 287 deletions
diff --git a/lib/qstring.h b/lib/qstring.h
index 0597eda8..b9813bc7 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,420 +37,681 @@
*
* The caller does, however, have to explicitly release the contents of a
* qstring when it is done with.
+ *
+ * The mechanics of a qstring work on a length/pointer basis. The body of a
+ * qstring is not guaranteed to be '\0' terminated, but when memory is
+ * allocated provision is always made for a terminator beyond the 'len'.
+ * The qs_string() function will add a '\0' at the 'len' position.
+ *
+ * The body of a qstring is allocated and extended automatically as the length
+ * or the size is set. The address of the body can, therefore, change -- so
+ * should be careful when handling pointers to the body. The qstring handling
+ * tends to hold on to any body that has been allocated -- only qs_reset() will
+ * free the body.
+ *
+ * The qstring supports an "alias" state. A qstring can be set to be an
+ * "alias" for another length/pointer string, and at some later date that
+ * can be copied to the qstring body -- to be changed or for any other
+ * reason.
*/
+struct qstring
+{
+ elstring_t els ; /* *embedded* */
+
+ usize size ; /* of the els body */
-typedef struct qstring qstring_t ;
+ ulen cp ;
+
+ void* b_body ;
+ usize b_size ;
+
+ bool alias ;
+ char* empty ;
+} ;
+
+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
} ;
/*------------------------------------------------------------------------------
* Access functions for body of qstring -- to take care of casting pointers
*
- * NB: if the body has not yet been allocated, these functions will return
- * NULL or NULL + the offset.
+ * There are generally two versions of each function:
+ *
+ * xxxx_nn -- where the argument may NOT be NULL
+ *
+ * xxxx -- where a NULL or zero value is returned if the argument
+ * is NULL
+ *
+ * NB: the various 'cp', 'len' and 'at' functions do not guarantee that these
+ * positions exist within the current body of the string.
+ *
*/
-Inline char* /* pointer to body of qstring */
-qs_chars(qstring qs)
+
+Inline elstring qs_els(qstring qs) ;
+Inline elstring qs_els_nn(qstring qs) ;
+Inline void qs_els_copy(elstring els, qstring qs) ;
+Inline void qs_els_copy_nn(elstring els, qstring qs) ;
+
+Inline char* qs_char(qstring qs) ;
+Inline char* qs_char_nn(qstring qs) ;
+
+Inline char* qs_cp_char(qstring qs) ;
+Inline char* qs_cp_char_nn(qstring qs) ;
+
+Inline char* qs_ep_char(qstring qs) ;
+Inline char* qs_ep_char_nn(qstring qs) ;
+
+Inline char* qs_char_at(qstring qs, usize off) ;
+Inline char* qs_char_at_nn(qstring qs, usize off) ;
+
+Inline void* qs_body(qstring qs) ;
+Inline void* qs_body_nn(qstring qs) ;
+Inline void qs_set_body_nn(qstring qs, const void* body) ;
+
+Inline usize qs_size(qstring qs) ;
+Inline usize qs_size_nn(qstring qs) ;
+
+Inline ulen qs_len(qstring qs) ;
+Inline ulen qs_len_nn(qstring qs) ;
+Inline void qs_set_len_nn(qstring qs, ulen len) ;
+Inline void qs_set_strlen_nn(qstring qs) ;
+
+Inline ulen qs_cp(qstring qs) ;
+Inline ulen qs_cp_nn(qstring qs) ;
+Inline void qs_set_cp_nn(qstring qs, usize cp) ;
+Inline void qs_move_cp_nn(qstring qs, int delta) ;
+
+Inline ulen qs_after_cp(qstring qs) ;
+Inline ulen qs_after_cp_nn(qstring qs) ;
+
+Inline void qs_pp(pp p, qstring qs) ;
+Inline void qs_pp_nn(pp p, qstring qs) ;
+
+Inline void qs_cpp(cpp p, qstring qs) ;
+Inline void qs_cpp_nn(cpp p, qstring qs) ;
+
+/*------------------------------------------------------------------------------
+ * Functions to fetch the elstring body of the qstring.
+ */
+
+/* Pointer to elstring of qstring -- returns NULL if qstring is NULL */
+Inline elstring
+qs_els(qstring qs)
+{
+ return (qs != NULL) ? qs->els : NULL ;
+} ;
+
+/* Pointer to elstring of qstring (not NULL) */
+Inline elstring
+qs_els_nn(qstring qs)
+{
+ return qs->els ;
+} ;
+
+/* Copy elstring of qstring to another elstring (elstring not NULL) */
+Inline void
+qs_els_copy(elstring els, qstring qs)
{
- return (char*)qs->body ;
+ if (qs != NULL)
+ qs_els_copy_nn(els, qs) ;
+ else
+ els_null(els) ;
} ;
-Inline unsigned char* /* pointer to body of qstring */
-qs_bytes(qstring qs)
+/* Copy elstring of qstring to another elstring (neither NULL) */
+Inline void
+qs_els_copy_nn(elstring els, qstring qs)
{
- return (unsigned char*)qs->body ;
+ *els = *(qs->els) ;
} ;
-Inline char* /* pointer to given offset in qstring */
-qs_chars_at(qstring qs, size_t off)
+/*------------------------------------------------------------------------------
+ * Functions to fetch pointers to or into the string body.
+ *
+ * NB: these pointers must be treated with care -- and change to the string
+ * may invalidate the pointer. Where the qstring is an alias, the pointer
+ * returned is the alias -- which could disappear !
+ */
+
+/* Start of qstring -- returns NULL if qstring is NULL, or body is. */
+Inline char*
+qs_char(qstring qs)
{
- return qs_chars(qs) + off ;
+ return qs_body(qs) ;
} ;
-Inline unsigned char* /* pointer to given offset in qstring */
-qs_bytes_at(qstring qs, size_t off)
+/* Start of qstring (not NULL)-- returns NULL if body is NULL. */
+Inline char*
+qs_char_nn(qstring qs)
{
- return qs_bytes(qs) + off ;
+ return qs_body_nn(qs) ;
} ;
-Inline char* /* pointer to 'cp' offset in qstring */
+/* Offset in qstring -- returns NULL if qstring is NULL
+ * returns *nonsense if body is NULL */
+Inline char*
+qs_char_at(qstring qs, usize off)
+{
+ return (qs != NULL) ? qs_char_at_nn(qs, off) : NULL ;
+} ;
+
+/* Offset in qstring (not NULL) -- returns *nonsense if body is NULL */
+Inline char*
+qs_char_at_nn(qstring qs, usize off)
+{
+ return qs_char_nn(qs) + off ;
+} ;
+
+/* 'cp' in qstring -- returns NULL if qstring is NULL
+ * returns *nonsense if body is NULL */
+Inline char*
qs_cp_char(qstring qs)
{
- return qs_chars_at(qs, qs->cp) ;
+ return (qs != NULL) ? qs_cp_char_nn(qs) : NULL ;
} ;
-Inline unsigned char* /* pointer to 'cp' offset in qstring */
-qs_cp_byte(qstring qs)
+/* 'cp' in qstring (not NULL) -- returns *nonsense if body is NULL */
+Inline char*
+qs_cp_char_nn(qstring qs)
{
- return qs_bytes_at(qs, qs->cp) ;
+ return qs_char_at_nn(qs, qs_cp_nn(qs)) ;
} ;
-Inline char* /* pointer to 'len' offset in qstring */
+/* 'len' in qstring -- returns NULL if qstring is NULL
+ * returns *nonsense if body is NULL */
+Inline char*
qs_ep_char(qstring qs)
{
- return qs_chars_at(qs, qs->len) ;
+ return (qs != NULL) ? qs_ep_char_nn(qs) : NULL ;
} ;
-Inline unsigned char* /* pointer to 'len' offset in qstring */
-qs_ep_byte(qstring qs)
+/* 'len' in qstring (not NULL) -- returns *nonsense if body is NULL */
+Inline char*
+qs_ep_char_nn(qstring qs)
{
- return qs_bytes_at(qs, qs->len) ;
+ return qs_char_at_nn(qs, qs_len_nn(qs)) ;
} ;
-/*==============================================================================
- * Functions
+/* Start of qstring -- returns NULL if qstring is NULL, or body is. */
+Inline void*
+qs_body(qstring qs)
+{
+ return (qs != NULL) ? qs_body_nn(qs) : NULL ;
+} ;
+
+/* Start of qstring (not NULL)-- returns NULL if body is NULL. */
+Inline void*
+qs_body_nn(qstring qs)
+{
+ return els_body_nn(qs->els) ;
+} ;
+
+/* Set new body of qstring (not NULL).
+ *
+ * Caller must ensure that 'size', 'len' & 'cp' are all valid ! */
+Inline void
+qs_set_body_nn(qstring qs, const void* body)
+{
+ els_set_body_nn(qs->els, body) ;
+} ;
+
+/* Size of qstring body -- zero if qstring is NULL, or is alias. */
+Inline usize
+qs_size(qstring qs)
+{
+ return (qs != NULL) ? qs_size_nn(qs) : 0 ;
+} ;
+
+/* Size of qstring (not NULL). */
+Inline usize
+qs_size_nn(qstring qs)
+{
+ return (qs->size) ;
+} ;
+
+/*----------------------------------------------------------------------------*/
+
+/* 'len' of qstring -- returns 0 if qstring is NULL */
+Inline ulen
+qs_len(qstring qs)
+{
+ return (qs != NULL) ? qs_len_nn(qs) : 0 ;
+} ;
+
+/* 'len' of qstring (not NULL) */
+Inline ulen
+qs_len_nn(qstring qs)
+{
+ return els_len_nn(qs->els) ;
+} ;
+
+/* set 'len' of qstring (not NULL) -- caller responsible for validity */
+Inline void
+qs_set_len_nn(qstring qs, ulen len)
+{
+ els_set_len_nn(qs->els, len) ;
+} ;
+
+/* set 'len' of qstring according to strlen(body) -- nothing NULL ! */
+Inline void
+qs_set_strlen_nn(qstring qs)
+{
+ els_set_len_nn(qs->els, strlen(qs_body_nn(qs))) ;
+} ;
+
+/*----------------------------------------------------------------------------*/
+
+/* 'cp' of qstring -- returns 0 if qstring is NULL */
+Inline ulen
+qs_cp(qstring qs)
+{
+ return (qs != NULL) ? qs_cp_nn(qs) : 0 ;
+} ;
+
+/* 'cp' of qstring (not NULL) */
+Inline ulen
+qs_cp_nn(qstring qs)
+{
+ return qs->cp ;
+} ;
+
+/* set 'cp' of qstring (not NULL) -- caller responsible for validity */
+Inline void
+qs_set_cp_nn(qstring qs, usize cp)
+{
+ qs->cp = cp ;
+} ;
+
+/* move 'cp' of qstring (not NULL) -- caller responsible for validity */
+Inline void
+qs_move_cp_nn(qstring qs, int delta)
+{
+ qs->cp += delta ;
+} ;
+
+/*----------------------------------------------------------------------------*/
+
+/* 'len' - 'cp' of qstring (not NULL) -- zero if 'len' < 'cp' */
+Inline ulen
+qs_after_cp_nn(qstring qs)
+{
+ return (qs_len_nn(qs) > qs_cp_nn(qs)) ? qs_len_nn(qs) - qs_cp_nn(qs) : 0 ;
+} ;
+
+/* 'len' - 'cp' of qstring -- zero if NULL or 'len' < 'cp' */
+Inline ulen
+qs_after_cp(qstring qs)
+{
+ return (qs != NULL) ? qs_after_cp_nn(qs) : 0 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Functions to fetch various pointer pairs.
*/
-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) ;
+Inline void
+qs_pp(pp p, qstring qs)
+{
+ if (qs != NULL)
+ qs_pp_nn(p, qs) ;
+ else
+ pp_null(p) ;
+} ;
-#define qs_reset_keep(qs) qs_reset(qs, 0)
-#define qs_reset_free(qs) qs_reset(qs, 1)
+Inline void
+qs_pp_nn(pp p, qstring qs)
+{
+ els_pp_nn(p, qs->els) ;
+} ;
-Inline qstring qs_new(void) ;
-Inline qstring qs_dummy(qstring qs, const char* src, int pos) ;
+Inline void
+qs_cpp(cpp p, qstring qs)
+{
+ if (qs != NULL)
+ qs_cpp_nn(p, qs) ;
+ else
+ cpp_null(p) ;
+} ;
-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) ;
+Inline void
+qs_cpp_nn(cpp p, qstring qs)
+{
+ els_cpp_nn(p, qs->els) ;
+} ;
-extern qstring qs_set(qstring qs, const char* src) ;
-extern qstring qs_set_n(qstring qs, const char* src, size_t n) ;
+/*------------------------------------------------------------------------------
+ * Set real body -- discarding any alias.
+ *
+ * NB: does not affect 'len' or 'cp'
+ */
+Inline void qs_set_real_body_nn(qstring qs)
+{
+ qs->size = qs->b_size ;
+ qs_set_body_nn(qs, qs->b_body) ;
+ qs->alias = false ;
+} ;
+
+/*==============================================================================
+ * Functions
+ */
-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_new(usize slen) ;
+extern qstring qs_new_with_body(usize slen) ;
+extern qstring qs_init_new(qstring qs, usize len) ;
+extern qstring qs_reset(qstring qs, free_keep_b free_structure) ;
+Inline qstring qs_free(qstring qs) ;
-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 char* qs_make_string(qstring qs) ;
+Inline const char* qs_string(qstring qs) ;
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) ;
+Inline qstring qs_new_size(qstring qs, usize slen) ;
+Inline qstring qs_extend(qstring qs, usize elen) ;
+Inline void qs_chop(qstring qs, usize clen) ;
-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) ;
+Private void qs_make_to_size(qstring qs, usize len, usize alen) ;
+
+extern qstring qs_set(qstring qs, const char* src) ;
+extern qstring qs_set_n(qstring qs, const char* src, usize n) ;
+extern qstring qs_set_qs(qstring qs, qstring src) ;
+extern qstring qs_set_els(qstring qs, elstring src) ;
+extern qstring qs_set_fill(qstring qs, usize len, const char* src) ;
+extern qstring qs_set_fill_n(qstring qs, usize len, const char* src,
+ usize flen) ;
+
+extern qstring qs_append_str(qstring qs, const char* src) ;
+extern qstring qs_append_str_n(qstring qs, const char* src, usize n) ;
+extern qstring qs_append(qstring qs, qstring src) ;
+extern qstring qs_append_els(qstring qs, elstring src) ;
+
+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_set_alias_qs(qstring qs, qstring src) ;
+extern qstring qs_set_alias_els(qstring qs, elstring src) ;
extern qstring qs_copy(qstring dst, qstring src) ;
-extern int qs_cmp_sig(qstring a, qstring b) ;
+
+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_replace(qstring qs, usize r, const void* src, usize n) ;
+Inline usize qs_insert(qstring qs, const void* src, usize n)
+{
+ return qs_replace(qs, 0, src, n) ;
+} ;
+Inline usize qs_delete(qstring qs, usize n)
+{
+ return qs_replace(qs, n, NULL, 0) ;
+} ;
+
+Inline int qs_cmp(qstring a, qstring b) ;
+Inline int qs_cmp_word(qstring a, qstring w) ;
+Inline int qs_cmp_sig(qstring a, qstring b) ;
+Inline bool qs_equal(qstring a, qstring b) ;
+Inline bool qs_substring(qstring a, qstring b) ;
/*==============================================================================
* The Inline functions.
*/
/*------------------------------------------------------------------------------
- * Make a brand new, completely empty qstring
+ * Free given qstring
*/
Inline qstring
-qs_new(void)
+qs_free(qstring qs)
{
- /* 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)) ;
+ return qs_reset(qs, free_it) ;
} ;
/*------------------------------------------------------------------------------
- * Construct a "dummy" qstring from the given string.
+ * Return pointer to string value -- ensure not alias and '\0' terminated.
*
- * Allocates a qstring if required.
+ * If is alias, copies that before adding '\0' terminator.
*
- * This sets: body = the src
- * len = strlen(src) (0 if src is NULL)
- * cp = 0 if 'pos' is zero
- * len otherwise
- * size = 0
+ * Sets the '\0' terminator at the 'len' position, extending string if that
+ * is required.
*
- * 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 qs == NULL returns pointer to empty '\0' terminated string.
*
- * Returns: the address of the dummy qstring.
+ * NB: The qstring should not be changed or reset until this pointer has been
+ * discarded !
+ *
+ * NB: The value returned is not "const" BUT caller is NOT entitled to change
+ * any part of the string -- CERTAINLY nothing from the '\0' onwards !
*/
-Inline qstring
-qs_dummy(qstring qs, const char* src, int pos)
+Inline char*
+qs_make_string(qstring qs)
{
- if (qs == NULL)
- qs = qs_new() ;
+ static char empty_string[1] ;
- qs->const_body = src ;
- qs->len = (src != NULL) ? strlen(src) : 0 ;
- qs->cp = (pos == 0) ? 0 : qs->len ;
- qs->size = 0 ;
+ usize len ;
+ char* p ;
- return qs ;
-}
+ if (qs == NULL)
+ {
+ len = 0 ;
+ p = empty_string ;
+ }
+ else
+ {
+ len = qs_len_nn(qs) ;
+ if (len >= qs->size) /* for alias, qs_size == 0 */
+ qs_make_to_size(qs, len, len) ; /* extend and/or copy any alias */
-/*------------------------------------------------------------------------------
- * Need space for a string of 'len' characters (plus possible '\0').
- *
- * Allocates the qstring, if required.
- *
- * Returns: address of qstring
- *
- * NB: asking for 0 bytes will cause a body to be allocated, ready for any
- * '\0' !
- *
- * NB: has no effect on 'cp' or 'len'. (Will be zero if new qstring allocated.)
- */
-Inline qstring
-qs_need(qstring qs, size_t len)
-{
- if ((qs == NULL) || (len >= qs->size))
- return qs_make_to_length(qs, len) ;
+ p = qs_char_nn(qs) ;
+ } ;
- assert(qs->body != NULL) ;
- return qs ;
+ *(p + len) = '\0' ;
+
+ return p ;
} ;
/*------------------------------------------------------------------------------
- * Set 'len' -- allocate or extend body as required.
+ * Return pointer to string value.
*
- * Allocates the qstring, if required.
+ * Writes '\0' at 'len' in order to return a terminated string, if required.
*
- * Returns: address of qstring
+ * If qs == NULL or body == NULL, or 'len' == 0 returns pointer to constant
+ * empty '\0' terminated string (ie "").
*
- * NB: setting len == 0 bytes will cause a body to be allocated, ready for any
- * '\0' !
+ * NB: if 'len' is beyond the current 'size' of the of the qstring, then
+ * will extend the string.
*
- * NB: has no effect on 'cp' -- even if 'cp' > 'len'.
+ * NB: if string is an alias, and that is not '\0' terminated, will make a
+ * copy, before writing '\0' at end.
*
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * NB: In any event, the string should not be changed or reset until this
+ * pointer has been discarded !
*/
-Inline qstring
-qs_set_len(qstring qs, size_t len)
+Inline const char*
+qs_string(qstring qs)
{
- qs = qs_need(qs, len) ;
- qs->len = len ;
- return qs ;
+ char* p ;
+ usize len ;
+
+ if ( (qs == NULL) || ((len = qs_len_nn(qs) ) == 0)
+ || ((p = qs_char_nn(qs)) == NULL) )
+ return "" ;
+
+ if (len >= qs->size) /* for alias, qs_size == 0 */
+ {
+ if (qs->alias && (*(p + len) == '\0'))
+ return p ;
+
+ qs_make_to_size(qs, len, len) ; /* extend and/or copy alias */
+ p = qs_char_nn(qs) ;
+ } ;
+
+ *(p + len) = '\0' ;
+
+ return p ;
} ;
/*------------------------------------------------------------------------------
- * Reset contents of qstring.
+ * Clear contents of qstring -- preserves any qstring body, but sets len = 0.
*
* Does nothing if qstring is NULL
*
- * Sets 'cp' = 'len' = 0. Sets first byte of body (if any) to NULL.
+ * Sets 'cp' = 'len' = 0
+ *
+ * If is an alias qstring, discard the alias.
*
- * For "dummy" qstring, discards the body.
+ * NB: does not create a qstring body if there isn't one.
+ *
+ * NB: does not change the qstring body if there is one. (Which is used in
+ * vio_lc_write_nb().
*/
Inline void
qs_clear(qstring qs)
{
if (qs != NULL)
{
- qs->len = 0 ;
- qs->cp = 0 ;
- if (qs->size > 0)
- *((char*)qs->body) = '\0' ;
- else
- qs->body = NULL ;
+ if (qs->alias)
+ qs_set_real_body_nn(qs) ;
+ qs_set_len_nn(qs, 0) ;
+ qs_set_cp_nn(qs, 0) ;
} ;
} ;
/*------------------------------------------------------------------------------
- * Get length of qstring -- by doing strlen() -- and record it in qs->len.
+ * Ensure have space for a string of 'slen' characters (plus possible '\0'),
+ * and discard any alias.
+ *
+ * Allocate qstring if required (setting 'len' = 'cp' = 0).
*
- * Returns: the string length
+ * Returns: address of qstring -- with body that can be written upto and
+ * including 'slen' + 1.
*
- * NB: if no body has been allocated, length = 0
+ * Has no effect on 'len' -- even if 'len' > 'slen'.
+ *
+ * Has no effect on 'cp' -- even if 'cp' > 'len' or 'cp' > 'slen'.
+ *
+ * If this is a aliased qstring, the alias is discarded.
*/
-Inline size_t
-qs_len(qstring qs)
+Inline qstring
+qs_new_size(qstring qs, usize slen)
{
- return (qs != NULL) ? (qs->len = (qs->body != NULL) ? strlen(qs_chars(qs))
- : 0)
- : 0 ;
+ if (qs == NULL)
+ qs = qs_new_with_body(slen) ;
+ else if (slen >= qs->size) /* for alias qs->size == 0 ! */
+ qs_make_to_size(qs, slen, 0) ; /* extend and/or make body */
+
+ return qs ;
} ;
/*------------------------------------------------------------------------------
- * Get size of qstring body.
+ * Extend to 'len' + 'elen' -- allocate or extend body as required.
+ *
+ * Allocate qstring if required (setting 'cp' = 0).
*
- * NB: if no body has been allocated, size == 0
- * if qstring is NULL, size == 0
+ * Returns: address of qstring -- with body that can be written up to and
+ * including 'len' + 'elen' + 1.
*
- * NB: if this is a "dummy" qstring, size == 0.
+ * Has no effect on 'cp' -- even if 'cp' > 'len'.
+ *
+ * If this is a aliased qstring, a copy is made.
*/
-Inline size_t
-qs_size(qstring qs)
+Inline qstring
+qs_extend(qstring qs, usize elen)
{
- return (qs != NULL) ? qs->size : 0 ;
+ if (qs == NULL)
+ qs = qs_new_with_body(elen) ;
+ else
+ {
+ elen = qs_len_nn(qs) + elen ;
+ if (elen >= qs->size) /* for alias qs->size == 0 ! */
+ qs_make_to_size(qs, elen, elen) ; /* extend and/or copy any alias */
+ } ;
+
+ qs_set_len_nn(qs, elen) ;
+
+ return qs ;
} ;
/*------------------------------------------------------------------------------
- * Get address of current end of qstring body -- ie byte at 'len'.
+ * Chop to given length -- will neither allocate nor extend body.
*
- * NB: allocates body if required.
+ * Does nothing if qstring is NULL.
*
- * There will be space for '\0' after 'len', so the address returned
- * is within the real body of the string.
+ * Does not change the 'len' if it is <= length to chop to.
*
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * NB: has no effect on 'cp' -- even if 'cp' > (new) 'len'.
*
- * NB: address of qstring may NOT be NULL.
+ * NB: if this is a aliased qstring, then it remains an aliased string, but
+ * shorter (unless no change made to the length).
*/
-Inline void*
-qs_end(qstring qs)
+Inline void
+qs_chop(qstring qs, usize clen)
{
- if (qs->len >= qs->size)
- qs_make_to_length(qs, qs->len) ; /* allows for trailing '\0' */
-
- return (char*)qs->body + qs->len ;
+ if (qs != NULL)
+ {
+ if (clen < qs_len_nn(qs))
+ qs_set_len_nn(qs, clen) ;
+ } ;
} ;
/*------------------------------------------------------------------------------
- * Set '\0' at qs->len -- allocate or extend body as required.
- *
- * Returns address of body -- NULL if the qstring is NULL
+ * Compare two qstrings -- returns the usual -ve, 0, +ve cmp result.
*
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * NULL qstring is treated as empty.
*/
-Inline void*
-qs_term(qstring qs)
+Inline int
+qs_cmp(qstring a, qstring b)
{
- size_t len ;
-
- if (qs == NULL)
- return NULL ;
-
- if ((len = qs->len) >= qs->size)
- qs_make_to_length(qs, len) ;
-
- *qs_chars_at(qs, len) = '\0' ;
-
- return qs->body ;
+ return els_cmp(qs_els(a), qs_els(b)) ;
} ;
/*------------------------------------------------------------------------------
- * 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.
- *
- * NB: qstring MUST NOT be NULL
- *
- * NB: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce
- * one or more undefined bytes.
- *
- * NB: the string is NOT re-terminated.
- *
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * Compare qstrings to given word -- see els_cmp_word
*/
-Inline size_t
-qs_insert(qstring qs, const void* src, size_t n)
+Inline int
+qs_cmp_word(qstring a, qstring w)
{
- size_t after ;
- char* p ;
-
- if (qs->len < qs->cp)
- qs->len = qs->cp ;
- after = qs->len - qs->cp ;
-
- qs_set_len(qs, qs->len + n) ; /* set len and ensure have space */
-
- p = qs_cp_char(qs) ;
- if (after > 0)
- memmove (p + n, p, after) ;
-
- if (n > 0)
- memmove(p, src, n) ;
-
- return after ;
+ return els_cmp_word(qs_els(a), qs_els(w)) ;
} ;
/*------------------------------------------------------------------------------
- * Replace 'n' bytes at 'cp' -- extending if required.
- *
- * May increase 'len'. but does not affect 'cp'.
+ * Compare significant parts of two qstrings -- returns the usual -ve, 0, +ve
+ * cmp result.
*
- * NB: qstring MUST NOT be NULL
+ * By significant, mean excluding leading/trailing isspace() and treating
+ * multiple isspace() as single isspace().
*
- * NB: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce
- * one or more undefined bytes.
- *
- * NB: the string is NOT re-terminated.
- *
- * NB: if this is a "dummy" qstring, a copy is made of the original body.
+ * NULL qstring is treated as empty.
*/
-Inline void
-qs_replace(qstring qs, const void* src, size_t n)
+Inline int
+qs_cmp_sig(qstring a, qstring b)
{
- if ((qs->len < qs->cp + n) || (qs->size == 0))
- qs_set_len(qs, qs->cp + n) ; /* set len and ensure have space */
+ return els_cmp_sig(qs_els(a), qs_els(b)) ;
+} ;
- if (n > 0)
- memmove(qs_cp_char(qs), src, n) ;
+/*------------------------------------------------------------------------------
+ * Are two qstrings equal ? -- returns true if they are.
+ */
+Inline bool
+qs_equal(qstring a, qstring b)
+{
+ return els_equal(qs_els(a), qs_els(b)) ;
} ;
/*------------------------------------------------------------------------------
- * Remove 'n' bytes at 'cp' -- extending if required.
- *
- * May change 'len'. but does not affect 'cp'.
+ * Is 'b' a leading substring of 'a' ? -- returns true if it is.
*
- * Returns: number of bytes beyond 'cp' that were moved before insert.
- *
- * NB: qstring MUST NOT be NULL
- *
- * NB: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce
- * one or more undefined bytes.
- *
- * NB: the string is NOT re-terminated.
+ * If 'b' is empty it is always a leading substring.
*/
-Inline size_t
-qs_delete(qstring qs, size_t n)
+Inline bool
+qs_substring(qstring a, qstring b)
{
- size_t after ;
- char* p ;
-
- /* 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 ;
+ return els_substring(qs_els(a), qs_els(b)) ;
} ;
-
#endif /* _ZEBRA_QSTRING_H */