diff options
Diffstat (limited to 'lib/qstring.h')
-rw-r--r-- | lib/qstring.h | 365 |
1 files changed, 365 insertions, 0 deletions
diff --git a/lib/qstring.h b/lib/qstring.h new file mode 100644 index 00000000..1841657e --- /dev/null +++ b/lib/qstring.h @@ -0,0 +1,365 @@ +/* Some string handling -- header + * Copyright (C) 2009 Chris Hall (GMCH), Highwayman + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _ZEBRA_QSTRING_H +#define _ZEBRA_QSTRING_H + +#include "zebra.h" + +#include <stddef.h> +#include <stdint.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__ */ + +/*============================================================================== + * These "qstrings" address the ... + * + * + * + */ + +typedef struct qstring qstring_t ; +typedef struct qstring* qstring ; + +struct qstring +{ + void* body ; + size_t size ; + + size_t len ; + size_t cp ; +} ; + +/*------------------------------------------------------------------------------ + * 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. + */ +Inline char* /* pointer to body of qstring */ +qs_chars(qstring qs) +{ + return (char*)qs->body ; +} ; + +Inline unsigned char* /* pointer to body of qstring */ +qs_bytes(qstring qs) +{ + return (unsigned char*)qs->body ; +} ; + +Inline char* /* pointer to given offset in qstring */ +qs_chars_at(qstring qs, size_t off) +{ + return qs_chars(qs) + off ; +} ; + +Inline unsigned char* /* pointer to given offset in qstring */ +qs_bytes_at(qstring qs, size_t off) +{ + return qs_bytes(qs) + off ; +} ; + +Inline char* /* pointer to 'cp' offset in qstring */ +qs_cp_char(qstring qs) +{ + return qs_chars_at(qs, qs->cp) ; +} ; + +Inline unsigned char* /* pointer to 'cp' offset in qstring */ +qs_cp_byte(qstring qs) +{ + return qs_bytes_at(qs, qs->cp) ; +} ; + +Inline char* /* pointer to 'len' offset in qstring */ +qs_ep_char(qstring qs) +{ + return qs_chars_at(qs, qs->len) ; +} ; + +Inline unsigned char* /* pointer to 'len' offset in qstring */ +qs_ep_byte(qstring qs) +{ + return qs_bytes_at(qs, qs->len) ; +} ; + +/*============================================================================== + * Functions + */ + +extern qstring +qs_init_new(qstring qs, size_t len) ; + +extern size_t +qs_alloc(qstring qs, size_t len) ; + +extern void +qs_free_body(qstring qs) ; + +extern qstring +qs_reset(qstring qs, int free_structure) ; + +#define qs_reset_keep(qs) qs_reset(qs, 0) +#define qs_reset_free(qs) qs_reset(qs, 1) + +extern int +qs_printf(qstring qs, const char* format, ...) PRINTF_ATTRIBUTE(2, 3) ; + +extern int +qs_vprintf(qstring qs, const char *format, va_list args) ; + +extern size_t +qs_set(qstring qs, const char* s) ; + +extern size_t +qs_set_n(qstring qs, const char* s, size_t len) ; + +Inline size_t +qs_need(qstring qs, size_t len) ; + +Inline size_t +qs_set_len(qstring qs, size_t len) ; + +Inline void +qs_set_empty(qstring qs) ; + +Inline size_t +qs_len(qstring qs) ; + +Inline size_t +qs_size(qstring qs) ; + +Inline void* +qs_term(qstring qs) ; + +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) ; + +/*============================================================================== + * The Inline functions. + */ + +/*------------------------------------------------------------------------------ + * Need space for a string of 'len' characters (plus possible '\0'). + * + * Returns: size of the qstring body + * (which includes the extra space allowed for '\0') + * + * NB: asking for 0 bytes will cause a body to be allocated, ready for any + * '\0' ! + * + * NB: has no effect on 'cp' or 'len'. + */ +Inline size_t +qs_need(qstring qs, size_t len) +{ + if (len < qs->size) + { + assert(qs->body != NULL) ; + return qs->size ; + } + else + return qs_alloc(qs, len) ; +} ; + +/*------------------------------------------------------------------------------ + * Set 'len' -- allocate or extend body as required. + * + * Returns: size of the qstring body + * (which includes the extra space allowed for '\0') + * + * 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'. + */ +Inline size_t +qs_set_len(qstring qs, size_t len) +{ + qs->len = len ; + return qs_need(qs, len) ; +} ; + +/*------------------------------------------------------------------------------ + * Reset contents of qstring. + * + * Sets 'cp' = 'len' = 0. Sets first byte of body (if any) to NULL. + */ +Inline void +qs_set_empty(qstring qs) +{ + qs->len = 0 ; + qs->cp = 0 ; + if (qs->body != NULL) + *((char*)qs->body) = '\0' ; +} ; + +/*------------------------------------------------------------------------------ + * Get length of qstring -- by doing strlen() -- and record it in qs->len. + * + * Returns: the string length + * + * NB: if no body has been allocated, length = 0 + */ +Inline size_t +qs_len(qstring qs) +{ + return qs->len = (qs->body != NULL) ? strlen(qs_chars(qs)) : 0 ; +} ; + +/*------------------------------------------------------------------------------ + * Get size of qstring body. + * + * NB: if no body has been allocated, size = 0 + */ +Inline size_t +qs_size(qstring qs) +{ + return qs->size ; +} ; + +/*------------------------------------------------------------------------------ + * Set '\0' at qs->len -- allocate or extend body as required. + * + * Returns address of body. + */ +Inline void* +qs_term(qstring qs) +{ + size_t len ; + if ((len = qs->len) >= qs->size) + qs_alloc(qs, len) ; + + *qs_chars_at(qs, len) = '\0' ; + + return qs->body ; +} ; + +/*------------------------------------------------------------------------------ + * 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: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce + * one or more undefined bytes. + * + * NB: the string is NOT re-terminated. + */ +Inline size_t +qs_insert(qstring qs, const void* src, size_t n) +{ + 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 ; +} ; + +/*------------------------------------------------------------------------------ + * Replace 'n' bytes at 'cp' -- extending if required. + * + * May increase 'len'. but does not affect 'cp'. + * + * NB: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce + * one or more undefined bytes. + * + * NB: the string is NOT re-terminated. + */ +Inline void +qs_replace(qstring qs, const void* src, size_t n) +{ + if (qs->len < qs->cp + n) + qs_set_len(qs, qs->cp + n) ; /* set len and ensure have space */ + + 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: if 'cp' > 'len', then sets 'len' = 'cp' first -- which will introduce + * one or more undefined bytes. + * + * NB: the string is NOT re-terminated. + */ +Inline size_t +qs_delete(qstring qs, size_t n) +{ + size_t after ; + char* p ; + + /* 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 ; +} ; + +#endif /* _ZEBRA_QSTRING_H */ |