/*
 * Copyright (c) 2002-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: rcb.h,v 1.67 2007/01/31 04:18:17 ca Exp $
 */

#ifndef SM_RCB_H
#define SM_RCB_H 1

/*
**  Notice: This is almost a copy of sm/str.h
*/

#include "sm/generic.h"
#include "sm/types.h"
#include "sm/error.h"
#include "sm/magic.h"
#include "sm/rpool.h"
#include "sm/str.h"
#if SM_RCB_ST
# include "statethreads/st.h"
#endif
#if !SM_NO_CSTR
# include "sm/cstr.h"
#endif

#ifndef SM_STR_READ
# define SM_STR_READ	1
#endif

#ifndef MTA_USE_RCBV_INT2
# define MTA_USE_RCBV_INT2	1
#endif

#ifndef MTA_USE_RCBV_INTN
# define MTA_USE_RCBV_INTN	1
#endif
#ifndef MTA_USE_RCBV_STRN
# define MTA_USE_RCBV_STRN	0
#endif

#if SM_STR_CHECK
# ifndef SM_RCB_CHECK
#  define SM_RCB_CHECK 1
# endif
#endif

#ifndef SM_RCB_END_RCB
/* activate code to mark end of RCB: currently broken! */
# define SM_RCB_END_RCB	0
#endif

typedef struct sm_rcb_S	sm_rcb_T, *sm_rcb_P;

/*
**  sm_rcb_T -- Stores rcb data and length information.
**
**	Members:
**		sm_rcb_base -- uchar * to data (doesn't need to end with '\0').
**		sm_rcb_size -- Total bytes allocated.
**		sm_rcb_len -- Total number of characters in rcb.
**		sm_rcb_max -- Maximum number of characters in rcb.
**		sm_rcb_rpool -- rpool to allocate from.
**		sm_rcb_rw -- read index/space left to write.
**
**	Invariants:
**	  both modes:
**		sm_rcb_len <= sm_rcb_size <= sm_rcb_max
**	  read mode:
**		sm_rcb_rw <= sm_str_len
**	  write mode:
**		no length specified: sm_rcb_rw < 0
**		length specified: sm_rcb_rw > sizeof(data) to put into RCB
**
**	Notices:
**		See sm/str.h
**
**  Content of an RCB:
**	first 4 bytes: total length of RCB
**	then a sequence of records:
**		4 bytes: length of "payload" of record: value "l"
**		4 bytes: record type
**		l bytes: "payload" of record: l bytes
**	records are aligned to 4 bytes.
*/

struct sm_rcb_S
{
	sm_magic_T	 sm_magic;
	uchar		*sm_rcb_base;
	uint		 sm_rcb_len;
	uint		 sm_rcb_size;
	uint		 sm_rcb_max;
	int		 sm_rcb_rw; /* read index, must be last to match str */
	sm_rpool_P	 sm_rcb_rpool;
#if SM_STR_CHECK
	uint		 sm_rcb_state;
#endif
};

sm_rcb_P sm_rcb_new(sm_rpool_P _rpool, uint _len, uint _max);
#if 0
sm_rcb_P sm_rcb_crt(sm_rpool_P rpool, uchar *rcb, uint len, uint maxlen);
#endif

/* defines for rcb_putv() */
#define SM_RCBV_INT     1
#if MTA_USE_RCBV_INT2
# define SM_RCBV_INT2   2
#endif
#define SM_RCBV_INT64   3
#define SM_RCBV_STR     4
#define SM_RCBV_CSTR    5
#define SM_RCBV_BUF     6
#define SM_RCBV_RDSTR   7
#if MTA_USE_RCBV_INTN
# define SM_RCBV_INTN   8
# define SM_RCBV_INTA   9
#endif
#if MTA_USE_RCBV_STRN
# define SM_RCBV_STRA   10
#endif
#define SM_RCBV_END     11
#if SIZEOF_OFF_T == 4
#define SM_RCBV_OFF     SM_RCBV_INT
#elif SIZEOF_OFF_T == 8
#define SM_RCBV_OFF     SM_RCBV_INT64
#else
  ERROR _SIZEOF_OFF_T is neither 4 not 8: SIZEOF_OFF_T
#endif


