diff options
Diffstat (limited to 'lib/qstring.h')
-rw-r--r-- | lib/qstring.h | 823 |
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 */ |