/* * 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 */