#if SM_RCB_ST
# define rcb_fd_T	st_netfd_t
#else
# define rcb_fd_T	int
#endif

sm_ret_T sm_rcb_put(sm_rcb_P _rcb, uchar _c);

#if SM_STR_CHECK
int sm_rcb_get(sm_rcb_P _rcb);
#define SM_RCB_PUT(rcb, c) sm_rcb_put((rcb), (c))
#define SM_RCB_GET(rcb) sm_rcb_get(rcb)

#else /* SM_STR_CHECK */

#define SM_RCB_GET(rcb) (((rcb)->sm_rcb_len <= (rcb)->sm_rcb_rw)	\
			? sm_error_perm(SM_EM_RECCOM, SM_E_OVFLW_NS)	\
			: (rcb)->sm_rcb_base[(rcb)->sm_rcb_rw++])
#define SM_RCB_PUT(rcb, c) (((rcb)->sm_rcb_len == (rcb)->sm_rcb_size) ? \
	sm_rcb_put((rcb), (c)) : \
	((rcb)->sm_rcb_base[(rcb)->sm_rcb_len++] = (c)), SM_SUCCESS)

#endif /* SM_STR_CHECK */


#if SM_RCB_END_RCB
/* end of RCB marker length: l + record type + value: 3 * sizeof(uint32_t) */
#define SM_RCB_EORCB_LEN	12
#define SM_RCB_ISEOB(rcb)	((rcb)->sm_rcb_len <= (rcb)->sm_rcb_rw + SM_RCB_EORCB_LEN)
#else /* SM_RCB_END_RCB */
#define SM_RCB_EORCB_LEN	0
#define SM_RCB_ISEOB(rcb)	((int) (rcb)->sm_rcb_len <= (rcb)->sm_rcb_rw)
#endif /* SM_RCB_END_RCB */

sm_ret_T sm_rcb_putuint32(sm_rcb_P _rcb, uint32_t _n);
sm_ret_T sm_rcb_putuint64(sm_rcb_P _rcb, uint64_t _u);
sm_ret_T sm_rcb_put2uint32(sm_rcb_P _rcb, uint32_t _n1, uint32_t _n2);
sm_ret_T sm_rcb_put3uint32(sm_rcb_P _rcb, uint32_t _n1, uint32_t _n2, uint32_t _n3);
#if MTA_USE_RCBV_INT2
sm_ret_T sm_rcb_put4uint32(sm_rcb_P _rcb, uint32_t _n1, uint32_t _n2, uint32_t _n3, uint32_t _n4);
#endif
sm_ret_T sm_rcb_put3uint64(sm_rcb_P _rcb, uint32_t _n1, uint32_t _n2, uint64_t _u);
#if MTA_USE_RCBV_INTN
sm_ret_T sm_rcb_putnuint32(sm_rcb_P _rcb, uint32_t _rt, uint _n, ...);
sm_ret_T sm_rcb_putauint32(sm_rcb_P _rcb, uint32_t _rt, uint _n, uint32_t *_av);
#endif
#if MTA_USE_RCBV_STRN
sm_ret_T sm_rcb_putastr(sm_rcb_P _rcb, uint32_t _rt, uint _n, sm_str_P *_strv);
#endif

#if SIZEOF_OFF_T == 4
# define sm_rcb_putoff_t(rcb, n) sm_rcb_putuint32((rcb), (uint32_t) (n))
# define sm_rcb_put3off_t(rcb, n1, n2, n3) sm_rcb_put3uint32((rcb), (n1), (n2), (uint32_t) (n3))
# define sm_rcb_getoff_t(rcb, pv1) sm_rcb_getuint32((rcb), (uint32_t *) (pv1))
# define sm_rcb_get3off_t(rcb, pv1, pv2, pv3) sm_rcb_get3uint32((rcb), (pv1), (pv2), (uint32_t *) (pv3))
#elif SIZEOF_OFF_T == 8
# define sm_rcb_putoff_t(rcb, n) sm_rcb_putuint64((rcb), (uint64_t) (n))
# define sm_rcb_put3off_t(rcb, n1, n2, n3) sm_rcb_put3uint64((rcb), (n1), (n2), (uint64_t) (n3))
# define sm_rcb_getoff_t(rcb, pv1) sm_rcb_getuint64((rcb), (uint64_t *) (pv1))
# define sm_rcb_get3off_t(rcb, pv1, pv2, pv3) sm_rcb_get3uint64((rcb), (pv1), (pv2), (uint64_t *) (pv3))
#else
  ERROR _SIZEOF_OFF_T is neither 4 not 8: SIZEOF_OFF_T
