mirror of
https://github.com/OpenVPN/openvpn.git
synced 2024-11-27 19:53:51 +08:00
eca86913db
git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2995 e7ae566f-a301-0410-adde-c780ea21d3b5
763 lines
18 KiB
C
763 lines
18 KiB
C
/*
|
|
* OpenVPN -- An application to securely tunnel IP networks
|
|
* over a single UDP port, with support for SSL/TLS-based
|
|
* session authentication and key exchange,
|
|
* packet encryption, packet authentication, and
|
|
* packet compression.
|
|
*
|
|
* Copyright (C) 2002-2008 OpenVPN Solutions LLC <info@openvpn.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program (see the file COPYING included with this
|
|
* distribution); if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifndef BUFFER_H
|
|
#define BUFFER_H
|
|
|
|
#include "basic.h"
|
|
#include "thread.h"
|
|
|
|
/*
|
|
* Define verify_align function, otherwise
|
|
* it will be a noop.
|
|
*/
|
|
/* #define VERIFY_ALIGNMENT */
|
|
|
|
/*
|
|
* Keep track of source file/line of buf_init calls
|
|
*/
|
|
#ifdef VERIFY_ALIGNMENT
|
|
#define BUF_INIT_TRACKING
|
|
#endif
|
|
|
|
/* basic buffer class for OpenVPN */
|
|
|
|
struct buffer
|
|
{
|
|
int capacity; /* size of buffer allocated by malloc */
|
|
int offset; /* data starts at data + offset, offset > 0 to allow for efficient prepending */
|
|
int len; /* length of data that starts at data + offset */
|
|
uint8_t *data;
|
|
|
|
#ifdef BUF_INIT_TRACKING
|
|
const char *debug_file;
|
|
int debug_line;
|
|
#endif
|
|
};
|
|
|
|
/* for garbage collection */
|
|
|
|
struct gc_entry
|
|
{
|
|
struct gc_entry *next;
|
|
};
|
|
|
|
struct gc_arena
|
|
{
|
|
struct gc_entry *list;
|
|
};
|
|
|
|
#define BPTR(buf) ((buf)->data + (buf)->offset)
|
|
#define BEND(buf) (BPTR(buf) + (buf)->len)
|
|
#define BLAST(buf) (((buf)->data && (buf)->len) ? (BPTR(buf) + (buf)->len - 1) : NULL)
|
|
#define BLEN(buf) ((buf)->len)
|
|
#define BDEF(buf) ((buf)->data != NULL)
|
|
#define BSTR(buf) ((char *)BPTR(buf))
|
|
#define BCAP(buf) (buf_forward_capacity (buf))
|
|
|
|
void buf_clear (struct buffer *buf);
|
|
|
|
struct buffer clear_buf (void);
|
|
void free_buf (struct buffer *buf);
|
|
|
|
bool buf_assign (struct buffer *dest, const struct buffer *src);
|
|
|
|
void string_clear (char *str);
|
|
int string_array_len (const char **array);
|
|
|
|
#define PA_BRACKET (1<<0)
|
|
char *print_argv (const char **p, struct gc_arena *gc, const unsigned int flags);
|
|
|
|
/* for dmalloc debugging */
|
|
|
|
#ifdef DMALLOC
|
|
|
|
#define alloc_buf(size) alloc_buf_debug (size, __FILE__, __LINE__)
|
|
#define alloc_buf_gc(size, gc) alloc_buf_gc_debug (size, gc, __FILE__, __LINE__);
|
|
#define clone_buf(buf) clone_buf_debug (buf, __FILE__, __LINE__);
|
|
#define gc_malloc(size, clear, arena) gc_malloc_debug (size, clear, arena, __FILE__, __LINE__)
|
|
#define string_alloc(str, gc) string_alloc_debug (str, gc, __FILE__, __LINE__)
|
|
#define string_alloc_buf(str, gc) string_alloc_buf_debug (str, gc, __FILE__, __LINE__)
|
|
|
|
struct buffer alloc_buf_debug (size_t size, const char *file, int line);
|
|
struct buffer alloc_buf_gc_debug (size_t size, struct gc_arena *gc, const char *file, int line);
|
|
struct buffer clone_buf_debug (const struct buffer* buf, const char *file, int line);
|
|
void *gc_malloc_debug (size_t size, bool clear, struct gc_arena *a, const char *file, int line);
|
|
char *string_alloc_debug (const char *str, struct gc_arena *gc, const char *file, int line);
|
|
struct buffer string_alloc_buf_debug (const char *str, struct gc_arena *gc, const char *file, int line);
|
|
|
|
#else
|
|
|
|
struct buffer alloc_buf (size_t size);
|
|
struct buffer alloc_buf_gc (size_t size, struct gc_arena *gc); /* allocate buffer with garbage collection */
|
|
struct buffer clone_buf (const struct buffer* buf);
|
|
void *gc_malloc (size_t size, bool clear, struct gc_arena *a);
|
|
char *string_alloc (const char *str, struct gc_arena *gc);
|
|
struct buffer string_alloc_buf (const char *str, struct gc_arena *gc);
|
|
|
|
#endif
|
|
|
|
#ifdef BUF_INIT_TRACKING
|
|
#define buf_init(buf, offset) buf_init_debug (buf, offset, __FILE__, __LINE__)
|
|
bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line);
|
|
#else
|
|
#define buf_init(buf, offset) buf_init_dowork (buf, offset)
|
|
#endif
|
|
|
|
|
|
/* inline functions */
|
|
|
|
static inline void
|
|
buf_reset (struct buffer *buf)
|
|
{
|
|
buf->capacity = 0;
|
|
buf->offset = 0;
|
|
buf->len = 0;
|
|
buf->data = NULL;
|
|
}
|
|
|
|
static inline void
|
|
buf_reset_len (struct buffer *buf)
|
|
{
|
|
buf->len = 0;
|
|
buf->offset = 0;
|
|
}
|
|
|
|
static inline bool
|
|
buf_init_dowork (struct buffer *buf, int offset)
|
|
{
|
|
if (offset < 0 || offset > buf->capacity || buf->data == NULL)
|
|
return false;
|
|
buf->len = 0;
|
|
buf->offset = offset;
|
|
return true;
|
|
}
|
|
|
|
static inline bool
|
|
buf_defined (struct buffer *buf)
|
|
{
|
|
return buf->data != NULL;
|
|
}
|
|
|
|
static inline void
|
|
buf_set_write (struct buffer *buf, uint8_t *data, int size)
|
|
{
|
|
buf->len = 0;
|
|
buf->offset = 0;
|
|
buf->capacity = size;
|
|
buf->data = data;
|
|
if (size > 0 && data)
|
|
*data = 0;
|
|
}
|
|
|
|
static inline void
|
|
buf_set_read (struct buffer *buf, const uint8_t *data, int size)
|
|
{
|
|
buf->len = buf->capacity = size;
|
|
buf->offset = 0;
|
|
buf->data = (uint8_t *)data;
|
|
}
|
|
|
|
/* Like strncpy but makes sure dest is always null terminated */
|
|
static inline void
|
|
strncpynt (char *dest, const char *src, size_t maxlen)
|
|
{
|
|
strncpy (dest, src, maxlen);
|
|
if (maxlen > 0)
|
|
dest[maxlen - 1] = 0;
|
|
}
|
|
|
|
/* return true if string contains at least one numerical digit */
|
|
static inline bool
|
|
has_digit (const unsigned char* src)
|
|
{
|
|
unsigned char c;
|
|
while ((c = *src++))
|
|
{
|
|
if (isdigit(c))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* printf append to a buffer with overflow check
|
|
*/
|
|
void buf_printf (struct buffer *buf, const char *format, ...)
|
|
#ifdef __GNUC__
|
|
__attribute__ ((format (printf, 2, 3)))
|
|
#endif
|
|
;
|
|
|
|
/*
|
|
* Like snprintf but guarantees null termination for size > 0
|
|
*/
|
|
int openvpn_snprintf(char *str, size_t size, const char *format, ...)
|
|
#ifdef __GNUC__
|
|
__attribute__ ((format (printf, 3, 4)))
|
|
#endif
|
|
;
|
|
|
|
/*
|
|
* remove/add trailing characters
|
|
*/
|
|
|
|
void buf_null_terminate (struct buffer *buf);
|
|
void buf_chomp (struct buffer *buf);
|
|
void buf_rmtail (struct buffer *buf, uint8_t remove);
|
|
|
|
/*
|
|
* non-buffer string functions
|
|
*/
|
|
void chomp (char *str);
|
|
void rm_trailing_chars (char *str, const char *what_to_delete);
|
|
const char *skip_leading_whitespace (const char *str);
|
|
void string_null_terminate (char *str, int len, int capacity);
|
|
|
|
/*
|
|
* Write string in buf to file descriptor fd.
|
|
* NOTE: requires that string be null terminated.
|
|
*/
|
|
void buf_write_string_file (const struct buffer *buf, const char *filename, int fd);
|
|
|
|
/*
|
|
* write a string to the end of a buffer that was
|
|
* truncated by buf_printf
|
|
*/
|
|
void buf_catrunc (struct buffer *buf, const char *str);
|
|
|
|
/*
|
|
* convert a multi-line output to one line
|
|
*/
|
|
void convert_to_one_line (struct buffer *buf);
|
|
|
|
/*
|
|
* Parse a string based on a given delimiter char
|
|
*/
|
|
bool buf_parse (struct buffer *buf, const int delim, char *line, const int size);
|
|
|
|
/*
|
|
* Hex dump -- Output a binary buffer to a hex string and return it.
|
|
*/
|
|
char *
|
|
format_hex_ex (const uint8_t *data, int size, int maxoutput,
|
|
int space_break, const char* separator,
|
|
struct gc_arena *gc);
|
|
|
|
static inline char *
|
|
format_hex (const uint8_t *data, int size, int maxoutput, struct gc_arena *gc)
|
|
{
|
|
return format_hex_ex (data, size, maxoutput, 4, " ", gc);
|
|
}
|
|
|
|
/*
|
|
* Return a buffer that is a subset of another buffer.
|
|
*/
|
|
struct buffer buf_sub (struct buffer *buf, int size, bool prepend);
|
|
|
|
/*
|
|
* Check if sufficient space to append to buffer.
|
|
*/
|
|
|
|
static inline bool
|
|
buf_safe (const struct buffer *buf, int len)
|
|
{
|
|
return len >= 0 && buf->offset + buf->len + len <= buf->capacity;
|
|
}
|
|
|
|
static inline bool
|
|
buf_safe_bidir (const struct buffer *buf, int len)
|
|
{
|
|
const int newlen = buf->len + len;
|
|
return newlen >= 0 && buf->offset + newlen <= buf->capacity;
|
|
}
|
|
|
|
static inline int
|
|
buf_forward_capacity (const struct buffer *buf)
|
|
{
|
|
int ret = buf->capacity - (buf->offset + buf->len);
|
|
if (ret < 0)
|
|
ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
buf_forward_capacity_total (const struct buffer *buf)
|
|
{
|
|
int ret = buf->capacity - buf->offset;
|
|
if (ret < 0)
|
|
ret = 0;
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
buf_reverse_capacity (const struct buffer *buf)
|
|
{
|
|
return buf->offset;
|
|
}
|
|
|
|
static inline bool
|
|
buf_inc_len (struct buffer *buf, int inc)
|
|
{
|
|
if (!buf_safe_bidir (buf, inc))
|
|
return false;
|
|
buf->len += inc;
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Make space to prepend to a buffer.
|
|
* Return NULL if no space.
|
|
*/
|
|
|
|
static inline uint8_t *
|
|
buf_prepend (struct buffer *buf, int size)
|
|
{
|
|
if (size < 0 || size > buf->offset)
|
|
return NULL;
|
|
buf->offset -= size;
|
|
buf->len += size;
|
|
return BPTR (buf);
|
|
}
|
|
|
|
static inline bool
|
|
buf_advance (struct buffer *buf, int size)
|
|
{
|
|
if (size < 0 || buf->len < size)
|
|
return false;
|
|
buf->offset += size;
|
|
buf->len -= size;
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Return a pointer to allocated space inside a buffer.
|
|
* Return NULL if no space.
|
|
*/
|
|
|
|
static inline uint8_t *
|
|
buf_write_alloc (struct buffer *buf, int size)
|
|
{
|
|
uint8_t *ret;
|
|
if (!buf_safe (buf, size))
|
|
return NULL;
|
|
ret = BPTR (buf) + buf->len;
|
|
buf->len += size;
|
|
return ret;
|
|
}
|
|
|
|
static inline uint8_t *
|
|
buf_write_alloc_prepend (struct buffer *buf, int size, bool prepend)
|
|
{
|
|
return prepend ? buf_prepend (buf, size) : buf_write_alloc (buf, size);
|
|
}
|
|
|
|
static inline uint8_t *
|
|
buf_read_alloc (struct buffer *buf, int size)
|
|
{
|
|
uint8_t *ret;
|
|
if (size < 0 || buf->len < size)
|
|
return NULL;
|
|
ret = BPTR (buf);
|
|
buf->offset += size;
|
|
buf->len -= size;
|
|
return ret;
|
|
}
|
|
|
|
static inline bool
|
|
buf_write (struct buffer *dest, const void *src, int size)
|
|
{
|
|
uint8_t *cp = buf_write_alloc (dest, size);
|
|
if (!cp)
|
|
return false;
|
|
memcpy (cp, src, size);
|
|
return true;
|
|
}
|
|
|
|
static inline bool
|
|
buf_write_prepend (struct buffer *dest, const void *src, int size)
|
|
{
|
|
uint8_t *cp = buf_prepend (dest, size);
|
|
if (!cp)
|
|
return false;
|
|
memcpy (cp, src, size);
|
|
return true;
|
|
}
|
|
|
|
static inline bool
|
|
buf_write_u8 (struct buffer *dest, int data)
|
|
{
|
|
uint8_t u8 = (uint8_t) data;
|
|
return buf_write (dest, &u8, sizeof (uint8_t));
|
|
}
|
|
|
|
static inline bool
|
|
buf_write_u16 (struct buffer *dest, int data)
|
|
{
|
|
uint16_t u16 = htons ((uint16_t) data);
|
|
return buf_write (dest, &u16, sizeof (uint16_t));
|
|
}
|
|
|
|
static inline bool
|
|
buf_write_u32 (struct buffer *dest, int data)
|
|
{
|
|
uint32_t u32 = htonl ((uint32_t) data);
|
|
return buf_write (dest, &u32, sizeof (uint32_t));
|
|
}
|
|
|
|
static inline bool
|
|
buf_copy (struct buffer *dest, const struct buffer *src)
|
|
{
|
|
return buf_write (dest, BPTR (src), BLEN (src));
|
|
}
|
|
|
|
static inline bool
|
|
buf_copy_n (struct buffer *dest, struct buffer *src, int n)
|
|
{
|
|
uint8_t *cp = buf_read_alloc (src, n);
|
|
if (!cp)
|
|
return false;
|
|
return buf_write (dest, cp, n);
|
|
}
|
|
|
|
static inline bool
|
|
buf_copy_range (struct buffer *dest,
|
|
int dest_index,
|
|
const struct buffer *src,
|
|
int src_index,
|
|
int src_len)
|
|
{
|
|
if (src_index < 0
|
|
|| src_len < 0
|
|
|| src_index + src_len > src->len
|
|
|| dest_index < 0
|
|
|| dest->offset + dest_index + src_len > dest->capacity)
|
|
return false;
|
|
memcpy (dest->data + dest->offset + dest_index, src->data + src->offset + src_index, src_len);
|
|
if (dest_index + src_len > dest->len)
|
|
dest->len = dest_index + src_len;
|
|
return true;
|
|
}
|
|
|
|
/* truncate src to len, copy excess data beyond len to dest */
|
|
static inline bool
|
|
buf_copy_excess (struct buffer *dest,
|
|
struct buffer *src,
|
|
int len)
|
|
{
|
|
if (len < 0)
|
|
return false;
|
|
if (src->len > len)
|
|
{
|
|
struct buffer b = *src;
|
|
src->len = len;
|
|
if (!buf_advance (&b, len))
|
|
return false;
|
|
return buf_copy (dest, &b);
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
static inline bool
|
|
buf_read (struct buffer *src, void *dest, int size)
|
|
{
|
|
uint8_t *cp = buf_read_alloc (src, size);
|
|
if (!cp)
|
|
return false;
|
|
memcpy (dest, cp, size);
|
|
return true;
|
|
}
|
|
|
|
static inline int
|
|
buf_read_u8 (struct buffer *buf)
|
|
{
|
|
int ret;
|
|
if (BLEN (buf) < 1)
|
|
return -1;
|
|
ret = *BPTR(buf);
|
|
buf_advance (buf, 1);
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
buf_read_u16 (struct buffer *buf)
|
|
{
|
|
uint16_t ret;
|
|
if (!buf_read (buf, &ret, sizeof (uint16_t)))
|
|
return -1;
|
|
return ntohs (ret);
|
|
}
|
|
|
|
static inline uint32_t
|
|
buf_read_u32 (struct buffer *buf, bool *good)
|
|
{
|
|
uint32_t ret;
|
|
if (!buf_read (buf, &ret, sizeof (uint32_t)))
|
|
{
|
|
if (good)
|
|
*good = false;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if (good)
|
|
*good = true;
|
|
return ntohl (ret);
|
|
}
|
|
}
|
|
|
|
static inline bool
|
|
buf_string_match (const struct buffer *src, const void *match, int size)
|
|
{
|
|
if (size != src->len)
|
|
return false;
|
|
return memcmp (BPTR (src), match, size) == 0;
|
|
}
|
|
|
|
static inline bool
|
|
buf_string_match_head (const struct buffer *src, const void *match, int size)
|
|
{
|
|
if (size < 0 || size > src->len)
|
|
return false;
|
|
return memcmp (BPTR (src), match, size) == 0;
|
|
}
|
|
|
|
bool buf_string_match_head_str (const struct buffer *src, const char *match);
|
|
bool buf_string_compare_advance (struct buffer *src, const char *match);
|
|
int buf_substring_len (const struct buffer *buf, int delim);
|
|
|
|
/*
|
|
* Bitwise operations
|
|
*/
|
|
static inline void
|
|
xor (uint8_t *dest, const uint8_t *src, int len)
|
|
{
|
|
while (len-- > 0)
|
|
*dest++ ^= *src++;
|
|
}
|
|
|
|
/*
|
|
* Print a string which might be NULL
|
|
*/
|
|
const char *np (const char *str);
|
|
|
|
/*#define CHARACTER_CLASS_DEBUG*/
|
|
|
|
/* character classes */
|
|
|
|
#define CC_ANY (1<<0)
|
|
#define CC_NULL (1<<1)
|
|
|
|
#define CC_ALNUM (1<<2)
|
|
#define CC_ALPHA (1<<3)
|
|
#define CC_ASCII (1<<4)
|
|
#define CC_CNTRL (1<<5)
|
|
#define CC_DIGIT (1<<6)
|
|
#define CC_PRINT (1<<7)
|
|
#define CC_PUNCT (1<<8)
|
|
#define CC_SPACE (1<<9)
|
|
#define CC_XDIGIT (1<<10)
|
|
|
|
#define CC_BLANK (1<<11)
|
|
#define CC_NEWLINE (1<<12)
|
|
#define CC_CR (1<<13)
|
|
|
|
#define CC_BACKSLASH (1<<14)
|
|
#define CC_UNDERBAR (1<<15)
|
|
#define CC_DASH (1<<16)
|
|
#define CC_DOT (1<<17)
|
|
#define CC_COMMA (1<<18)
|
|
#define CC_COLON (1<<19)
|
|
#define CC_SLASH (1<<20)
|
|
#define CC_SINGLE_QUOTE (1<<21)
|
|
#define CC_DOUBLE_QUOTE (1<<22)
|
|
#define CC_REVERSE_QUOTE (1<<23)
|
|
#define CC_AT (1<<24)
|
|
#define CC_EQUAL (1<<25)
|
|
|
|
/* macro classes */
|
|
#define CC_NAME (CC_ALNUM|CC_UNDERBAR)
|
|
#define CC_CRLF (CC_CR|CC_NEWLINE)
|
|
|
|
bool char_class (const unsigned char c, const unsigned int flags);
|
|
bool string_class (const char *str, const unsigned int inclusive, const unsigned int exclusive);
|
|
bool string_mod (char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace);
|
|
|
|
const char *string_mod_const (const char *str,
|
|
const unsigned int inclusive,
|
|
const unsigned int exclusive,
|
|
const char replace,
|
|
struct gc_arena *gc);
|
|
|
|
#ifdef CHARACTER_CLASS_DEBUG
|
|
void character_class_debug (void);
|
|
#endif
|
|
|
|
/*
|
|
* Verify that a pointer is correctly aligned
|
|
*/
|
|
#ifdef VERIFY_ALIGNMENT
|
|
void valign4 (const struct buffer *buf, const char *file, const int line);
|
|
# define verify_align_4(ptr) valign4(buf, __FILE__, __LINE__)
|
|
#else
|
|
# define verify_align_4(ptr)
|
|
#endif
|
|
|
|
/*
|
|
* Very basic garbage collection, mostly for routines that return
|
|
* char ptrs to malloced strings.
|
|
*/
|
|
|
|
void gc_transfer (struct gc_arena *dest, struct gc_arena *src);
|
|
|
|
void x_gc_free (struct gc_arena *a);
|
|
|
|
static inline void
|
|
gc_init (struct gc_arena *a)
|
|
{
|
|
a->list = NULL;
|
|
}
|
|
|
|
static inline void
|
|
gc_detach (struct gc_arena *a)
|
|
{
|
|
gc_init (a);
|
|
}
|
|
|
|
static inline struct gc_arena
|
|
gc_new (void)
|
|
{
|
|
struct gc_arena ret;
|
|
ret.list = NULL;
|
|
return ret;
|
|
}
|
|
|
|
static inline void
|
|
gc_free (struct gc_arena *a)
|
|
{
|
|
if (a->list)
|
|
x_gc_free (a);
|
|
}
|
|
|
|
static inline void
|
|
gc_reset (struct gc_arena *a)
|
|
{
|
|
gc_free (a);
|
|
}
|
|
|
|
/*
|
|
* Allocate memory to hold a structure
|
|
*/
|
|
|
|
void out_of_memory (void);
|
|
|
|
#define ALLOC_OBJ(dptr, type) \
|
|
{ \
|
|
check_malloc_return ((dptr) = (type *) malloc (sizeof (type))); \
|
|
}
|
|
|
|
#define ALLOC_OBJ_CLEAR(dptr, type) \
|
|
{ \
|
|
ALLOC_OBJ (dptr, type); \
|
|
memset ((dptr), 0, sizeof(type)); \
|
|
}
|
|
|
|
#define ALLOC_ARRAY(dptr, type, n) \
|
|
{ \
|
|
check_malloc_return ((dptr) = (type *) malloc (sizeof (type) * (n))); \
|
|
}
|
|
|
|
#define ALLOC_ARRAY_GC(dptr, type, n, gc) \
|
|
{ \
|
|
(dptr) = (type *) gc_malloc (sizeof (type) * (n), false, (gc)); \
|
|
}
|
|
|
|
#define ALLOC_ARRAY_CLEAR(dptr, type, n) \
|
|
{ \
|
|
ALLOC_ARRAY (dptr, type, n); \
|
|
memset ((dptr), 0, (sizeof(type) * (n))); \
|
|
}
|
|
|
|
#define ALLOC_ARRAY_CLEAR_GC(dptr, type, n, gc) \
|
|
{ \
|
|
(dptr) = (type *) gc_malloc (sizeof (type) * (n), true, (gc)); \
|
|
}
|
|
|
|
#define ALLOC_OBJ_GC(dptr, type, gc) \
|
|
{ \
|
|
(dptr) = (type *) gc_malloc (sizeof (type), false, (gc)); \
|
|
}
|
|
|
|
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc) \
|
|
{ \
|
|
(dptr) = (type *) gc_malloc (sizeof (type), true, (gc)); \
|
|
}
|
|
|
|
static inline void
|
|
check_malloc_return (void *p)
|
|
{
|
|
void out_of_memory (void);
|
|
if (!p)
|
|
out_of_memory ();
|
|
}
|
|
|
|
/*
|
|
* Manage lists of buffers
|
|
*/
|
|
|
|
#ifdef ENABLE_BUFFER_LIST
|
|
|
|
struct buffer_entry
|
|
{
|
|
struct buffer buf;
|
|
struct buffer_entry *next;
|
|
};
|
|
|
|
struct buffer_list
|
|
{
|
|
struct buffer_entry *head; /* next item to pop/peek */
|
|
struct buffer_entry *tail; /* last item pushed */
|
|
int size; /* current number of entries */
|
|
int max_size; /* maximum size list should grow to */
|
|
};
|
|
|
|
struct buffer_list *buffer_list_new (const int max_size);
|
|
void buffer_list_free (struct buffer_list *ol);
|
|
|
|
bool buffer_list_defined (const struct buffer_list *ol);
|
|
void buffer_list_reset (struct buffer_list *ol);
|
|
|
|
void buffer_list_push (struct buffer_list *ol, const unsigned char *str);
|
|
const struct buffer *buffer_list_peek (struct buffer_list *ol);
|
|
void buffer_list_advance (struct buffer_list *ol, int n);
|
|
|
|
struct buffer_list *buffer_list_file (const char *fn, int max_line_len);
|
|
|
|
#endif
|
|
|
|
#endif /* BUFFER_H */
|