From 5cae7eea451f2b7d65b5892e2c1dafc70f8b836e Mon Sep 17 00:00:00 2001 From: Chris Hall Date: Sun, 13 Feb 2011 23:11:45 +0000 Subject: Second tranche of updates for pipework branch. modified: bgpd/bgp_connection.c modified: bgpd/bgp_debug.c modified: bgpd/bgp_engine.h modified: bgpd/bgp_main.c modified: bgpd/bgp_packet.c modified: bgpd/bgp_peer.c modified: bgpd/bgp_route.c modified: bgpd/bgp_routemap.c modified: bgpd/bgp_session.c modified: bgpd/bgp_vty.c modified: bgpd/bgpd.c modified: bgpd/bgpd.h modified: configure.ac modified: isisd/dict.h modified: isisd/isis_misc.c modified: isisd/isis_routemap.c modified: isisd/isis_spf.c modified: lib/Makefile.am modified: lib/command.c modified: lib/command.h modified: lib/command_execute.h modified: lib/command_parse.c modified: lib/command_parse.h modified: lib/command_queue.c modified: lib/command_queue.h modified: lib/elstring.h modified: lib/heap.c modified: lib/if.c modified: lib/if.h modified: lib/keychain.c modified: lib/keystroke.c modified: lib/keystroke.h modified: lib/list_util.c modified: lib/list_util.h modified: lib/log.c modified: lib/log.h modified: lib/memory.c modified: lib/memory.h modified: lib/memtypes.c modified: lib/misc.h modified: lib/mqueue.c modified: lib/mqueue.h deleted: lib/node_type.h modified: lib/pthread_safe.c modified: lib/qfstring.c modified: lib/qiovec.c modified: lib/qiovec.h modified: lib/qpath.c modified: lib/qpnexus.c modified: lib/qpnexus.h modified: lib/qpselect.c modified: lib/qpthreads.h modified: lib/qstring.c modified: lib/qstring.h modified: lib/qtime.c modified: lib/qtime.h modified: lib/qtimers.c modified: lib/qtimers.h modified: lib/routemap.c modified: lib/symtab.h modified: lib/thread.h deleted: lib/uty.h modified: lib/vector.c modified: lib/vector.h modified: lib/version.h.in modified: lib/vio_fifo.c modified: lib/vio_fifo.h modified: lib/vio_lines.c modified: lib/vio_lines.h modified: lib/vty.c modified: lib/vty.h modified: lib/vty_cli.c modified: lib/vty_cli.h modified: lib/vty_io.c modified: lib/vty_io.h modified: lib/vty_io_basic.c modified: lib/vty_io_basic.h modified: lib/vty_io_file.c modified: lib/vty_io_file.h modified: lib/vty_io_shell.c modified: lib/vty_io_term.c modified: lib/vty_io_term.h modified: lib/vty_local.h modified: lib/vty_pipe.c modified: lib/workqueue.h modified: lib/zebra.h modified: ospf6d/ospf6_lsa.c modified: ripngd/ripngd.c modified: tests/test-list_util.c modified: tests/test-vector.c modified: vtysh/vtysh.c modified: vtysh/vtysh_config.c --- lib/qstring.c | 861 +++++++++++++++++++++++++--------------------------------- 1 file changed, 372 insertions(+), 489 deletions(-) (limited to 'lib/qstring.c') diff --git a/lib/qstring.c b/lib/qstring.c index c7e5b81c..19f74e8c 100644 --- a/lib/qstring.c +++ b/lib/qstring.c @@ -19,13 +19,10 @@ * Boston, MA 02111-1307, USA. */ -#include -#include +#include "stdio.h" #include "qstring.h" - #include "memory.h" -#include "zassert.h" /*============================================================================== */ @@ -38,15 +35,53 @@ qs_new(void) { /* zeroising sets a completely empty qstring -- see qs_init_new() */ return XCALLOC(MTYPE_QSTRING, sizeof(qstring_t)) ; + + confirm(QSTRING_INIT_ALL_ZEROS) ; +} ; + +/*------------------------------------------------------------------------------ + * Create a new body or extend existing one to accommodate at least slen + 1. + * + * Sets size to multiple of 8 (minimum 16), with at least 9 bytes free beyond + * the requested slen. + * + * Does not affect 'len' or 'cp'. + * + * If 'keep_alias', ONLY sets 'b_size' & 'b_body'. + * + * If !'keep_alias', sets the elstring body & size & clears 'alias'. + */ +static inline void +qs_new_body(qstring qs, usize slen, bool keep_alias) +{ + qs->b_size = (slen + 0x10) & ~(usize)(0x08 - 1) ; + qs->b_body = XREALLOC(MTYPE_STRING, qs->b_body, qs->b_size) ; + + if (!keep_alias) + qs_set_real_body_nn(qs) ; +} ; + +/*------------------------------------------------------------------------------ + * Create a new, empty qs with body + */ +extern qstring +qs_new_with_body(usize slen) +{ + qstring qs ; + + qs = qs_new() ; + qs_new_body(qs, slen, false) ; + + return qs ; } ; /*------------------------------------------------------------------------------ * Initialise qstring -- allocate if required. * - * If non-zero slen is given, a body is allocated (for at least slen + 1). + * If non-zero slen is given, a body is allocated (size = slen + 1). * If zero slen is given, no body is allocated. * - * Sets qs->len = qs->cp = 0. '\0' terminates body if allocates one. + * Sets 'len' = 'cp' = 0. * * Returns: address of qstring * @@ -65,18 +100,20 @@ qs_init_new(qstring qs, usize slen) /* Zeroising has set: * - * body = NULL -- no body - * size = 0 -- no body + * empty elstring -- no body, 'len' = 0 + * + * size = 0 -- no elstring body * - * len = 0 * cp = 0 * - * b_body = NULL -- no body buffer - * b_size = 0 -- no body buffer + * b_body = NULL -- no body buffer + * b_size = 0 -- no body buffer + * + * alias = false -- not an alias qstring */ if (slen != 0) - qs_make_to_size(qs, slen, false) ; + qs_new_body(qs, slen, false) ; return qs ; } ; @@ -104,90 +141,75 @@ qs_reset(qstring qs, free_keep_b free_structure) XFREE(MTYPE_QSTRING, qs) ; /* sets qs = NULL */ else memset(qs, 0, sizeof(qstring_t)) ; /* see qs_init_new */ + + confirm(QSTRING_INIT_ALL_ZEROS) ; } ; return qs ; } ; /*------------------------------------------------------------------------------ - * Allocate or reallocate body so that is big enough for the given "slen". + * Allocate or reallocate body so that is big enough for the given 'slen'. * - * If the qstring is currently an alias, copies all of the alias to a new - * body -- so always returns a non-alias qstring. + * qstring may NOT be NULL. * - * Returns with a body with size > 0. Allocates to 16 byte boundaries with - * space for '\0' beyond given length. + * Returns with a body with size > 0 (even if 'slen' == 0). * - * Does NOT affect qs->len or qs->cp. Does NOT re-terminate. + * Expects, but does not require, that 'slen' > 'size'. * - * NB: will allocate a new body even if the slen == 0. + * Does not change 'cp' or 'len' (even if 'len' > 'slen'). * - * NB: always copies all of any aliased string (even if the slen == 0). - * - * NB: sets terminated false + * If is an alias, copies min('len', 'alen', 'slen') characters to the body. */ Private void -qs_make_to_size(qstring qs, usize slen, bool keep) +qs_make_to_size(qstring qs, usize slen, usize alen) { - usize size ; - usize alen ; + /* If body needs to be extended, do that now */ + if (slen >= qs->b_size) + qs_new_body(qs, slen, (qs->alias && (alen != 0))) ; + /* keeps alias if required */ /* Worry about alias. If we keep it, we keep all of it. */ - if (keep && (qs->size == 0)) + if (qs->alias) { - alen = qs_len_nn(qs) ; /* alias stuff to keep */ - if (slen <= alen) - slen = alen + 1 ; /* making sure can do that. */ - } - else - alen = 0 ; /* no alias stuff to keep */ + /* alias or empty */ + usize len = qs_len_nn(qs) ; - /* Calculate the new size -- multiple of 16, >= 16. */ - size = (slen + 0x10) & ~(usize)(0x10 - 1) ; - dassert(size != 0) ; + if (alen >= len) + alen = len ; /* keep min(alen, len) */ - /* If that requires the body to be extended, do that now */ - if (size > qs->b_size) - { - /* Need to allocate or extend the buffer. - * - * If current size is not zero, extend by doubling size or making at - * least the multiple of 16 calculated for new len. - */ - qs->b_size *= 2 ; - if (qs->b_size < size) - qs->b_size = size ; - qs->b_body = XREALLOC(MTYPE_STRING, qs->b_body, qs->b_size) ; - } ; - - /* If this is a non-empty alias, copy all or part of it. */ - if (alen != 0) - memcpy(qs->b_body, qs_body_nn(qs), alen) ; - - /* Update body and size, and no longer known to be terminated */ - qs_set_body_nn(qs, qs->b_body) ; - qs->size = qs->b_size ; + if (alen > slen) + alen = slen ; /* keep only to new len. */ + if (alen != 0) + memcpy(qs->b_body, qs_body_nn(qs), alen) ; + qs_set_real_body_nn(qs) ; + } ; } ; /*============================================================================== * Setting value of qstring + * + * Copy the given string to the qstring, allocating qstring and/or extending + * it as required. + * + * Any alias is simply discarded. + * + * Sets 'len' to new length + * Sets 'cp' = 0 + * + * Returns: address of the qstring (allocated if required). */ /*------------------------------------------------------------------------------ * Set qstring to be copy of the given string. * - * Allocate qstring if required (setting qs->len = qs->cp = 0). - * - * Allocates a body and copies src to it, adding '\0'. Treats src == NULL as - * an empty string. - * - * Sets qs->len to the length of the string (excluding trailing '\0'). - * Sets qs->cp == 0. + * Treats src == NULL as an empty string. Otherwise src must be a '\0' + * terminated string. * - * Returns: address of the qstring copied to. + * Does not copy or count the '\0' terminator. * - * NB: if copying to a dummy qstring, the old body is simply discarded. + * See notes above. */ extern qstring qs_set(qstring qs, const char* src) @@ -196,157 +218,202 @@ qs_set(qstring qs, const char* src) } ; /*------------------------------------------------------------------------------ - * Set qstring to be leading 'n' bytes of given string. - * - * Allocate qstring if required (setting qs->len = qs->cp = 0). - * - * Allocates a body and copies 'n' bytes from src to it, adding '\0'. The - * src pointer is ignored if n == 0. + * Set qstring to be copy of leading 'n' bytes of given string. * - * Sets qs->len to the length of the string (excluding trailing '\0'). - * Sets qs->cp == 0. + * If n == 0, src is ignored (and may be NULL) + * If n > 0, src string MUST be at least 'n' bytes long. * - * Returns: address of the qstring copied to. - * - * NB: if n == 0, src may be NULL - * - * NB: if n > 0, src string MUST be at least 'n' bytes long. - * - * NB: if copying to a dummy qstring, the old body is simply discarded. + * See notes above. */ extern qstring qs_set_n(qstring qs, const char* src, usize len) { - char* p ; - - qs = qs_new_len(qs, len) ; /* ensures have body > n */ - - p = qs_char_nn(qs) ; + qs = qs_new_size(qs, len) ; /* ensures have body > len */ if (len != 0) - memcpy(p, src, len) ; - - *(p + len) = '\0' ; + memcpy(qs_char_nn(qs), src, len) ; - qs_set_term_nn(qs, true) ; - qs->cp = 0 ; + qs_set_len_nn(qs, len) ; + qs_set_cp_nn(qs, 0) ; return qs ; } ; /*------------------------------------------------------------------------------ - * Append given string to a qstring -- adding at qs->len position. - * - * Allocate qstring if required (setting qs->len = qs->cp = 0). - * - * Allocates or extends the body and copies bytes from src to it, adding '\0'. - * Treats src == NULL as an empty string. - * - * Sets qs->len to the length of the result (excluding trailing '\0') - * Does not change qs->cp. + * Set qstring to be copy of given qstring contents. * - * Returns: address of the qstring appended to. + * If the given qstring is an alias, then the contents of the alias are copied + * (so the result is not an alias). See qs_copy() for the alternative. * - * NB: if appending to a dummy qstring, the old body is copied first. + * See notes above -- and note that 'cp' is set to 0. */ -extern qstring qs_append(qstring qs, const char* src) +extern qstring +qs_set_qs(qstring qs, qstring src) { - return qs_append_n(qs, src, (src != NULL) ? strlen(src) : 0) ; + return qs_set_n(qs, qs_body(src), qs_len(src)) ; } ; /*------------------------------------------------------------------------------ - * Append leading 'n' bytes of given string to a qstring -- adding at qs->len - * position. - * - * Allocate qstring if required (setting qs->len = qs->cp = 0). + * Set qstring to be copy of given elstring contents. * - * Allocates or extends the body and copies 'n' bytes from src to it, - * adding '\0'. The src pointer is ignored if n == 0. + * See notes above. + */ +extern qstring +qs_set_els(qstring qs, elstring src) +{ + return qs_set_n(qs, els_body(src), els_len(src)) ; +} ; + +/*------------------------------------------------------------------------------ + * Set qstring with given pattern to given length. * - * Sets qs->len to the length of the result (excluding trailing '\0') - * Does not change qs->cp. + * Repeats the given pattern as many times as necessary to get to the given + * length -- using a final partial piece of the pattern as required. * - * Returns: address of the qstring appended to. + * If the pattern is zero length, fills with spaces ! * - * NB: if n == 0, src may be NULL + * See notes above. + */ +extern qstring +qs_set_fill(qstring qs, usize len, const char* src) +{ + return qs_set_fill_n(qs, len, src, (src != NULL ? strlen(src) : 0)) ; +} ; + +/*------------------------------------------------------------------------------ + * Set qstring with given pattern to given length. * - * NB: if n > 0, src string MUST be at least 'n' bytes long. + * Repeats the given pattern as many times as necessary to get to the given + * length -- using a final partial piece of the pattern as required. * - * NB: if appending to a dummy qstring, the old body is copied first. + * See notes above. */ extern qstring -qs_append_n(qstring qs, const char* src, usize n) +qs_set_fill_n(qstring qs, usize len, const char* src, usize flen) { - char* ep ; + char* p ; + char* q ; + usize left ; - qs = qs_add_len(qs, n, &ep) ; + qs = qs_new_size(qs, len) ; /* ensures have body > len */ - if (n != 0) - memcpy(ep, src, n) ; + if (len != 0) + { + if (flen == 0) + { + src = " " ; + flen = strlen(src) ; + } ; + + if (len < flen) + flen = len ; + + q = p = qs_char_nn(qs) ; + memcpy(p, src, flen) ; + p += flen ; + left = len - flen ; + + while (left > 0) + { + if (left < flen) + flen = left ; + + memcpy(p, q, flen) ; + p += flen ; + left -= flen ; + + flen += flen ; + } ; + } ; + + qs_set_len_nn(qs, len) ; + qs_set_cp_nn(qs, 0) ; return qs ; } ; -/*------------------------------------------------------------------------------ - * Copy one qstring to another +/*============================================================================== + * Appending to a qstring * - * If both are NULL, returns NULL. + * Copy the given string to the end of the given qstring (at 'len'), + * allocating qstring and/or extending it as required. * - * Otherwise if dst is NULL, creates a new qstring. + * If this is an alias, it is copied to before being appended to (even if + * appending nothing). * - * Sets dst: body = copy of src->len bytes of src->body -- '\0' terminated. - * cp = src->cp - * len = src->len + * Can append to NULL or empty qstring. * - * Where a NULL src has zero cp and len. + * Sets 'len' to new length. + * Does not affect 'cp'. + * + * Returns: address of the qstring (allocated if required). + */ + +/*------------------------------------------------------------------------------ + * Append given string to a qstring. * - * If not NULL, the destination is guaranteed to have a body, and that will be - * '\0' terminated. + * Treats src == NULL as an empty string. Otherwise src must be a '\0' + * terminated string. * - * Returns: the destination qstring + * Does not copy or count the '\0' terminator. * - * NB: if copying to a dummy qstring, the old body is simply discarded. + * See notes above. + */ +extern qstring qs_append(qstring qs, const char* src) +{ + return qs_append_n(qs, src, (src != NULL) ? strlen(src) : 0) ; +} ; + +/*------------------------------------------------------------------------------ + * Append leading 'n' bytes of given string to a qstring. + * + * If n == 0, src may be NULL + * If n > 0, src string MUST be at least 'n' bytes long. + * + * See notes above. */ extern qstring -qs_copy(qstring dst, qstring src) +qs_append_n(qstring qs, const char* src, usize n) { - usize n ; + qs = qs_extend(qs, n) ; /* allocate, copy any alias, extend body, + set new length, etc */ - if (src == NULL) - { - if (dst == NULL) - return dst ; + if (n != 0) + memcpy(qs_ep_char_nn(qs) - n, src, n) ; - n = 0 ; - dst->cp = 0 ; - } - else - { - if (dst == NULL) - dst = qs_new() ; + return qs ; +} ; - n = src->len ; - dst->cp = src->cp ; - } ; +/*------------------------------------------------------------------------------ + * Append given qstring to a qstring. + * + * See notes above. + */ +extern qstring +qs_append_qs(qstring qs, qstring src) +{ + return qs_append_n(qs, qs_body(src), qs_len(src)) ; +} ; - qs_set_len(dst, n) ; /* TODO: Copies alias !! */ +/*------------------------------------------------------------------------------ + * Append given elstring to a qstring. + * + * See notes above. + */ +extern qstring +qs_append_els(qstring qs, elstring src) +{ + return qs_append_n(qs, els_body(src), els_len(src)) ; +} ; - if (n > 0) - memcpy(dst->s.body, src->s.body, n) ; - *(dst->s.char_body + n) = '\0' ; - return dst ; -} ; -/*------------------------------------------------------------------------------ - * Construct a qstring which is an alias for the given string. - * - * Allocates a qstring if required. - * - * Given string must be '\0' terminated. +/*============================================================================== + * Setting of alias. * * Does NOT copy the given string, but sets the qstring to be a pointer to it. + * This means that: * * NB: it is the caller's responsibility to ensure that the original string * stays put for however long the qstring is an alias for it. @@ -361,150 +428,147 @@ qs_copy(qstring dst, qstring src) * use, the qstring must not be released, so that the alias is not * released. * - * Returns: the address of the qstring. + * Preserves any existing qstring body. + * + * Returns: address of the qstring (allocated if required). + */ + +/*------------------------------------------------------------------------------ + * Set qstring to be an alias for the given string. + * + * Treats src == NULL as an empty string. Otherwise src must be a '\0' + * terminated string. + * + * Does not count the '\0' terminator. + * + * See notes above. */ extern qstring qs_set_alias(qstring qs, const char* src) +{ + return qs_set_alias_n(qs, src, (src != NULL) ? strlen(src) : 0) ; +} ; + +/*------------------------------------------------------------------------------ + * Set qstring to be an alias for the leading 'n' bytes of given string. + * + * If n == 0, src may be NULL + * If n > 0, src string MUST be at least 'n' bytes long. + * + * See notes above. + */ +extern qstring +qs_set_alias_n(qstring qs, const char* src, usize n) { if (qs == NULL) - qs = qs_init_new(NULL, 0) ; + qs = qs_new() ; /* Make the alias. Note that any existing b_body and b_size are preserved, * so that any current body can be reused at a later date. */ - qs->s.const_body = (src != NULL) ? src : "" ; - qs->len = strlen(src) ; - qs->cp = 0 ; - qs->size = 0 ; /* <=> this is an alias ! */ - qs->terminated = true ; + qs_set_body_nn(qs, (n != 0) ? src : "") ; + qs_set_len_nn(qs, n) ; + qs_set_cp_nn(qs, 0) ; + qs->alias = true ; + qs->size = 0 ; /* => empty or alias */ return qs ; } ; /*------------------------------------------------------------------------------ - * Construct a qstring which is an alias for the 'n' given characters. - * - * Allocates a qstring if required. - * - * Given characters are assumed not to be '\0' terminated. + * Set qstring to be an alias for the given qstring. * - * Does NOT copy the given characters, but sets the qstring to be a pointer to - * them. + * If the src is not an alias, then the qstring is an alias for the body of + * src -- so must be careful not to disturb that ! * - * NB: it is the caller's responsibility to ensure that the original characters - * stays put for however long the qstring is an alias for them. + * If the src is an alias, then the qstring is another alias. * - * It is also the caller's responsibility to see that the original - * characters are discarded as required (once the alias is no longer - * required.) - * - * NB: if the qstring is changed in any way, a copy of the aliased characters - * will be made first. + * See notes above. + */ +extern qstring +qs_set_alias_qs(qstring qs, qstring src) +{ + return qs_set_alias_n(qs, qs_body(src), qs_len(src)) ; +} ; + +/*------------------------------------------------------------------------------ + * Construct a qstring which is an alias for the given elstring. * - * NB: if a pointer to the body of the qstring is taken, then while that is in - * use, the qstring must not be released, so that the alias is not - * released. + * If n == 0, src may be NULL + * If n > 0, src string MUST be at least 'n' bytes long. * - * Returns: the address of the qstring. + * See notes above. */ extern qstring -qs_set_alias_n(qstring qs, const char* src, usize len) +qs_set_alias_els(qstring qs, elstring src) { - if (qs == NULL) - qs = qs_init_new(NULL, 0) ; - - if (len == 0) - src = "" ; - else - assert(src != NULL) ; - - /* Make the alias. Note that any existing b_body and b_size are preserved, - * so that any current body can be reused at a later date. - */ - qs->s.const_body = src ; - qs->len = len ; - qs->cp = 0 ; - qs->size = 0 ; /* <=> this is an alias ! */ - qs->terminated = false ; - - return qs ; + return qs_set_alias_n(qs, els_body(src), els_len(src)) ; } ; - - - - - - - - - - - - - +/*============================================================================== + * Copying of qstring + */ /*------------------------------------------------------------------------------ - * Add 'n' to the current string length, allocating or extending the body. + * Copy one qstring to another -- allocating/extending as required. * - * Allocate qstring if required (setting qs->len = qs->cp = 0). + * If both are NULL, returns NULL. + * Otherwise if dst is NULL, creates a new qstring. * - * Returns with a body with size > 0. Allocates to 16 byte boundaries with - * space for '\0' beyond given length. + * If src is NULL it is treated as zero length, with 'cp' == 0. * - * Does NOT affect qs->cp. - * Does set the new qs->len -- qs->len += n - * Does NOT reterminate. + * If src is not an alias, a copy is made to dst. + * If src is an alias, dst becomes another alias for the same thing. * - * Returns: address of qstring + * If dst is an alias, that is discarded. * - * also: sets char** p_ep to point at the *end* of the old len. + * Copies the src 'cp' to the dst. * - * NB: will allocate a new body even if the new len == 0. - * - * NB: always copies all of any aliased string (even if the slen == 0). + * Returns: the destination qstring (allocated if required). */ extern qstring -qs_add_len(qstring qs, usize n, char** p_ep) +qs_copy(qstring dst, qstring src) { - usize slen ; - usize len ; - - len = qs_len(qs) ; - slen = len + n ; + if (src == NULL) + { + qs_clear(dst) ; /* if dst not NULL, clear it */ + return dst ; + } ; - /* Set the new length -- creating if required. - * - * Will always return with a body and no longer an alias (if was one). - */ - qs = qs_set_len(qs, slen) ; + if (src->alias) + dst = qs_set_alias_qs(dst, src) ; + else + dst = qs_set_qs(dst, src) ; - /* Set pointer to old end (len) position. */ - *p_ep = ((char*)qs_body_nn(qs)) + len ; + qs_set_cp_nn(dst, qs_cp_nn(src)) ; /* copy in the src cp. */ - return qs ; + return dst ; } ; /*============================================================================== * printf() and vprintf() type functions - */ - -/*------------------------------------------------------------------------------ - * Formatted print to qstring -- cf printf() * - * Allocate qstring if required (setting qs->len = qs->cp = 0). + * Allocate and/or extend qstring as required. * - * If OK: + * Any alias is discarded. * - * Sets qs->len to the length of the null terminated result. - * Does NOT affect qs->cp. + * Sets 'len' = length of the '\0' terminated result (less the '\0'). + * Sets 'cp' = 0 * - * If fails: + * If fails and qs != NULL: * - * Sets qs->len = qs->cp = 0 and terminates to zero length. + * Sets 'len' = 0 + * Sets 'cp' = 0 + * But retains any existing body. * * Returns: address of qstring if OK - * NULL if failed (unlikely though that is) -- qstring set empty. + * NULL if failed (unlikely though that is) + */ + +/*------------------------------------------------------------------------------ + * Formatted print to qstring -- cf printf() + * + * See notes above. */ extern qstring qs_printf(qstring qs, const char* format, ...) @@ -521,19 +585,7 @@ qs_printf(qstring qs, const char* format, ...) /*------------------------------------------------------------------------------ * Formatted print to qstring -- cf vprintf() * - * Allocate qstring if required (setting qs->len = qs->cp = 0). - * - * If OK: - * - * Sets qs->len to the length of the null terminated result. - * Does NOT affect qs->cp. - * - * If fails: - * - * Sets qs->len = qs->cp = 0 and terminates to zero length. - * - * Returns: address of qstring if OK - * NULL if failed (unlikely though that is) + * See notes above. */ extern qstring qs_vprintf(qstring qs, const char *format, va_list args) @@ -542,11 +594,12 @@ qs_vprintf(qstring qs, const char *format, va_list args) int slen ; qstring qqs ; - qqs = qs ; + qqs = qs ; /* NULL => need to make qs */ if (qs == NULL) - qs = qs_new() ; /* sets size == 0 */ + qqs = qs_new() ; /* Sets size, cp & len = 0 */ else - qs_set_len_nn(qs, 0) ; /* Forget current contents */ + qs_clear(qqs) ; /* Sets cp & len = 0, discard any alias, but + keep existing body */ while (1) { @@ -558,25 +611,24 @@ qs_vprintf(qstring qs, const char *format, va_list args) * the result is still the length required. */ va_copy(ac, args); - slen = vsnprintf (qs_body_nn(qs), qs->size, format, ac) ; + slen = vsnprintf(qs_body_nn(qqs), qqs->size, format, ac) ; va_end(ac); if (slen < 0) - break ; /* Quit if failed */ + break ; /* failed */ - if ((usize)slen < qs->size) + if ((usize)slen < qqs->size) { - qs_set_len_nn(qs, slen) ; - return qs ; /* Exit if succeeded */ + qs_set_len_nn(qqs, slen) ; + return qqs ; /* succeeded */ } ; - qs_make_to_size(qs, slen) ; /* Extend body to required len */ + qs_make_to_size(qqs, slen, 0) ; /* need space for slen */ } ; - if (qqs == NULL) - qs_reset(qs, free_it) ; /* discard what was allocated */ - else - qs_clear(qs) ; + /* Failed... discard anything that has been allocated. */ + if (qs == NULL) + qs_reset(qqs, free_it) ; return NULL ; } ; @@ -586,233 +638,64 @@ qs_vprintf(qstring qs, const char *format, va_list args) */ /*------------------------------------------------------------------------------ - * Compare significant parts of two qstrings. + * Replace 'r' bytes at 'cp' by 'n' bytes -- extending if required. * - * By significant, mean excluding leading/trailing isspace() and treating - * multiple isspace() as single isspace(). + * May increase or decrease 'len'. but does not affect 'cp'. * - * Compares the 'len' portions of the strings. + * Returns: number of bytes beyond 'cp' that now exist. * - * If either is NULL, it is deemed to be an empty string. + * qstring MUST NOT be NULL * - * 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->s.uchar_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->s.uchar_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 ; -} ; - -/*------------------------------------------------------------------------------ - * 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 aliased qstring, a copy is made of the original body. - */ -extern usize -qs_insert(qstring qs, const void* src, usize n) -{ - usize after ; - usize len ; - char* p ; - - qs->terminated = false ; /* NB: require qs != NULL ! */ - - len = qs_len_nn(qs) ; - if (len < qs->cp) /* make len = max(len, cp) ! */ - len = qs->cp ; - - after = len - qs->cp ; - - qs_set_len(qs, len + n) ; /* set len and ensure have space - Makes copy of any aliased string. */ - p = qs_cp_char(qs) ; - if (after > 0) - memmove (p + n, p, after) ; - - if (n > 0) - memmove(p, src, n) ; - - return after ; -} ; - -/*------------------------------------------------------------------------------ - * Replace 'n' bytes at 'cp' -- extending if required. - * - * May increase 'len'. but does not affect 'cp'. + * If 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce + * one or more undefined bytes. * - * 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 aliased qstring, a copy is made of the original body. - */ -extern void -qs_replace(qstring qs, const void* src, usize n) -{ - usize len ; - - qs->terminated = false ; /* NB: require qs != NULL ! */ - - len = qs_len_nn(qs) ; - if (len < (qs->cp + n)) /* make len = max(len, cp + n) */ - len = qs->cp + n ; - - qs_set_len(qs, len) ; /* set len and ensure have space. - Makes copy of any aliased string. */ - - if (n > 0) - memmove(qs_cp_char(qs), src, n) ; -} ; - -/*------------------------------------------------------------------------------ - * Remove 'n' bytes at 'cp' -- extending if required. - * - * May change '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 aliased qstring, a copy is made of the original body. + * If this is a aliased qstring, a copy is made, so is no longer an alias. */ extern usize -qs_delete(qstring qs, usize n) +qs_replace(qstring qs, usize r, const void* src, usize n) { - usize after ; - char* p ; - usize len ; + usize cp, len, nlen, after ; + const char* ap ; + char* np ; - qs->terminated = false ; /* NB: require qs != NULL ! */ + len = qs_len_nn(qs) ; + cp = qs_cp_nn(qs) ; - len = qs_len_nn(qs) ; - - /* If deleting to or beyond 'len', force len to cp */ - if ((qs->cp + n) >= len) - { - len = qs->cp ; - qs_set_len_nn(qs, len) ; /* truncate now, so that if this is an - aliased string, only copy what is - going to be kept. */ - after = 0 ; /* nothing to move */ - } + if ((cp + r) >= len) + /* Replacing up to or beyond the end of the string */ + after = 0 ; else - after = len - (qs->cp + n) ; + /* Replacing section short of the end of the string */ + after = len - (cp + r) ; - qs_set_len(qs, len) ; /* set len and ensure have space. - Makes copy of any aliased string. */ + nlen = cp + n + after ; + if (nlen >= qs->b_size) + qs_new_body(qs, nlen, qs->alias) ; /* keeping any alias */ + ap = np = qs->b_body ; + if (qs->alias) + { + ap = qs_body_nn(qs) ; /* copy from the alias */ - /* Watch out for "dummy" */ - if (qs->size == 0) - qs_make_to_size(qs, len) ; + uint before = cp ; + if (before > len) + before = len ; - /* If deleting up to or beyond len, then simply set len == cp - * note that this may reduce or increase len ! - */ - if ((qs->cp + n) >= len) - { - if (qs->cp < len) - qs_set_len_nn(qs, qs->cp) ; /* discard stuff after qs->cp */ + if (before > 0) + memmove(np, ap, before) ; - qs_set_len(qs, qs->cp) ; /* set len */ - return 0 ; /* nothing after */ - } + qs_set_real_body_nn(qs) ; + } ; - /* There is at least one byte after cp (so body must exist) */ - after = len - (qs->cp + n) ; + if (after > 0) /* move the after part before inserting */ + memmove(np + cp + n, ap + cp + r, after) ; - if (n > 0) - { - p = qs_cp_char(qs) ; - memmove (p, p + n, after) ; + if (n > 0) /* insert */ + memmove(np + cp, src, n) ; - qs_set_len_nn(qs, len - n) ; - } ; + /* Set new 'len' */ + qs_set_len_nn(qs, nlen) ; - return after ; + return n + after ; } ; -- cgit v1.2.3