#endif

/* flag values for sm_rcb_putv() */
#define RCB_PUTV_NONE	0x00
#define RCB_PUTV_FIRST	0x01
#define RCB_PUTV_OPEN	0x02
#define RCB_PUTV_CLOSE	0x04

/* flag values for sm_rcb_putrec() */
#define RCB_PUTR_NONE	0x00	/* do nothing special */
#define RCB_PUTR_FIRST	0x01
#define RCB_PUTR_OPEN	0x02
#define RCB_PUTR_CLOSE	0x04
#define RCB_PUTR_DFLT	0x07	/* default */

sm_ret_T sm_rcb_putv(sm_rcb_P _rcb, uint _flags, ...);
sm_ret_T sm_rcb_putrec(sm_rcb_P _rcb, uint _flags, uint32_t _sz, int _n, ...);
sm_ret_T sm_rcb_putstr(sm_rcb_P _dst, const sm_rcb_P _src);

sm_ret_T sm_rcb_getuint32(sm_rcb_P _rcb, uint32_t *_pval);
sm_ret_T sm_rcb_getuint64(sm_rcb_P _rcb, uint64_t *_pu);
sm_ret_T sm_rcb_get2uint32(sm_rcb_P _rcb, uint32_t *_pv1, uint32_t *_pv2);
sm_ret_T sm_rcb_get3uint32(sm_rcb_P _rcb, uint32_t *_pv1, uint32_t *_pv2, uint32_t *_pv3);
#if MTA_USE_RCBV_INT2
sm_ret_T sm_rcb_get4uint32(sm_rcb_P _rcb, uint32_t *_pv1, uint32_t *_pv2, uint32_t *_pv3, uint32_t *_pv4);
#endif
sm_ret_T sm_rcb_get3uint64(sm_rcb_P _rcb, uint32_t *_pv1, uint32_t *_pv2, uint64_t *_pu);
sm_ret_T sm_rcb_peek2uint32(sm_rcb_P _rcb, uint32_t *_pv1, uint32_t *_pv2);
#if MTA_USE_RCBV_INTN
sm_ret_T sm_rcb_getauint32(sm_rcb_P _rcb, uint _nmax, uint *_pn, uint32_t *_prt, uint32_t *_pv);
#endif

sm_ret_T sm_rcb_putn(sm_rcb_P _rcb, const uchar *_put, uint n);
sm_ret_T sm_rcb_getn(sm_rcb_P _rcb, uchar *_get, uint _n);
sm_ret_T sm_rcb_getstr(sm_rcb_P _rcb, sm_str_P _str, uint _n);
sm_ret_T sm_rcb_getnstr(sm_rcb_P _rcb, sm_str_P *_str, uint _n);
sm_ret_T sm_rcb_getn0str(sm_rcb_P _rcb, sm_str_P *_str, uint _n);
sm_ret_T sm_rcb_getdata(sm_rcb_P _rcb, const uchar **_data, uint _n);
#if !SM_NO_CSTR
sm_ret_T sm_rcb_getncstr(sm_rcb_P _rcb, sm_cstr_P *_cstr, uint _n);
#endif

sm_ret_T sm_rcb_skip(sm_rcb_P _rcb, uint _n);

sm_ret_T sm_rcb_resize_data(sm_rcb_P _rcb, uint _len);

#if SM_STR_CHECK
uint	sm_rcb_getlen(sm_rcb_P _rcb);
uint	sm_rcb_getsize(sm_rcb_P _rcb);
int	sm_rcb_setmax(sm_rcb_P _rcb, uint _max);
uint	sm_rcb_getmax(sm_rcb_P _rcb);
uchar	sm_rcb_elem(sm_rcb_P _rcb, uint _i);
uint	sm_rcb_space(sm_rcb_P _rcb, uint _new_len);
#else /* SM_STR_CHECK */
# define sm_rcb_getrd(rcb)	((rcb)->sm_rcb_rw)
# define sm_rcb_getlen(rcb)	((rcb)->sm_rcb_len)
# define sm_rcb_getsize(rcb)	((rcb)->sm_rcb_size)
# define sm_rcb_setmax(rcb, m)	(rcb)->sm_rcb_max = (m)
# define sm_rcb_getmax(rcb)	(rcb)->sm_rcb_max
# define sm_rcb_elem(rcb, i)	((rcb)->sm_rcb_base[i])
# define sm_rcb_space(rcb, new_len)			\
	(((new_len) <= (rcb)->sm_rcb_size) ? (rcb)->sm_rcb_size	\
		: sm_rcb_resize_data((rcb), (new_len)))
