blob: 225a248b72e2eeec22346fbca8f62a3f346c6835 [file] [log] [blame]
/*
* Copyright (C) 2003, 2004, 2005, 2011, 2014, 2015 Filip Pizlo. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY FILIP PIZLO ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FILIP PIZLO OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FP_TSF_INTERNAL_H
#define FP_TSF_INTERNAL_H
#include "tsf_internal_config.h"
#include "tsf.h"
#include <stdlib.h>
#include <stdarg.h>
#include <sys/time.h>
#include "tsf_inttypes.h"
/* define all of the structs that were left opaque in tsf.h. */
struct tsf_type_table {
tsf_named_type_t **elements;
uint32_t num_elements;
tsf_st_table *ele_table;
};
struct tsf_type_in_map {
void *region; /* NULL if not allocated in a region */
tsf_type_t **elements;
uint32_t num_elements;
uint32_t capacity;
};
struct tsf_ra_type_info {
uint32_t type_code;
uint64_t ref_count;
};
struct tsf_ra_tc_node {
uint32_t type_code;
tsf_ra_tc_node_t *next;
};
struct tsf_ra_type_man {
tsf_ra_tc_node_t *type_codes;
tsf_st_table *out_map;
tsf_st_table *in_map;
};
struct tsf_type {
tsf_type_kind_t kind_code;
/* true if this is an ANY or if is a container that contains an ANY. */
tsf_bool_t is_dynamic;
union {
/* additional data for array */
struct {
tsf_type_t *element_type;
} a;
/* additional data for struct */
struct {
/* struct mapping support - need to know the size of
* the struct in memory. this is NOT the sum of the
* sizes of the elements, because that doesn't take
* into account padding or the possibility of additional
* fields in that struct that the user isn't telling us
* about. HOWEVER! we can be sure that this size must
* be greater than or equal to the sum of the sizes of
* the elements. */
tsf_bool_t has_size;
size_t size;
void (*constructor)(void *);
void (*pre_destructor)(void *);
void (*destructor)(void *);
tsf_type_table_t *tt;
} s;
/* additional data for choice */
struct {
tsf_type_table_t *tt;
/* struct mapping support */
tsf_bool_t has_mapping;
tsf_bool_t in_place; /* use union? */
tsf_bool_t choice_as_full_word; /* use full 32-bit word for emitting the choice. */
size_t value_offset; /* offset to the value field */
size_t data_offset; /* offset to the union if in_place
is true, or to the pointer if
it is false. */
size_t size; /* size of the choice structure */
} h;
} u;
/* precomputed hash code. since each tsf_type object is immutable
* (that's why all functions that 'modify' a tsf_type actually take
* a pointer to a pointer to a tsf_type - so that instead of modifying
* the actual tsf_type, it allocates a new one and changes your
* pointer), the hash code can safely be precomputed when the
* tsf_type is created. */
int hash_code;
/* lazily computed type size in bytes. if it hasn't been computed yet,
* its value will be 0. */
volatile uint32_t byte_size;
/* holder for an optional comment supplied by the user. only
* commentable types can hold comments (use tsf_type_kind_is_commentable()
* to find out if it is commentable). the comment is a UTF-8 string
* supplied by the user via a function call (see tsf_type_set_comment())
* or by using javadoc comments in definitions passed to tsf_define. */
char *comment;
/* holder for an optional type name supplied by the user. only
* commentable types can have names (use tsf_type_kind_is_commentable()
* to find out if it is commentable). the name is a UTF-8 string
* supplied by the user via a function call (see tsf_type_set_name()).
* types defined using tsf_define automatically have names. */
char *name;
/* optional version number for a type. the default value is 0.
* this is actually an encoding of major.minor.patch, where major
* is a uint16_t, minor is a uint8_t, and patch is a uint8_t.
* this can only be changed for commentable types (use
* tsf_type_kind_is_commentable() to find out if it is commentable). */
uint32_t version;
/* only used for non-singletons */
tsf_atomic_count_t ref_count;
/* for memoization: points at the memo master. may be NULL, indicating
* that we haven't ever memoized this type. may point to self,
* indicating that this is the memo master. */
tsf_type_t *memo_master;
};
struct tsf_named_type {
char *name;
tsf_type_t *type;
uint32_t index;
/* for struct entries - struct entries may be marked optional. note
* that if we have structure A, B, and C, so that A does not have
* field F, B has an optional field F, and C has field F, then, assuming
* the structs are otherwise equal, the instanceof 'matrix' goes as
* follows:
*
* A B C
* A Y Y N
* B Y Y N
* C Y Y Y
*
* In other words, a structure with an optional F is not instanceof a
* structure with a mandatory F. */
tsf_bool_t optional;
/* struct mapping support - need to know the offset of this
* element within its parent struct.
*
* Note that this does not apply to choice types, where
* all elements have the same offset. */
tsf_bool_t has_offset;
size_t offset;
/* holder for an optional comment supplied by the user either through
* a function call or through tsf_define. */
char *comment;
};
struct tsf_buffer {
tsf_type_t *type;
tsf_type_in_map_t *types;
tsf_bool_t keep;
void *data;
uint32_t size;
tsf_atomic_count_t ref_count;
};
struct tsf_reflect {
tsf_type_t *type;
union {
/* container, used for both struct and array. note that it
* is used differently for struct and for array. */
struct {
tsf_reflect_t **array;
uint32_t size;
} c;
/* choice data. */
struct {
uint32_t choice; /* 'unknown' if equal to UINT32_MAX */
tsf_reflect_t *data;
} h;
/* string data. */
char *str;
/* primitives */
int8_t p_int8_t;
uint8_t p_uint8_t;
int16_t p_int16_t;
uint16_t p_uint16_t;
int32_t p_int32_t;
uint32_t p_uint32_t;
int64_t p_int64_t;
uint64_t p_uint64_t;
tsf_integer_t p_integer;
tsf_long_t p_long;
float p_float;
double p_double;
/* bit */
tsf_bool_t bit;
/* for the any type */
tsf_buffer_t *any;
} u;
};
struct tsf_genrtr {
tsf_type_t *type;
gpc_program_t *generator;
};
struct tsf_parser {
tsf_type_t *expected_type;
size_t expected_type_size;
tsf_st_table *parsers;
gpc_program_t *cached_program;
tsf_type_t *cached_type;
tsf_mutex_t lock;
};
struct tsf_copier {
gpc_program_t *copier;
};
struct tsf_destructor {
gpc_program_t *destructor;
};
typedef struct {
tsf_type_cback_t cback;
void *arg;
} tsf_serial_in_man_cback_t;
struct tsf_serial_in_man {
tsf_type_in_map_t *types;
tsf_serial_in_man_state_t state;
uint32_t types_byte_size;
tsf_serial_in_man_cback_t *cbacks;
uint32_t num_cbacks;
tsf_reader_t reader;
void *arg;
tsf_limits_t *limits;
};
struct tsf_serial_out_man {
tsf_type_out_map_t *types;
tsf_writer_t writer;
void *arg;
};
struct tsf_sha1_wtr {
tsf_SHA1Context ctx;
};
struct tsf_buf_rdr {
int fd;
tsf_bool_t keep_fd;
uint8_t *buf;
uint32_t size;
uint32_t puti;
uint32_t geti;
};
struct tsf_buf_wtr {
int fd;
tsf_bool_t keep_fd;
uint8_t *buf;
uint32_t size;
uint32_t pos;
};
struct tsf_zip_rdr {
tsf_zip_mode_t mode;
tsf_partial_reader_t reader;
void *reader_arg;
void *stream; /* can be either of type z_stream or bz_stream */
tsf_zip_abstract_t abstract;
tsf_bool_t decomp_eof; /* true if the decompression algorithm has
* reached EOF. */
uint8_t *buf;
uint32_t buf_size;
};
struct tsf_zip_wtr {
tsf_zip_mode_t mode;
tsf_writer_t writer;
void *writer_arg;
void *stream; /* can be either of type z_stream of bz_stream */
tsf_zip_abstract_t abstract;
uint8_t *buf;
uint32_t buf_size;
};
struct tsf_adpt_rdr {
tsf_zip_mode_t mode;
tsf_partial_reader_t reader;
void *reader_arg;
void *stream; /* can be either of type z_stream or bz_stream */
tsf_zip_abstract_t abstract;
tsf_bool_t expect_switch;
uint8_t *buf;
uint32_t puti,geti; /* same as in buffered reader */
uint32_t buf_size;
tsf_zip_rdr_attr_t attr;
uint32_t nozip_buf_size;
};
struct tsf_stream_file_input {
int fd;
tsf_bool_t keep_fd;
tsf_serial_in_man_t *in_man;
tsf_bool_t use_adpt;
union {
tsf_buf_rdr_t *buf;
tsf_adpt_rdr_t *adpt;
void *ptr;
} reader;
};
struct tsf_stream_file_output {
int fd;
tsf_bool_t keep_fd;
tsf_serial_out_man_t *out_man;
tsf_bool_t use_zip;
union {
tsf_buf_wtr_t *buf;
tsf_zip_wtr_t *zip;
void *ptr;
} writer;
tsf_bool_t all_good;
};
struct tsf_fsdb_connection {
int fd;
tsf_bool_t clear;
tsf_stream_file_input_t *in;
tsf_stream_file_output_t *out;
uint8_t *buf;
uint32_t buf_size;
uint32_t buf_cursor;
};
struct tsf_fsdb {
tsf_fsdb_kind_t kind;
union {
struct {
DIR *dirhandle;
const char *dirname;
tsf_bool_t update;
tsf_bool_t truncate;
uint64_t create_cnt;
} local;
struct {
#ifdef TSF_HAVE_BSDSOCKS
/* FIXME: open_remote() should attempt to connect just to see which
* address works. it should leave that connection open until the
* first put/get request. and it should leave enough info in here
* to make subsequent connection requests possible. */
#ifdef TSF_HAVE_GETADDRINFO
struct addrinfo *result;
struct addrinfo *cur;
#else
uint32_t addr;
int port;
#endif
tsf_fsdb_connection_t *connection;
#endif
} remote;
} u;
tsf_limits_t *limits;
tsf_zip_rdr_attr_t rdr_attr;
tsf_zip_wtr_attr_t wtr_attr;
tsf_mutex_t lock;
};
struct tsf_fsdb_response_s;
struct tsf_fsdb_in {
tsf_fsdb_t *db;
union {
struct {
tsf_buffer_t *key;
tsf_stream_file_input_t *in;
} local;
struct {
tsf_fsdb_connection_t *connection;
struct tsf_fsdb_response_s *rsp;
uint32_t rsp_cursor;
tsf_serial_in_man_t *in_man;
} remote;
} u;
};
struct tsf_fsdb_out {
tsf_fsdb_t *db;
union {
struct {
char *partname;
tsf_buffer_t *key;
tsf_stream_file_output_t *out;
} local;
struct {
tsf_fsdb_connection_t *connection;
tsf_serial_out_man_t *out_man;
} remote;
} u;
};
/* min and max */
#define tsf_min(a,b) ((a)<(b)?(a):(b))
#define tsf_max(a,b) ((a)>(b)?(a):(b))
/* timestamping */
#ifdef HAVE_GETTIMEOFDAY
static TSF_inline int64_t tsf_cur_time(void) {
int64_t result;
struct timeval tv;
gettimeofday(&tv,NULL);
result=tv.tv_sec;
result*=1000;
result*=1000;
result+=tv.tv_usec;
result*=1000;
return result;
}
#else
static TSF_inline int64_t tsf_cur_time(void) {
return ((int64_t)time(NULL))*(1000*1000*1000);
}
#endif
/* the full error setting command */
void tsf_set_error_fullv(tsf_error_t code,
int sys_errno,
int deadly_signal,
int zlib_error,
const char *zlib_msg,
const char *format,
va_list lst);
void tsf_set_error_full(tsf_error_t code,
int sys_errno,
int deadly_signal,
int zlib_error,
const char *zlib_msg,
const char *format,
...);
/* this is an strerror thingy for zlib. it will abort if called when
* no zlib support is compiled. */
const char *tsf_zlib_strerror(int code);
/* this is an strerror thingy for libbzip2. it will abort if called
* when no libbzip2 support is compiled. */
const char *tsf_libbzip2_strerror(int code);
/* this is just plain dumb. thanks a lot, GNU ppl. */
#if defined(HAVE_STPCPY) && !defined(stpcpy)
char *stpcpy(char *dest,const char *src);
#endif
/* tsf_sort just calls qsort if available. otherwise it is some shitty
* sorting algo that I implemented. */
void tsf_sort(void *base,size_t nmemb,size_t size,
int (*compar)(const void *a,const void *b));
/* sorts an array of uint32_t in ascending order. */
void tsf_ui32_sort(uint32_t *base,size_t nmemb);
/* string creation stuff. on error, both functions just set errno. */
char *tsf_vasprintf(const char *format,va_list lst);
char *tsf_asprintf(const char *format,...);
/* hashtable stuff */
tsf_st_table *tsf_st_init_typetable();
/* limits stuff */
/* max number of types in one stream */
#define tsf_limits_max_types(limits) \
((limits)==NULL?UINT32_MAX:(limits)->max_types)
/* maximum size in bytes of a serialized type */
#define tsf_limits_max_type_size(limits) \
((limits)==NULL?UINT32_MAX:(limits)->max_type_size)
/* maximum total size of all types read in a session */
#define tsf_limits_max_total_type_size(limits) \
((limits)==NULL?UINT32_MAX:(limits)->max_total_type_size)
/* maximum size in bytes of a buffer */
#define tsf_limits_max_buf_size(limits) \
((limits)==NULL?UINT32_MAX:(limits)->max_buf_size)
/* container depth limit */
#define tsf_limits_depth_limit(limits) \
((limits)==NULL?UINT32_MAX:(limits)->depth_limit)
/* comments */
#define tsf_limits_allow_comments(limits) \
((limits)==NULL?tsf_true:(limits)->allow_comments)
/* maximum array length */
#define tsf_limits_max_array_length(limits) \
((limits)==NULL?UINT32_MAX:(limits)->max_array_length)
/* maximum struct size, in number of elements */
#define tsf_limits_max_struct_size(limits) \
((limits)==NULL?UINT32_MAX:(limits)->max_struct_size)
/* maximum choice size, in number of elements */
#define tsf_limits_max_choice_size(limits) \
((limits)==NULL?UINT32_MAX:(limits)->max_choice_size)
/* maximum string size */
#define tsf_limits_max_string_size(limits) \
((limits)==NULL?UINT32_MAX:(limits)->max_string_size)
/* endianness stuff */
/* get ntohl, htonl, ntohs, htons */
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#else
#ifdef HAVE_LITTLE_ENDIAN
static inline uint32_t ntohl(uint32_t x) {
union {
uint32_t x;
uint8_t c[4];
} u;
u.x=x;
u.c[0]^=u.c[3]^=u.c[0]^=u.c[3];
u.c[1]^=u.c[2]^=u.c[1]^=u.c[2];
return u.x;
}
static inline uint16_t ntohs(uint16_t x) {
union {
uint16_t x;
uint8_t c[2];
} u;
u.x=x;
u.c[0]^=u.c[1]^=u.c[0]^=u.c[1];
return u.x;
}
#define htonl(x) (ntohl(x))
#define htons(x) (ntohs(x))
#else
#define ntohl(x) (x)
#define htonl(x) (x)
#define ntohs(x) (x)
#define htons(x) (x)
#endif
#endif
/* define stupid trivial stuff */
#define htonc(x) (x)
#define ntohc(x) (x)
#ifdef HAVE_BIG_ENDIAN
/* #undef NEED_INT_CONVERSION */
/* define long long equivalent of the arpa/inet functions */
#ifndef htonll
#define htonll(x) (x)
#endif
/* define misaligned copy equivalents of all of the arpa/inet functions */
static inline void copy_htonc(uint8_t *dst,
uint8_t *src) {
*dst=*src;
}
static inline void copy_htons(uint8_t *dst,
uint8_t *src) {
#ifdef CAN_DO_MISALIGNED_LDST
*((uint16_t*)dst)=*((uint16_t*)src);
#else
dst[0]=src[0];
dst[1]=src[1];
#endif
}
static inline void copy_htonl(uint8_t *dst,
uint8_t *src) {
#ifdef CAN_DO_MISALIGNED_LDST
uint32_t tmp=*((uint32_t*)src);
*((uint32_t*)dst)=tmp;
#else
dst[0]=src[0];
dst[1]=src[1];
dst[2]=src[2];
dst[3]=src[3];
#endif
}
static inline void copy_htonll(uint8_t *dst,
uint8_t *src) {
#ifdef CAN_DO_MISALIGNED_LDST
*((uint64_t*)dst)=*((uint64_t*)src);
#else
dst[0]=src[0];
dst[1]=src[1];
dst[2]=src[2];
dst[3]=src[3];
dst[4]=src[4];
dst[5]=src[5];
dst[6]=src[6];
dst[7]=src[7];
#endif
}
#define copy_ntohc(dst,src) copy_htonc(dst,src)
#define copy_ntohs(dst,src) copy_htons(dst,src)
#define copy_ntohl(dst,src) copy_htonl(dst,src)
#define copy_ntohll(dst,src) copy_htonll(dst,src)
#else
#define NEED_INT_CONVERSION
#ifndef htonll
/* define long long equivalent of the arpa/inet functions */
static inline uint64_t htonll(uint64_t x) {
/* probably not very efficient, but oh well. */
return ((x >> 56) & UINT64_C(0x00000000000000ff))
| ((x >> 40) & UINT64_C(0x000000000000ff00))
| ((x >> 24) & UINT64_C(0x0000000000ff0000))
| ((x >> 8) & UINT64_C(0x00000000ff000000))
| ((x << 8) & UINT64_C(0x000000ff00000000))
| ((x << 24) & UINT64_C(0x0000ff0000000000))
| ((x << 40) & UINT64_C(0x00ff000000000000))
| ((x << 56) & UINT64_C(0xff00000000000000));
}
#endif /* #ifndef htonll */
/* define misaligned copy equivalents of all of the arpa/inet functsions */
static inline void copy_htonc(uint8_t *dst,
uint8_t *src) {
*dst=*src;
}
static inline void copy_htons(uint8_t *dst,
uint8_t *src) {
dst[0]=src[1];
dst[1]=src[0];
}
static inline void copy_htonl(uint8_t *dst,
uint8_t *src) {
dst[0]=src[3];
dst[1]=src[2];
dst[2]=src[1];
dst[3]=src[0];
}
static inline void copy_htonll(uint8_t *dst,
uint8_t *src) {
dst[0]=src[7];
dst[1]=src[6];
dst[2]=src[5];
dst[3]=src[4];
dst[4]=src[3];
dst[5]=src[2];
dst[6]=src[1];
dst[7]=src[0];
}
#define copy_ntohc(dst,src) copy_htonc(dst,src)
#define copy_ntohs(dst,src) copy_htons(dst,src)
#define copy_ntohl(dst,src) copy_htonl(dst,src)
#define copy_ntohll(dst,src) copy_htonll(dst,src)
#endif
#ifndef ntohll
#define ntohll(x) (htonll(x))
#endif
/* floating point stuff */
#ifdef TSF_HAVE_IEEE_FLOAT
#ifdef NEED_INT_CONVERSION
#define NEED_FLOAT_CONVERSION
#endif
static inline float htonf(float x) {
uint32_t ret=htonl(*((long*)&x));
return *((float*)&ret);
}
static inline double htond(double x) {
uint64_t ret=htonll(*((uint64_t*)&x));
return *((double*)&ret);
}
#define ntohf(x) (htonf(x))
#define ntohd(x) (htond(x))
#if !defined(NEED_INT_CONVERSION) &&\
defined(CAN_DO_MISALIGNED_LDST) &&\
!defined(CAN_DO_FLOAT_MISALIGNED_LDST)
static inline void copy_htonf(uint8_t *dst,
uint8_t *src) {
dst[0]=src[0];
dst[1]=src[1];
dst[2]=src[2];
dst[3]=src[3];
}
static inline void copy_htond(uint8_t *dst,
uint8_t *src) {
dst[0]=src[0];
dst[1]=src[1];
dst[2]=src[2];
dst[3]=src[3];
dst[4]=src[4];
dst[5]=src[5];
dst[6]=src[6];
dst[7]=src[7];
}
#else
#define copy_htonf(dst,src) copy_htonl(dst,src)
#define copy_htond(dst,src) copy_htonll(dst,src)
#endif
#define copy_ntohf(dst,src) copy_htonf(dst,src)
#define copy_ntohd(dst,src) copy_htond(dst,src)
#else
#define NEED_FLOAT_CONVERSION
#error "Currently, we only support IEEE floats!"
#endif
#if defined(NEED_FLOAT_CONVERSION) || defined(NEED_INT_COVERSION)
#define NEED_CONVERSION
#endif
/* destination-incrementing misaligned copy macros. these do
* no bounds checking. */
#define copy_htonc_incdst(dst,src) do { \
copy_htonc(dst,src); \
(dst)=(void*)(((uint8_t*)(dst))+1); \
} while (0)
#define copy_ntohc_incdst(dst,src) do { \
copy_ntohc(dst,src); \
(dst)=(void*)(((uint8_t*)(dst))+1); \
} while (0)
#define copy_htons_incdst(dst,src) do { \
copy_htons(dst,src); \
(dst)=(void*)(((uint16_t*)(dst))+1); \
} while (0)
#define copy_ntohs_incdst(dst,src) do { \
copy_ntohs(dst,src); \
(dst)=(void*)(((uint16_t*)(dst))+1); \
} while (0)
#define copy_htonl_incdst(dst,src) do { \
copy_htonl(dst,src); \
(dst)=(void*)(((uint32_t*)(dst))+1); \
} while (0)
#define copy_ntohl_incdst(dst,src) do { \
copy_ntohl(dst,src); \
(dst)=(void*)(((uint32_t*)(dst))+1); \
} while (0)
#define copy_htonll_incdst(dst,src) do { \
copy_htonll(dst,src); \
(dst)=(void*)(((uint64_t*)(dst))+1); \
} while (0)
#define copy_ntohll_incdst(dst,src) do { \
copy_ntohll(dst,src); \
(dst)=(void*)(((uint64_t*)(dst))+1); \
} while (0)
#define copy_htonf_incdst(dst,src) do { \
copy_htonf(dst,src); \
(dst)=(void*)(((float*)(dst))+1); \
} while (0)
#define copy_ntohf_incdst(dst,src) do { \
copy_ntohf(dst,src); \
(dst)=(void*)(((float*)(dst))+1); \
} while (0)
#define copy_htond_incdst(dst,src) do { \
copy_htond(dst,src); \
(dst)=(void*)(((double*)(dst))+1); \
} while (0)
#define copy_ntohd_incdst(dst,src) do { \
copy_ntohd(dst,src); \
(dst)=(void*)(((double*)(dst))+1); \
} while (0)
/* source-incrementing misaligned copy macros. these do
* no bounds checking. */
#define copy_htonc_incsrc(dst,src) do { \
copy_htonc(dst,src); \
(src)=(void*)(((uint8_t*)(src))+1); \
} while (0)
#define copy_ntohc_incsrc(dst,src) do { \
copy_ntohc(dst,src); \
(src)=(void*)(((uint8_t*)(src))+1); \
} while (0)
#define copy_htons_incsrc(dst,src) do { \
copy_htons(dst,src); \
(src)=(void*)(((uint16_t*)(src))+1); \
} while (0)
#define copy_ntohs_incsrc(dst,src) do { \
copy_ntohs(dst,src); \
(src)=(void*)(((uint16_t*)(src))+1); \
} while (0)
#define copy_htonl_incsrc(dst,src) do { \
copy_htonl(dst,src); \
(src)=(void*)(((uint32_t*)(src))+1); \
} while (0)
#define copy_ntohl_incsrc(dst,src) do { \
copy_ntohl(dst,src); \
(src)=(void*)(((uint32_t*)(src))+1); \
} while (0)
#define copy_htonll_incsrc(dst,src) do { \
copy_htonll(dst,src); \
(src)=(void*)(((uint64_t*)(src))+1); \
} while (0)
#define copy_ntohll_incsrc(dst,src) do { \
copy_ntohll(dst,src); \
(src)=(void*)(((uint64_t*)(src))+1); \
} while (0)
#define copy_htonf_incsrc(dst,src) do { \
copy_htonf(dst,src); \
(src)=(void*)(((float*)(src))+1); \
} while (0)
#define copy_ntohf_incsrc(dst,src) do { \
copy_ntohf(dst,src); \
(src)=(void*)(((float*)(src))+1); \
} while (0)
#define copy_htond_incsrc(dst,src) do { \
copy_htond(dst,src); \
(src)=(void*)(((double*)(src))+1); \
} while (0)
#define copy_ntohd_incsrc(dst,src) do { \
copy_ntohd(dst,src); \
(src)=(void*)(((double*)(src))+1); \
} while (0)
/* source-incrementing misaligned copy macros. these do
* bounds checks. when a bounds check fails, they jump to
* the label you give them. */
#define copy_htonc_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<1) { \
goto label; \
} \
copy_htonc(dst,src); \
(src)=(void*)(((uint8_t*)(src))+1); \
} while (0)
#define copy_ntohc_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<1) { \
goto label; \
} \
copy_ntohc(dst,src); \
(src)=(void*)(((uint8_t*)(src))+1); \
} while (0)
#define copy_htons_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<2) { \
goto label; \
} \
copy_htons(dst,src); \
(src)=(void*)(((uint16_t*)(src))+1); \
} while (0)
#define copy_ntohs_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<2) { \
goto label; \
} \
copy_ntohs(dst,src); \
(src)=(void*)(((uint16_t*)(src))+1); \
} while (0)
#define copy_htonl_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<4) { \
goto label; \
} \
copy_htonl(dst,src); \
(src)=(void*)(((uint32_t*)(src))+1); \
} while (0)
#define copy_ntohl_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<4) { \
goto label; \
} \
copy_ntohl(dst,src); \
(src)=(void*)(((uint32_t*)(src))+1); \
} while (0)
#define copy_htonll_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<8) { \
goto label; \
} \
copy_htonll(dst,src); \
(src)=(void*)(((uint64_t*)(src))+1); \
} while (0)
#define copy_ntohll_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<8) { \
goto label; \
} \
copy_ntohll(dst,src); \
(src)=(void*)(((uint64_t*)(src))+1); \
} while (0)
#define copy_htonf_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<4) { \
goto label; \
} \
copy_htonf(dst,src); \
(src)=(void*)(((float*)(src))+1); \
} while (0)
#define copy_ntohf_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<4) { \
goto label; \
} \
copy_ntohf(dst,src); \
(src)=(void*)(((float*)(src))+1); \
} while (0)
#define copy_htond_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<8) { \
goto label; \
} \
copy_htond(dst,src); \
(src)=(void*)(((double*)(src))+1); \
} while (0)
#define copy_ntohd_incsrc_bc(dst,src,end,label) do { \
if (((uint8_t*)(end))-((uint8_t*)(src))<8) { \
goto label; \
} \
copy_ntohd(dst,src); \
(src)=(void*)(((double*)(src))+1); \
} while (0)
static inline size_t size_of_tsf_integer(tsf_integer_t src) {
if (src >= -TSF_INTEGER_SMALL_LIM && src < TSF_INTEGER_SMALL_LIM) {
return 1;
}
if (src >= -TSF_INTEGER_MEDIUM_LIM && src < TSF_INTEGER_MEDIUM_LIM) {
return 2;
}
if (src >= -TSF_INTEGER_LARGE_LIM && src < TSF_INTEGER_LARGE_LIM) {
return 4;
}
return 5;
}
static inline size_t size_of_tsf_unsigned(tsf_unsigned_t src) {
if (src < TSF_UNSIGNED_SMALL_LIM) {
return 1;
}
if (src < TSF_UNSIGNED_MEDIUM_LIM) {
return 2;
}
if (src < TSF_UNSIGNED_LARGE_LIM) {
return 4;
}
return 5;
}
static inline size_t size_of_tsf_long(tsf_long_t src) {
if (src >= -TSF_INTEGER_SMALL_LIM && src < TSF_INTEGER_SMALL_LIM) {
return 1;
}
if (src >= -TSF_INTEGER_MEDIUM_LIM && src < TSF_INTEGER_MEDIUM_LIM) {
return 2;
}
if (src >= -TSF_INTEGER_LARGE_LIM && src < TSF_INTEGER_LARGE_LIM) {
return 4;
}
return 9;
}
static inline size_t write_tsf_integer(uint8_t *dst, tsf_integer_t src) {
if (src >= -TSF_INTEGER_SMALL_LIM && src < TSF_INTEGER_SMALL_LIM) {
dst[0] = ((uint8_t)(int8_t)src) & ~TSF_INTEGER_MEDIUM_BIT;
return 1;
}
/* FIXME: The remainder of this function could be an out-of-line slow path. */
if (src >= -TSF_INTEGER_MEDIUM_LIM && src < TSF_INTEGER_MEDIUM_LIM) {
if (src < 0) {
src += TSF_INTEGER_SMALL_LIM;
} else {
src -= TSF_INTEGER_SMALL_LIM;
}
dst[0] =
(((int8_t)((src >> 8) & 255)) - TSF_INTEGER_MEDIUM_DIFF) |
TSF_INTEGER_MEDIUM_BIT;
dst[1] = src & 255;
return 2;
}
if (src >= -TSF_INTEGER_LARGE_LIM && src < TSF_INTEGER_LARGE_LIM) {
if (src < 0) {
src += TSF_INTEGER_MEDIUM_LIM;
} else {
src -= TSF_INTEGER_MEDIUM_LIM;
}
dst[0] = TSF_INTEGER_LARGE_TAG;
dst[1] = (src >> 16) & 255;
dst[2] = (src >> 8) & 255;
dst[3] = src & 255;
return 4;
}
dst[0] = TSF_INTEGER_HUGE_TAG;
dst[1] = (src >> 24) & 255;
dst[2] = (src >> 16) & 255;
dst[3] = (src >> 8) & 255;
dst[4] = src & 255;
return 5;
}
static inline size_t write_tsf_unsigned(uint8_t *dst, tsf_unsigned_t src) {
if (src < TSF_UNSIGNED_SMALL_LIM) {
dst[0] = src;
return 1;
}
/* FIXME: The remainder of this function could be an out-of-line slow path. */
if (src < TSF_UNSIGNED_MEDIUM_LIM) {
src -= TSF_UNSIGNED_SMALL_LIM;
dst[0] = ((src >> 8) & 255) | TSF_UNSIGNED_MEDIUM_BIT;
dst[1] = src & 255;
return 2;
}
if (src < TSF_UNSIGNED_LARGE_LIM) {
src -= TSF_UNSIGNED_MEDIUM_LIM;
dst[0] = TSF_UNSIGNED_LARGE_TAG;
dst[1] = (src >> 16) & 255;
dst[2] = (src >> 8) & 255;
dst[3] = src & 255;
return 4;
}
dst[0] = TSF_UNSIGNED_HUGE_TAG;
dst[1] = (src >> 24) & 255;
dst[2] = (src >> 16) & 255;
dst[3] = (src >> 8) & 255;
dst[4] = src & 255;
return 5;
}
static inline size_t write_tsf_long(uint8_t *dst, tsf_long_t src) {
if (src >= -TSF_INTEGER_SMALL_LIM && src < TSF_INTEGER_SMALL_LIM) {
dst[0] = ((uint8_t)(int8_t)src) & ~TSF_INTEGER_MEDIUM_BIT;
return 1;
}
/* FIXME: The remainder of this function could be an out-of-line slow path. */
if (src >= -TSF_INTEGER_MEDIUM_LIM && src < TSF_INTEGER_MEDIUM_LIM) {
if (src < 0) {
src += TSF_INTEGER_SMALL_LIM;
} else {
src -= TSF_INTEGER_SMALL_LIM;
}
dst[0] =
(((int8_t)((src >> 8) & 255)) - TSF_INTEGER_MEDIUM_DIFF) |
TSF_INTEGER_MEDIUM_BIT;
dst[1] = src & 255;
return 2;
}
if (src >= -TSF_INTEGER_LARGE_LIM && src < TSF_INTEGER_LARGE_LIM) {
if (src < 0) {
src += TSF_INTEGER_MEDIUM_LIM;
} else {
src -= TSF_INTEGER_MEDIUM_LIM;
}
dst[0] = TSF_INTEGER_LARGE_TAG;
dst[1] = (src >> 16) & 255;
dst[2] = (src >> 8) & 255;
dst[3] = src & 255;
return 4;
}
dst[0] = TSF_INTEGER_HUGE_TAG;
dst[1] = (src >> 56) & 255;
dst[2] = (src >> 48) & 255;
dst[3] = (src >> 40) & 255;
dst[4] = (src >> 32) & 255;
dst[5] = (src >> 24) & 255;
dst[6] = (src >> 16) & 255;
dst[7] = (src >> 8) & 255;
dst[8] = src & 255;
return 9;
}
static inline size_t size_of_encoded_tsf_integer(int8_t value) {
if (!(value & TSF_INTEGER_MEDIUM_BIT)) {
return 1;
}
switch (value) {
case TSF_INTEGER_LARGE_TAG:
return 4;
case TSF_INTEGER_HUGE_TAG:
return 5;
default:
return 2;
}
}
static inline size_t size_of_encoded_tsf_unsigned(uint8_t value) {
if (!(value & TSF_UNSIGNED_MEDIUM_BIT)) {
return 1;
}
switch (value) {
case TSF_UNSIGNED_LARGE_TAG:
return 4;
case TSF_UNSIGNED_HUGE_TAG:
return 5;
default:
return 2;
}
}
static inline size_t size_of_encoded_tsf_long(int8_t value) {
if (!(value & TSF_INTEGER_MEDIUM_BIT)) {
return 1;
}
switch (value) {
case TSF_INTEGER_LARGE_TAG:
return 4;
case TSF_INTEGER_HUGE_TAG:
return 9;
default:
return 2;
}
}
static inline size_t read_tsf_integer(tsf_integer_t *dst, uint8_t *src, size_t src_remaining) {
if (!src_remaining)
return 0;
int8_t head_value = src[0];
if (!(head_value & TSF_INTEGER_MEDIUM_BIT)) {
*dst = ((int8_t)(head_value << 1)) >> 1;
return 1;
}
/* FIXME: The remainder of this function could be an out-of-line slow path. */
switch (head_value) {
case TSF_INTEGER_LARGE_TAG: {
if (src_remaining < 4)
return 0;
int32_t value =
(((int32_t)(int8_t)src[1]) << 16) |
(((int32_t)(uint32_t)src[2]) << 8) |
((int32_t)(uint32_t)src[3]);
if (value < 0)
value -= TSF_INTEGER_MEDIUM_LIM;
else
value += TSF_INTEGER_MEDIUM_LIM;
*dst = value;
return 4;
}
case TSF_INTEGER_HUGE_TAG: {
if (src_remaining < 5)
return 0;
int32_t value =
(((int32_t)(int8_t)src[1]) << 24) |
(((int32_t)(uint32_t)src[2]) << 16) |
(((int32_t)(uint32_t)src[3]) << 8) |
((int32_t)(uint32_t)src[4]);
*dst = value;
return 5;
}
default: {
if (src_remaining < 2)
return 0;
int32_t value =
((int32_t)(uint32_t)src[1]) |
(((int32_t)((((int8_t)(head_value << 1)) >> 1) + TSF_INTEGER_MEDIUM_DIFF)) << 8);
if (value < 0)
value -= TSF_INTEGER_SMALL_LIM;
else
value += TSF_INTEGER_SMALL_LIM;
*dst = value;
return 2;
} }
}
static inline size_t read_tsf_unsigned(tsf_unsigned_t *dst, uint8_t *src, size_t src_remaining) {
if (!src_remaining)
return 0;
uint8_t head_value = src[0];
if (!(head_value & TSF_UNSIGNED_MEDIUM_BIT)) {
*dst = head_value;
return 1;
}
/* FIXME: The remainder of this function could be an out-of-line slow path. */
switch (head_value) {
case TSF_UNSIGNED_LARGE_TAG: {
if (src_remaining < 4)
return 0;
int32_t value =
(((int32_t)(int8_t)src[1]) << 16) |
(((int32_t)(uint32_t)src[2]) << 8) |
((int32_t)(uint32_t)src[3]);
value += TSF_UNSIGNED_MEDIUM_LIM;
*dst = value;
return 4;
}
case TSF_UNSIGNED_HUGE_TAG: {
if (src_remaining < 5)
return 0;
int32_t value =
(((int32_t)(int8_t)src[1]) << 24) |
(((int32_t)(uint32_t)src[2]) << 16) |
(((int32_t)(uint32_t)src[3]) << 8) |
((int32_t)(uint32_t)src[4]);
*dst = value;
return 5;
}
default: {
if (src_remaining < 2)
return 0;
int32_t value =
((int32_t)(uint32_t)src[1]) |
((head_value & ~TSF_UNSIGNED_MEDIUM_BIT) << 8);
value += TSF_UNSIGNED_SMALL_LIM;
*dst = value;
return 2;
} }
}
static inline size_t read_tsf_long(tsf_long_t *dst, uint8_t *src, size_t src_remaining) {
if (!src_remaining)
return 0;
int8_t head_value = src[0];
if (!(head_value & TSF_INTEGER_MEDIUM_BIT)) {
*dst = ((int8_t)(head_value << 1)) >> 1;
return 1;
}
/* FIXME: The remainder of this function could be an out-of-line slow path. */
switch (head_value) {
case TSF_INTEGER_LARGE_TAG: {
if (src_remaining < 4)
return 0;
int64_t value =
(((int64_t)(int8_t)src[1]) << 16) |
(((int64_t)(uint64_t)src[2]) << 8) |
((int64_t)(uint64_t)src[3]);
if (value < 0)
value -= TSF_INTEGER_MEDIUM_LIM;
else
value += TSF_INTEGER_MEDIUM_LIM;
*dst = value;
return 4;
}
case TSF_INTEGER_HUGE_TAG: {
if (src_remaining < 9)
return 0;
int64_t value =
(((int64_t)(int8_t)src[1]) << 56) |
(((int64_t)(uint64_t)src[2]) << 48) |
(((int64_t)(uint64_t)src[3]) << 40) |
(((int64_t)(uint64_t)src[4]) << 32) |
(((int64_t)(uint64_t)src[5]) << 24) |
(((int64_t)(uint64_t)src[6]) << 16) |
(((int64_t)(uint64_t)src[7]) << 8) |
((int64_t)(uint64_t)src[8]);
*dst = value;
return 9;
}
default: {
if (src_remaining < 2)
return 0;
int64_t value =
((int64_t)(uint64_t)src[1]) |
(((int64_t)((((int8_t)(head_value << 1)) >> 1) + TSF_INTEGER_MEDIUM_DIFF)) << 8);
if (value < 0)
value -= TSF_INTEGER_SMALL_LIM;
else
value += TSF_INTEGER_SMALL_LIM;
*dst = value;
return 2;
} }
}
#define read_tsf_integer_incsrc(dst, src, end, bounds_error) do { \
size_t total_bytes_read = \
read_tsf_integer((dst), (src), (end) - (src)); \
if (!total_bytes_read) { \
goto bounds_error; \
} \
\
(src) += total_bytes_read; \
} while (0)
#define read_tsf_unsigned_incsrc(dst, src, end, bounds_error) do { \
size_t total_bytes_read = \
read_tsf_unsigned((dst), (src), (end) - (src)); \
if (!total_bytes_read) { \
goto bounds_error; \
} \
\
(src) += total_bytes_read; \
} while (0)
#define read_tsf_long_incsrc(dst, src, end, bounds_error) do { \
size_t total_bytes_read = \
read_tsf_long((dst), (src), (end) - (src)); \
if (!total_bytes_read) { \
goto bounds_error; \
} \
\
(src) += total_bytes_read; \
} while (0)
static inline size_t skip_string(const char *start, const char *end) {
const char *cur = start;
for (;;) {
if (cur >= end)
return 0;
if (!*cur)
return cur + 1 - start;
cur++;
}
}
/* internal recursive function for reading types */
tsf_type_t *tsf_type_read_rec(tsf_reader_t reader,
void *arg,
tsf_limits_t *limits,
uint32_t depth);
/* read a type table */
tsf_type_table_t* tsf_type_table_read(const char *name,
tsf_reader_t reader,
void *arg,
tsf_limits_t *limits,
uint32_t size_limit,
uint32_t depth);
/* clones a type, returning a new one just like it. note this is
* actually deep copy. */
tsf_type_t* tsf_type_clone(tsf_type_t *type);
/* gives you a version of the given type that you own; i.e. if you make
* changes to it in-place then nobody else will notice. this is a O(1)
* operation that returns the passed-in type object if it already has a
* reference count of 1. otherwise the type is copied using
* tsf_type_clone(). */
tsf_type_t* tsf_type_own_begin(tsf_type_t *type);
/* commits to an ownership operation by relinquishing our reference to
* the original type. */
void tsf_type_own_commit(tsf_type_t **dst, tsf_type_t *ret);
/* undoes an ownership operation by deleting the clone if necessary. */
void tsf_type_own_abort(tsf_type_t *dst, tsf_type_t *ret);
/* recompute the hash code */
void tsf_type_recompute_hash(tsf_type_t *type);
/* create a tsf_buffer in which the caller owns the tsf_buffer object itself
and the original backing store. this can be used to read stack-allocated
buffers. this must be destroyed with tsf_buffer_destroy_custom(). few
functions work on the buffer that this returns. the tsf_buffer_read_simple
and tsf_buffer_read_small_with_type_code functions are two functions that
do work with custom buffers.
note that this really needs to be internal API, since it requires that the
caller knows exactly the sizeof(tsf_buffer_t). if we wanted an external
vesion of this API, we'd have the user just pass in a backing store and we'd
partition it into a tsf_buffer_t and the actual backing store. we'd also
kindly report error if the buffer wasn't big enough for a tsf_buffer_t. */
void tsf_buffer_initialize_custom(tsf_buffer_t *buf,
void *backing_store,
size_t backing_store_size);
/* destroy a tsf_buffer created with tsf_buffer_initialize_custom(). */
void tsf_buffer_destroy_custom(tsf_buffer_t *buf);
/* create a tsf_buffer that is ready for use with tsf_buffer_read_simple,
tsf_buffer_read_small_with_type_code, and the GPC generator. */
tsf_buffer_t *tsf_buffer_create_bare(void);
/* create a tsf_buffer that is ready for use with GPC generator with a non-NULL
* region. */
tsf_buffer_t *tsf_buffer_create_bare_in(void* region);
/* destroy a tsf_buffer that was created with tsf_buffer_create_bare()
but didn't yet have anything else done to it. */
void tsf_buffer_destroy_bare(tsf_buffer_t *buf);
/* read/write a buffer using the old buffer framing format, which is still
* appropriate for large buffers. */
tsf_bool_t tsf_buffer_read_simple(tsf_buffer_t *buf,
tsf_type_in_map_t *enclosing_types,
tsf_reader_t reader,
void *arg,
tsf_limits_t *limits);
tsf_bool_t tsf_buffer_write_simple(tsf_buffer_t *buf,
uint32_t type_code,
tsf_type_out_map_t *type_map,
tsf_writer_t writer,
void *arg);
/* read/write a small buffer using the new framing format, which only works
* for small buffers. */
tsf_bool_t tsf_buffer_read_small_with_type_code(tsf_buffer_t *buf,
uint32_t type_code,
tsf_type_in_map_t *enclosing_types,
tsf_reader_t reader,
void *arg,
tsf_limits_t *limits);
tsf_bool_t tsf_buffer_write_small_with_type_code(tsf_buffer_t *buf,
tsf_type_out_map_t *type_map,
tsf_writer_t writer,
void *arg);
/* read into an already-created buffer. the buffer should have been created
using either tsf_buffer_initialize_custom() or tsf_buffer_create_bare() */
tsf_bool_t tsf_serial_in_man_read_existing_buffer(tsf_serial_in_man_t *in_man,
tsf_buffer_t *buf);
/* read a buffer from a file that was openned for reading using an already-created
buffer. */
tsf_bool_t tsf_stream_file_input_read_existing_buffer(tsf_stream_file_input_t *file,
tsf_buffer_t *buf);
/* generate into an existing buffer created usign tsf_buffer_initialize_custom(). */
tsf_bool_t tsf_generator_generate_existing_buffer(tsf_genrtr_t *gen,
void *data,
tsf_buffer_t *buf);
/* write a type according to the serial protocol */
tsf_bool_t tsf_serial_out_man_write_type(tsf_writer_t writer,
void *arg,
tsf_type_t *type);
/* verify that the data is valid. basically just does NULL checks. */
tsf_bool_t tsf_reflect_verify(tsf_reflect_t *data);
/* generate a gpint prototype for a generator. a generator takes
* the following arguments on the stack: a pointer to a tsf_type_t,
* and a pointer to the user structure. the generator returns a
* pointer to a tsf_buffer_t, or 0 if an error occurred. */
gpc_proto_t *tsf_gpc_code_gen_generate_generator(tsf_type_t *type);
/* generate a gpint prototype for a parser. a parser takes the
* following arguments on the stack: a pointer to a tsf_buffer_t.
* it returns a pointer to a user structure that is also a region. */
gpc_proto_t *tsf_gpc_code_gen_generate_parser(tsf_type_t *dest_type,
tsf_type_t *src_type);
/* generate a gpint prototype for a converter. a converter takes
* the following arguments on the stack: a pointer to the destination,
* which may be NULL indicating that the destination should be
* allocated, and a pointer to the source. the region register
* may be NULL only if the destination is NULL; if the region
* is NULL it means that a new region should be allocated. a
* converter returns the destination. */
gpc_proto_t *tsf_gpc_code_gen_generate_converter(tsf_type_t *dest_type,
tsf_type_t *src_type);
/* generate a gpint prototype for a destroyer. a destroyer takes the
* following arguments on the stack: a pointer to the user structure.
* it returns 0. */
gpc_proto_t *tsf_gpc_code_gen_generate_destroyer(tsf_type_t *type);
/* internal FSDB put function. just gives you a file descriptor
* for writing to the file and the file name. */
tsf_bool_t tsf_fsdb_guts_put(tsf_fsdb_t *fsdb,
tsf_buffer_t *key,
int *fd,
char **partflnm);
/* internal FSDB commit function. */
tsf_bool_t tsf_fsdb_guts_commit(tsf_fsdb_t *fsdb,
char *partflnm,
tsf_buffer_t *key,
char **dataflnm);
/* internal FSDB abort function. */
tsf_bool_t tsf_fsdb_guts_abort(tsf_fsdb_t *fsdb,
char *partflnm);
/* internal FSDB get function. */
tsf_bool_t tsf_fsdb_guts_get(tsf_fsdb_t *fsdb,
tsf_buffer_t *key,
int *fd,
char **dataflnm);
/* internal FSDB rm function. */
tsf_bool_t tsf_fsdb_guts_rm(tsf_fsdb_t *fsdb,
tsf_buffer_t *key,
char **dataflnm);
/* abort because we screwed up big time */
#define tsf_abort(msg) do { \
fprintf(stderr,"tsf_abort(\"%s\"): called at %s:%d\n", \
msg,__FILE__,__LINE__); \
abort(); \
} while (0)
/* function version of abort */
void tsf_f_abort(const char *msg);
/* make an assertion that, if it fails, causes us to abort. we don't
* support the notion of optional assertions; they are always enabled. */
#define tsf_assert(exp) do { \
if (!(exp)) { \
fprintf(stderr,"tsf_assert(%s): failed at %s:%d\n", \
#exp,__FILE__,__LINE__); \
abort(); \
} \
} while (0)
#endif