/*
* Copyright (c) 2002-2006 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: cstr.h,v 1.28 2006/10/05 04:27:35 ca Exp $
*/
#ifndef SM_CSTR_H
#define SM_CSTR_H 1
#include "sm/generic.h"
#include "sm/types.h"
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/memops.h"
#include "sm/heap.h"
#include "sm/limits.h"
#if MTA_USE_PTHREADS
# include "sm/pthread.h"
#endif
#ifndef SM_CSTR_CHECK
# define SM_CSTR_CHECK 1
#endif
#ifndef CSTR_MAX_SIZE
# define CSTR_MAX_SIZE (SIZE_T_MAX / 2)
#endif
typedef struct sm_cstr_S sm_cstr_T, *sm_cstr_P;
/*
** sm_cstr_T -- Stores a constant string: the string can only be
** allocated once and thereafter only read/copied/freed.
**
** Members:
** sm_cstr_base -- uchar * to data (doesn't need to end with '\0').
** sm_cstr_len -- Total number of characters in buf.
** sm_cstr_refcnt -- number of references
**
** We could "embed" the string directly in the struct,
** it would allow us to use only one malloc/free, but it
** would keep us from using a preallocated string.
*/
struct sm_cstr_S
{
sm_magic_T sm_magic;
uchar *sm_cstr_base;
uint sm_cstr_len;
uint sm_cstr_refcnt;
#if MTA_USE_PTHREADS
/* mutex to protect changes of the reference counter */
pthread_mutex_t sm_cstr_mutex;
#endif
};
/* extern sm_cstr_P sm_cstr_new(uint _len); */
sm_cstr_P sm_cstr_crt(uchar *_str, uint _len);
/* assign necessary elements to an existing str_buf */
#define sm_cstr_assign(str, s, len) \
do \
{ \
(str).sm_cstr_base = (s); \
(str).sm_cstr_len = (len); \
(str).sm_cstr_refcnt = 1; \
} while (0)
#if MTA_USE_PTHREADS
/* WARNING: this asserts that lock/unlock succeeds! */
# define SM_CSTR_LOCK(cstr) SM_ASSERT(pthread_mutex_lock(&(cstr)->sm_cstr_mutex) == 0)
# define SM_CSTR_UNLOCK(cstr) SM_ASSERT(pthread_mutex_unlock(&(cstr)->sm_cstr_mutex) == 0)
# define SM_CSTR_MUT_FREE(cstr) SM_ASSERT(pthread_mutex_destroy(&(cstr)->sm_cstr_mutex) == 0)
#else
# define SM_CSTR_LOCK(cstr) SM_NOOP
# define SM_CSTR_UNLOCK(cstr) SM_NOOP
# define SM_CSTR_MUT_FREE(cstr) SM_NOOP
#endif
#if SM_CSTR_CHECK
bool sm_cstr_eq(const sm_cstr_P _s1, const sm_cstr_P _s2);
bool sm_cstr_caseq(const sm_cstr_P _s1, const sm_cstr_P _s2);
# define SM_CSTR_EQ(s1, s2) sm_cstr_eq((s1), (s2))
sm_cstr_P sm_cstr_dup(sm_cstr_P _src);
# define SM_CSTR_DUP(src) sm_cstr_dup(src)
#else /* SM_CSTR_CHECK */
# define SM_CSTR_EQ(s1, s2) \
((s1) == (s2) || (((s1)->sm_cstr_len == (s2)->sm_cstr_len) && \
sm_memeq((s1)->sm_cstr_base, (s2)->sm_cstr_base, (s1)->sm_cstr_len)))
# define SM_CSTR_DUP(src) (SM_CSTR_LOCK(src), (src)->sm_cstr_refcnt++, SM_CSTR_UNLOCK(src), src)
#endif /* SM_CSTR_CHECK */
#define SM_CSTR_CASEQ(s1, s2) \
((s1) == (s2) || (((s1)->sm_cstr_len == (s2)->sm_cstr_len) && \
sm_memcaseeq((s1)->sm_cstr_base, (s2)->sm_cstr_base, (s1)->sm_cstr_len)))
/* Add SM_ASSERT(i < ((str)->sm_cstr_len)) ? */
#define sm_cstr_rd_elem(str, i) ((str)->sm_cstr_base[i])
#define sm_cstr_getlen(str) ((str)->sm_cstr_len)
#define sm_cstr_data(str) ((str)->sm_cstr_base)
/* inline version of sm_cstr_free() with check whether cstr != NULL */
#define SM_CSTR_FREE(cstr) do \
{ \
if ((cstr) != NULL) \
{ \
SM_CSTR_LOCK(cstr); \
SM_ASSERT(((cstr)->sm_cstr_refcnt) > 0); \
if ((--((cstr)->sm_cstr_refcnt)) == 0) \
{ \
SM_CSTR_UNLOCK(cstr); \
sm_free(cstr->sm_cstr_base); \
SM_CSTR_MUT_FREE(cstr); \
sm_free(cstr); \
} \
else \
SM_CSTR_UNLOCK(cstr); \
(cstr) = NULL; \
} \
} while (0)
/* last character if string is non-empty otherwise -1 (XXX is -1 ok?) */
# define SM_CSTR_LAST(str) ((str)->sm_cstr_len > 0 ? ((str)->sm_cstr_base[(str)->sm_cstr_len - 1]) : (-1))
#if 0
/* UGLY: add '\0' when cstr is created? can't change it afterwards! */
uchar *sm_cstr_getdata(sm_cstr_P _cstr);
#endif
int sm_cstr_cmp(const sm_cstr_P _s1, const sm_cstr_P _s2);
sm_cstr_P sm_cstr_scpyn(const uchar *_src, uint _n);
sm_cstr_P sm_cstr_scpyn0(const uchar *_src, uint _n);
sm_cstr_P sm_cstr_scpyvn0(const uchar *_src, uint _n, ...);
void sm_cstr_free(sm_cstr_P _str);
#define SM_IS_CSTR(str) SM_REQUIRE_ISA((str), SM_CSTR_MAGIC)
#endif /* SM_CSTR_H */
syntax highlighted by Code2HTML, v. 0.9.1