#endif /* SM_STR_CHECK */

/* XXX Careful: filled externally, e.g., reuse RCB and fill buffer directly */
#define sm_rcb_setlen(rcb, len)	((rcb)->sm_rcb_len) = (len)

#define sm_rcb_data(rcb)	((rcb)->sm_rcb_base)

void	 sm_rcb_free(sm_rcb_P _rcb);

#define SM_RCB_FREE(ptr) do	{	\
		if ((ptr) != NULL) {	\
			sm_rcb_free(ptr);	\
			(ptr) = NULL;		\
		}				\
	} while (0)

#if SM_STR_CHECK
void		 sm_rcb_clr(sm_rcb_P _rcb);
# define SM_RCB_CLR(rcb) sm_rcb_clr(rcb)
#else
# define SM_RCB_CLR(rcb) do {	\
		(rcb)->sm_rcb_len = 0;	\
		(rcb)->sm_rcb_rw = 0;	\
	} while (0)
#endif /* SM_STR_CHECK */
# define sm_rcb_getinit(rcb)	(rcb)->sm_rcb_rw = 0

sm_ret_T sm_rcb_putinit(sm_rcb_P _rcb, int _n);

#if SM_RCB_ST
sm_ret_T sm_rcb_rcv(rcb_fd_T _fd, sm_rcb_P _rcb, uint _rs, st_utime_t _timeout);
sm_ret_T sm_rcb_snd(rcb_fd_T _fd, sm_rcb_P _rcb, st_utime_t _timeout);
#else
sm_ret_T sm_rcb_rcv(rcb_fd_T _fd, sm_rcb_P _rcb, uint _rs);
sm_ret_T sm_rcb_snd(rcb_fd_T _fd, sm_rcb_P _rcb);
#endif

sm_ret_T sm_rcb_open_rcv(sm_rcb_P _rcb);
sm_ret_T sm_rcb_open_dec(sm_rcb_P _rcb);
sm_ret_T sm_rcb_open_enc(sm_rcb_P _rcb, int _n);
sm_ret_T sm_rcb_open_snd(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_rcv(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_dec(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_enc(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_snd(sm_rcb_P _rcb);

sm_ret_T sm_rcb_open_rcvn(sm_rcb_P _rcb);
sm_ret_T sm_rcb_open_decn(sm_rcb_P _rcb);
sm_ret_T sm_rcb_open_encn(sm_rcb_P _rcb, int _n);
sm_ret_T sm_rcb_open_sndn(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_rcvn(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_decn(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_encn(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_sndn(sm_rcb_P _rcb);
sm_ret_T sm_rcb_close_n(sm_rcb_P _rcb);

#if SM_STR_CHECK
# define SM_RCB_NONE	0
# define SM_RCB_RCV	1
# define SM_RCB_DEC	2
# define SM_RCB_ENC	4
# define SM_RCB_SND	8
#endif /* SM_STR_CHECK */

#ifndef SM_MIN_RCB_SIZE
# define SM_MIN_RCB_SIZE	64
#endif
#ifndef SM_MIN_BUF_SIZE
# define SM_MIN_BUF_SIZE	SM_MIN_RCB_SIZE
#endif

#ifndef SM_RCB_MAX_LEN
# define SM_RCB_MAX_LEN		65536
#endif

#ifndef SM_STR_MAX_LEN
# define SM_STR_MAX_LEN		SM_RCB_MAX_LEN
#endif

#define SM_IS_RCB(rcb)	SM_REQUIRE_ISA((rcb), SM_RCB_MAGIC)

#endif /* SM_RCB_H */


syntax highlighted by Code2HTML, v. 0.9.1