/* * Copyright (c) 2000-2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * * $Id: str.h,v 1.76 2007/11/14 06:03:08 ca Exp $ */ #ifndef SM_STR_H #define SM_STR_H 1 #include "sm/generic.h" #include "sm/types.h" #include "sm/error.h" #include "sm/rpool.h" #include "sm/limits.h" #include "sm/rdstr.h" typedef struct sm_str_S sm_str_T, *sm_str_P; #ifndef SM_STR_CHECK # define SM_STR_CHECK 1 #endif /* ** sm_str_T -- Stores buf data and length information. ** ** Members: ** sm_str_base -- uchar * to data (doesn't need to end with '\0'). ** sm_str_size -- Total bytes allocated. ** sm_str_len -- Total number of characters in buf. ** sm_str_max -- Maximum number of characters in buf. ** sm_str_rpool -- rpool to allocate from. ** ** Invariants: ** sm_str_len <= sm_str_size <= sm_str_max ** ** Notices: ** - the structure could be extended to a general buffer, ** like iobuf (VSTRING) to put/get characters out of it. ** This would make loops through the data more abstract, ** e.g., instead of ** for (i = 0; i < len(str); i++) ** do something with elem(str, i) ** it could be ** for (ch = first(str); !EOS(str); ch = get(str)) ** do something with ch ** however, that requires read/write pointers and hence ** there can't be independent operations on the string. ** ** - we could use reference counting to avoid free()ing ** a buf twice if it is used as: ** d = sm_str_cat(s1, s2) ** because now d and s1 are identical (unless the ** operation fails). ** ** - a flag field could note whether this is statically ** allocated and can't be changed, ** whether the current size is fixed (could be achieve ** wiht sm_str_max) ** ** - reference counting could also be used for the data ** part, which may allow sharing (use copy-on-write). ** ** - this structure is only "public" due to macros accessing ** components, e.g., sm_str_len(), otherwise the ** data structure could be in buf.c or an internal ** include file. ** ** - sm_str_max should be always set and it should be ** less than INT_MAX. Then we can get rid of some ** overflow tests (sm_str_size wrap-around). Moreover, ** this would be better for some other code which ** assumes int is good enough as index. ** XXX should we enforce this? ** SM_ASSERT(sm_str_max != 0 && sm_str_max < INT_MAX) */ struct sm_str_S { sm_magic_T sm_magic; uchar *sm_str_base; uint sm_str_len; uint sm_str_size; uint sm_str_max; #if SM_STR_READ uint sm_str_rd; /* read index; not used anywhere */ /* matches sm_rcb_rw for sm_rcb_T */ #endif sm_rpool_P sm_str_rpool; }; sm_str_P sm_str_new(sm_rpool_P _rpool, uint _len, uint _maxlen); sm_str_P sm_str_crt(sm_rpool_P _rpool, uchar *_str, uint _len, uint _maxlen); /* assign necessary elements to an existing str_buf */ #define sm_str_assign(str, rpool, s, len, maxlen) \ do \ { \ (str).sm_str_base = (s); \ (str).sm_str_size = (len); \ (str).sm_str_len = (len); \ (str).sm_str_max = (maxlen); \ (str).sm_str_rpool = (rpool); \ (str).sm_magic = SM_STR_MAGIC; \ } while (0) /* save an existing str */ #define SM_STR_SAVE(str, save) \ do \ { \ (save).sm_str_base = (str).sm_str_base; \ (save).sm_str_size = (str).sm_str_size; \ (save).sm_str_len = (str).sm_str_len; \ (save).sm_str_max = (str).sm_str_max; \ (save).sm_str_rpool = (str).sm_str_rpool; \ (save).sm_magic = SM_STR_MAGIC; \ } while (0) /* restore str from "save" */ #define SM_STR_RESTORE(str, save) SM_STR_SAVE((save), (str)) sm_ret_T sm_str_resize_data(sm_str_P _str, uint _len); #if SM_STR_CHECK uint sm_str_getlen(sm_str_P _str); uint sm_str_getsize(sm_str_P _str); int sm_str_setmax(sm_str_P _str, uint _max); uint sm_str_getmax(sm_str_P _str); sm_ret_T sm_str_space(sm_str_P _str, uint _new_len); sm_ret_T sm_str_wr_elem(sm_str_P _str, uint _i, uchar _c); uchar sm_str_rd_elem(sm_str_P _str, uint _i); #else /* SM_STR_CHECK */ # define sm_str_getlen(str) ((str)->sm_str_len) # define sm_str_getsize(str) ((str)->sm_str_size) # define sm_str_setmax(str, m) (str)->sm_str_max = (m) # define sm_str_getmax(str) (str)->sm_str_max # define sm_str_space(str, new_len) \ (((new_len) <= (str)->sm_str_size) ? SM_SUCCESS \ : sm_str_resize_data((str), (new_len))) # define sm_str_wr_elem(str, i, c) (str)->sm_str_base[i] = (c) # define sm_str_rd_elem(str, i) ((str)->sm_str_base[i]) #endif /* SM_STR_CHECK */ # define SM_STR_PUT(str, c) (((str)->sm_str_len == (str)->sm_str_size) \ ? sm_str_put((str), (c)) \ : ((str)->sm_str_base[(str)->sm_str_len] = (c), \ (str)->sm_str_len++, SM_SUCCESS)) #define SM_STR_SETLEN(str, len) (SM_ASSERT((len) <= (str)->sm_str_size), ((str)->sm_str_len) = (len)) #define sm_str_data(str) ((str)->sm_str_base) void sm_str_free(sm_str_P _str); #define SM_STR_FREE(ptr) do \ { \ if ((ptr) != NULL) \ { \ sm_str_free(ptr); \ (ptr) = NULL; \ } \ } while (0) #if SM_STR_CHECK void sm_str_clr(sm_str_P _str); #else # define sm_str_clr(str) (str)->sm_str_len = 0 #endif #define SM_STR_CLR(ptr) do { \ if ((ptr) != NULL) \ sm_str_clr(ptr); \ } while (0) sm_ret_T sm_str_shorten(sm_str_P _str, int _l); /* last character if string is non-empty otherwise -1 (XXX is -1 ok?) */ # define SM_STR_LAST(str) ((str)->sm_str_len > 0 ? ((str)->sm_str_base[(str)->sm_str_len - 1]) : (-1)) uchar *sm_str_getdata(sm_str_P _str); uchar *sm_str_copydata(sm_rpool_P _rpool, sm_str_P _str); sm_str_P sm_str_dup(sm_rpool_P _rpool, const sm_str_P _src); sm_ret_T sm_str_cpy(sm_str_P _dst, const sm_str_P _src); sm_ret_T sm_str_dc(sm_rpool_P _rpool, sm_str_P *_pdst, const sm_str_P _src); sm_ret_T sm_str_cat(sm_str_P _dst, const sm_str_P _src); sm_ret_T sm_str_catpart(sm_str_P _dst, const sm_rdstr_P _src, uint _first, uint _last); sm_ret_T sm_str_catv(sm_str_P _dst, int _n, ...); sm_ret_T sm_str_catmv(sm_str_P _dst, int _n, ...); sm_ret_T sm_str_rm_trail(sm_str_P _str, const char *_rmchars); sm_ret_T sm_str_rm_trail_sp(sm_str_P _str); bool sm_str_eq(const sm_str_P _s1, const sm_str_P _s2); int sm_str_cmp(const sm_str_P _s1, const sm_str_P _s2); int sm_str_casecmp(const sm_str_P _s1, const sm_str_P _s2); sm_ret_T sm_str_scopyn(sm_str_P _str, const char *_src, uint _len); sm_ret_T sm_str_scopy(sm_str_P _str, const char *_src); sm_str_P sm_str_scpy(sm_rpool_P _rpool, const char *_str, uint _maxlen); sm_str_P sm_str_scpy0(sm_rpool_P _rpool, const char *_src, uint _maxlen); sm_str_P sm_str_scpyn(sm_rpool_P _rpool, const char *_src, uint _n, uint _maxlen); sm_ret_T sm_str_scat(sm_str_P _str, const char *_append); sm_ret_T sm_str_scatn(sm_str_P _str, const char *_append, uint _len); sm_ret_T sm_str_scatv(sm_str_P _dst, int n, ...); sm_str_P sm_str_scpyn0(sm_rpool_P _rpool, const char *_src, uint _n, uint _maxlen); sm_ret_T sm_str_scatn0(sm_str_P _str, const char *_append, uint _len); sm_ret_T sm_str_scat0(sm_str_P _str, const char *_append); sm_ret_T sm_str_put(sm_str_P _str, uchar _c); sm_ret_T sm_str_term(sm_str_P _str); sm_ret_T sm_str_putuint32(sm_str_P _str, uint32_t _n); uint sm_str_sanitize(sm_str_P _str); sm_ret_T sm_str_split(sm_str_P _str, uchar _delim, bool _excl, sm_str_P _left, sm_str_P _right); sm_ret_T sm_str_splitidx(sm_str_P _str, uint _i, bool _excl, sm_str_P _left, sm_str_P _right); sm_ret_T sm_str2argv(sm_str_P _str, uint _offset, uint _maxargs, uint *_argv); sm_ret_T sm_str2args(sm_str_P _str, uint _offset, uint _maxargs, uint *_argnames, uint *_argvalues); #if SIZEOF_OFF_T == 4 # define sm_str_put3off_t(str, n1, n2, n3) sm_str_put3uint32(str, n1, n2, n3) # define sm_str_putoff_t(str, n) sm_str_putuint32(str, n) #elif SIZEOF_OFF_T == 8 # define sm_str_put3off_t(str, n1, n2, n3) sm_str_put3uint64(str, n1, n2, n3) # define sm_str_putoff_t(str, n) sm_str_putuint64(rcb, n) #else ERROR _SIZEOF_OFF_T is neither 4 not 8: SIZEOF_OFF_T #endif bool sm_str2lower(sm_str_P _str); sm_ret_T sm_str_shift(sm_str_P _str, uint _off); sm_ret_T sm_str_unquote(sm_str_P _str); sm_ret_T sm_str_fchrquoted(sm_str_P _str, const uchar *_delim, uint *_pidx); sm_ret_T sm_str_fchr(sm_str_P _str, const uchar *_delim, uint *_pidx); sm_ret_T sm_str_lchr(sm_str_P _str, const uchar *_delim, uint *_pidx); sm_ret_T xtextify(char *_t, char *_taboo, sm_str_P _str); #endif /* SM_STR_H */