/*
* 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 */
syntax highlighted by Code2HTML, v. 0.9.1