Improve new config code, SORTED and NO_DUPLICATE flags

Config Object Model parser now returns bitmask result of CFxxx flags and only
allocates root node if the config file is non-empty.

Added emalloc_zero().
This commit is contained in:
Andrew Bettison 2012-11-30 12:32:30 +10:30
parent f42292ffc6
commit 4aac3637ed
8 changed files with 132 additions and 91 deletions

View File

@ -46,8 +46,10 @@ static const char *cf_find_keyend(const char *const key, const char *const fullk
static int cf_om_make_child(struct cf_om_node **const parentp, const char *const fullkey, const char *const key, const char *const keyend)
{
// Allocate parent node if it is not present.
if (!*parentp && (*parentp = emalloc_zero(sizeof **parentp)) == NULL)
return -1;
size_t keylen = keyend - key;
//DEBUGF("%s key=%s", __FUNCTION__, alloca_toprint(-1, key, keylen));
int i = 0;
struct cf_om_node *child;
if ((*parentp)->nodc) {
@ -75,10 +77,8 @@ static int cf_om_make_child(struct cf_om_node **const parentp, const char *const
// At this point, i is the index where a new child should be inserted.
assert(i >= 0);
assert(i <= (*parentp)->nodc);
child = emalloc(sizeof *child);
if (child == NULL)
if ((child = emalloc_zero(sizeof *child)) == NULL)
return -1;
memset(child, 0, sizeof *child);
++(*parentp)->nodc;
if ((*parentp)->nodc > NELS((*parentp)->nodv))
*parentp = realloc(*parentp, sizeof(**parentp) + sizeof((*parentp)->nodv[0]) * ((*parentp)->nodc - NELS((*parentp)->nodv)));
@ -105,31 +105,13 @@ int cf_get_child(const struct cf_om_node *parent, const char *key)
return -1;
}
void cf_free_node(struct cf_om_node *node)
int cf_parse_to_om(const char *source, const char *buf, size_t len, struct cf_om_node **rootp)
{
while (node->nodc)
cf_free_node(node->nodv[--node->nodc]);
if (node->fullkey) {
free((char *)node->fullkey);
node->fullkey = node->key = NULL;
}
if (node->text) {
free((char *)node->text);
node->text = NULL;
}
free(node);
}
struct cf_om_node *cf_parse_to_om(const char *source, const char *buf, size_t len)
{
struct cf_om_node *root = emalloc(sizeof(struct cf_om_node));
if (root == NULL)
return NULL;
memset(root, 0, sizeof *root);
const char *end = buf + len;
const char *line = buf;
const char *nextline;
unsigned lineno = 1;
int result = CFOK;
for (lineno = 1; line < end; line = nextline, ++lineno) {
const char *lend = line;
while (lend < end && *lend != '\n')
@ -148,10 +130,11 @@ struct cf_om_node *cf_parse_to_om(const char *source, const char *buf, size_t le
for (p = line; p < lend && *p != '='; ++p)
;
if (p == line || p == lend) {
WARNF("%s:%u: malformed configuration line -- ignored", source, lineno);
WARNF("%s:%u: malformed configuration line", source, lineno);
result |= CFINVALID;
continue;
}
struct cf_om_node **nodep = &root;
struct cf_om_node **nodep = rootp;
const char *fullkey = line;
const char *fullkeyend = p;
const char *key = fullkey;
@ -162,31 +145,48 @@ struct cf_om_node *cf_parse_to_om(const char *source, const char *buf, size_t le
nodep = &(*nodep)->nodv[nodi];
}
if (keyend == NULL) {
WARNF("%s:%u: malformed configuration option %s -- ignored",
WARNF("%s:%u: malformed configuration option %s",
source, lineno, alloca_toprint(-1, fullkey, fullkeyend - fullkey)
);
result |= CFINVALID;
continue;
}
if (nodi == -1)
goto error; // out of memory
return CFERROR; // out of memory
struct cf_om_node *node = *nodep;
if (node->text) {
WARNF("%s:%u: duplicate configuration option %s -- ignored (original is at %s:%u)",
WARNF("%s:%u: duplicate configuration option %s (original is at %s:%u)",
source, lineno, alloca_toprint(-1, fullkey, fullkeyend - fullkey),
node->source, node->line_number
);
result |= CFDUPLICATE;
continue;
}
++p;
if (!(node->text = strn_edup(p, lend - p)))
break; // out of memory
return CFERROR; // out of memory
node->source = source;
node->line_number = lineno;
}
return root;
error:
cf_free_node(root);
return NULL;
return result;
}
void cf_free_node(struct cf_om_node **nodep)
{
if (*nodep) {
while ((*nodep)->nodc)
cf_free_node(&(*nodep)->nodv[--(*nodep)->nodc]);
if ((*nodep)->fullkey) {
free((char *)(*nodep)->fullkey);
(*nodep)->fullkey = (*nodep)->key = NULL;
}
if ((*nodep)->text) {
free((char *)(*nodep)->text);
(*nodep)->text = NULL;
}
free(*nodep);
*nodep = NULL;
}
}
void cf_dump_node(const struct cf_om_node *node, int indent)
@ -287,6 +287,7 @@ strbuf strbuf_cf_flags(strbuf sb, int flags)
size_t n = strbuf_len(sb);
static struct { int flag; const char *name; } flagdefs[] = {
{ CFEMPTY, "CFEMPTY" },
{ CFDUPLICATE, "CFDUPLICATE" },
{ CFSTRINGOVERFLOW, "CFSTRINGOVERFLOW" },
{ CFARRAYOVERFLOW, "CFARRAYOVERFLOW" },
{ CFINCOMPLETE, "CFINCOMPLETE" },
@ -329,12 +330,14 @@ strbuf strbuf_cf_flag_reason(strbuf sb, int flags)
size_t n = strbuf_len(sb);
static struct { int flag; const char *reason; } flagdefs[] = {
{ CFEMPTY, "empty" },
{ CFDUPLICATE, "duplicate element" },
{ CFSTRINGOVERFLOW, "string overflow" },
{ CFARRAYOVERFLOW, "array overflow" },
{ CFINCOMPLETE, "incomplete" },
{ CFINVALID, "invalid" },
{ CFUNSUPPORTED, "not supported" },
{ CFSUB(CFEMPTY), "contains empty element" },
{ CFSUB(CFDUPLICATE), "contains element with duplicate" },
{ CFSUB(CFSTRINGOVERFLOW), "contains string overflow" },
{ CFSUB(CFARRAYOVERFLOW), "contains array overflow" },
{ CFSUB(CFINCOMPLETE), "contains incomplete element" },
@ -373,7 +376,7 @@ void _cf_warn_array_key(struct __sourceloc __whence, const struct cf_om_node *no
{
strbuf b = strbuf_alloca(180);
strbuf_cf_flag_reason(b, reason);
_cf_warn_node(__whence, node, NULL, "array label %s -- %s", alloca_str_toprint(node->key), strbuf_str(b));
_cf_warn_node(__whence, node, NULL, "array key %s -- %s", alloca_str_toprint(node->key), strbuf_str(b));
}
void _cf_warn_array_value(struct __sourceloc __whence, const struct cf_om_node *node, int reason)

View File

@ -37,7 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define END_STRUCT \
return CFOK; \
}
#define ARRAY(__name, __validator...) \
#define ARRAY(__name, __flags, __validator...) \
int cf_dfl_config_##__name(struct config_##__name *a) { \
a->ac = 0; \
return CFOK; \
@ -76,15 +76,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define SUB_STRUCT(__name, __element, __flags)
#define NODE_STRUCT(__name, __element, __parser, __flags)
#define END_STRUCT
#define ARRAY(__name, __validator...) \
#define ARRAY(__name, __flags, __validator...) \
static int __cmp_config_##__name(const struct config_##__name##__element *a, const struct config_##__name##__element *b) { \
__compare_func__config_##__name##__t *cmp = (NULL
#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
,##__cmpfunc); \
return cmp ? (*cmp)(&a->key, &b->key) : 0;
return cmp ? (*cmp)(&a->key, &b->key) : memcmp(&a->key, &b->key, sizeof a->key);
#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \
,##__cmpfunc); \
return cmp ? (*cmp)(a->key, b->key) : 0;
return cmp ? (*cmp)(a->key, b->key) : strcmp(a->key, b->key);
#define VALUE_ATOM(__type, __eltparser)
#define VALUE_STRING(__strsize, __eltparser)
#define VALUE_NODE(__type, __eltparser)
@ -114,11 +114,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#define __MANDATORY (1<<0)
#define __TEXT (1<<1)
#define __CHILDREN (1<<2)
#define __SORTED (1<<3)
#define __NO_DUPLICATES (1<<4)
// Schema flag symbols, to be used in the '__flags' macro arguments.
#define MANDATORY |__MANDATORY
#define USES_TEXT |__TEXT
#define USES_CHILDREN |__CHILDREN
#define SORTED |__SORTED
#define NO_DUPLICATES |__NO_DUPLICATES
// Generate parsing functions, cf_opt_config_SECTION()
#define STRUCT(__name, __validator...) \
@ -182,9 +186,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
return result; \
}
#define ARRAY(__name, __validator...) \
#define ARRAY(__name, __flags, __validator...) \
int cf_opt_config_##__name(struct config_##__name *array, const struct cf_om_node *node) { \
__compare_func__config_##__name##__t *cmp = NULL; \
int flags = (0 __flags); \
int (*eltcmp)(const struct config_##__name##__element *, const struct config_##__name##__element *) = __cmp_config_##__name; \
int (*validator)(const struct cf_om_node *, struct config_##__name *, int) = (NULL, ##__validator); \
int result = CFOK; \
@ -192,13 +196,22 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
for (n = 0, i = 0; i < node->nodc && n < NELS(array->av); ++i) { \
const struct cf_om_node *child = node->nodv[i]; \
int ret = CFEMPTY;
#define __ARRAY_KEY(__parseexpr) \
#define __ARRAY_KEY(__parseexpr, __cmpfunc...) \
ret = (__parseexpr); \
if (ret == CFERROR) \
return CFERROR; \
result |= ret & CF__SUBFLAGS; \
ret &= CF__FLAGS; \
result |= CFSUB(ret); \
if (ret == CFOK && (flags & __NO_DUPLICATES)) { \
int j; \
for (j = 0; j < n; ++j) { \
if ((*eltcmp)(&array->av[j], &array->av[n]) == 0) { \
cf_warn_duplicate_node(child, NULL); \
ret |= CFDUPLICATE; \
} \
} \
} \
if (ret != CFOK) \
cf_warn_array_key(child, ret);
#define __ARRAY_VALUE(__parseexpr) \
@ -223,7 +236,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
cf_warn_list_overflow(node->nodv[i]); \
} \
array->ac = n; \
if (cmp) \
if (flags & __SORTED) \
qsort(array->av, array->ac, sizeof array->av[0], (int (*)(const void *, const void *)) eltcmp); \
if (validator) \
result = (*validator)(node, array, result); \
@ -236,11 +249,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
return result; \
}
#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
__ARRAY_KEY(__eltparser(&array->av[n].key, child->key)) \
cmp = (NULL, ##__cmpfunc);
__ARRAY_KEY(__eltparser(&array->av[n].key, child->key), ##__cmpfunc)
#define KEY_STRING(__strsize, __eltparser, __cmpfunc...) \
__ARRAY_KEY(__eltparser(array->av[n].key, sizeof array->av[n].key, child->key)) \
cmp = (NULL, ##__cmpfunc);
__ARRAY_KEY(__eltparser(array->av[n].key, sizeof array->av[n].key, child->key), ##__cmpfunc)
#define VALUE_ATOM(__type, __eltparser) \
__ARRAY_VALUE(child->text ? __eltparser(&array->av[n].value, child->text) : CFEMPTY)
#define VALUE_STRING(__strsize, __eltparser) \

View File

@ -246,7 +246,7 @@ int vld_argv(const struct cf_om_node *parent, struct config_argv *array, int res
char labelkey[12];
sprintf(labelkey, "%u", last_key);
cf_warn_duplicate_node(parent, labelkey);
result |= CFINVALID;
result |= CFDUPLICATE;
}
while (++last_key < key && last_key <= sizeof(array->av)) {
char labelkey[12];

View File

@ -50,7 +50,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* STRING(80, element2, "boo!", cf_opt_str_nonempty, MANDATORY, "A non-empty string")
* END_STRUCT
*
* ARRAY(joy)
* ARRAY(joy,)
* KEY_STRING(3, happy, cf_opt_str)
* VALUE_SUB_STRUCT(happy)
* END_ARRAY(16)
@ -104,7 +104,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* SUB_STRUCT(structname, element, flags)
* NODE_STRUCT(structname, element, parsefunc, flags)
*
* ARRAY(name[, validatorfunc])
* ARRAY(name, flags[, validatorfunc])
* key-declaration
* value-declaration
* END_ARRAY(size)
@ -199,7 +199,7 @@ STRUCT(mdp_iftype)
ATOM(uint32_t, tick_ms, 0, cf_opt_uint32_nonzero,, "Tick interval for this interface type")
END_STRUCT
ARRAY(mdp_iftypelist)
ARRAY(mdp_iftypelist, NO_DUPLICATES)
KEY_ATOM(short, cf_opt_interface_type, cmp_short)
VALUE_SUB_STRUCT(mdp_iftype)
END_ARRAY(5)
@ -216,7 +216,7 @@ ATOM(uint16_t, remote_port,4130, cf_opt_port,, "Remote port number"
ATOM(uint16_t, local_port, 4131, cf_opt_port,, "Local port number")
END_STRUCT
ARRAY(argv, vld_argv)
ARRAY(argv, SORTED NO_DUPLICATES, vld_argv)
KEY_ATOM(unsigned short, cf_opt_ushort_nonzero, cmp_ushort)
VALUE_STRING(128, cf_opt_str)
END_ARRAY(16)
@ -236,7 +236,7 @@ STRING(256, host, "", cf_opt_str_nonempty, MANDATORY, "Hos
ATOM(uint16_t, port, RHIZOME_HTTP_PORT, cf_opt_port,, "Port number")
END_STRUCT
ARRAY(peerlist)
ARRAY(peerlist,)
KEY_STRING(15, cf_opt_str)
VALUE_NODE(struct config_rhizomepeer, cf_opt_rhizome_peer)
END_ARRAY(10)
@ -276,7 +276,7 @@ ATOM(struct in_addr, address, (struct in_addr){htonl(INADDR_NONE)}, cf
ATOM(uint16_t, port, PORT_DNA, cf_opt_port,, "Port number")
END_STRUCT
ARRAY(host_list)
ARRAY(host_list, NO_DUPLICATES)
KEY_ATOM(sid_t, cf_opt_sid, cmp_sid)
VALUE_SUB_STRUCT(host)
END_ARRAY(32)
@ -290,7 +290,7 @@ ATOM(uint64_t, speed, 1000000, cf_opt_uint64_scaled,, "Speed i
ATOM(uint32_t, mdp_tick_ms, 0, cf_opt_uint32_nonzero,, "Override MDP tick interval for this interface")
END_STRUCT
ARRAY(interface_list)
ARRAY(interface_list,)
KEY_STRING(15, cf_opt_str)
VALUE_SUB_STRUCT(network_interface)
END_ARRAY(10)
@ -306,5 +306,6 @@ SUB_STRUCT(dna, dna,)
NODE(debugflags_t, debug, 0, cf_opt_debugflags, USES_CHILDREN, "Debug flags")
SUB_STRUCT(rhizome, rhizome,)
SUB_STRUCT(directory, directory,)
SUB_STRUCT(olsr, olsr,)
SUB_STRUCT(host_list, hosts,)
END_STRUCT

View File

@ -98,7 +98,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* function is used to parse each individual array element, and the parsed result is only
* appended to the array if it returns CFOK.
*
* If a STRUCT(NAME, VALIDATOR) or ARRAY(NAME, VALIDATOR) schema declaration is given a
* If a STRUCT(NAME, VALIDATOR) or ARRAY(NAME, FLAGS, VALIDATOR) schema declaration is given a
* validator function, then the function must have the following signature:
*
* - int VALIDATOR(struct config_NAME *dest, int orig_result);
@ -140,12 +140,19 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* contains elements that are not defined in the STRUCT. This may indicate a typo in the name
* of a config option, resulting in the intended option not being set.
*
* - CFDUPLICATE if a duplicate array entry was found. The result may be an empty array (in which
* case CFEMPTY is also set), or an array that omits the duplicate element. It is not defined
* which of the two conflicting elements will get omitted. Normal array parsing without a
* validator function will return an empty array in the case of duplicate, but a validator
* function may change this behaviour.
*
* - CFARRAYOVERFLOW if the size of any array was exceeded. The result in *dest may be empty (in
* which case CFEMPTY is also set), or may contain elements parsed successfully from the COM (ie,
* returned CFOK), omitting any that did not parse successfully (in which case other bits will be
* set) and arbitrarily omitting others that did not fit (it is not defined which will be
* omitted). Normal array parsing without a validator function will return an empty result in
* the case of overflow, but a validator function may change this behaviour.
* returned CFOK), omitting any that did not parse successfully (in which case the relevant
* CFSUB() bits will be set) and arbitrarily omitting others that did not fit. It is not defined
* which elements get omitted from an overflowed array. Normal array parsing without a validator
* function will return an empty array in the case of overflow, but a validator function may
* change this behaviour.
*
* - CFSTRINGFOVERFLOW if the size of any string element was exceeded. The result in *dest may be
* unchanged or may contain a truncated string, depending on the parser that detected and
@ -206,6 +213,25 @@ struct pattern_list {
};
#define PATTERN_LIST_EMPTY ((struct pattern_list){.patc = 0})
/* Return bit flags for config schema default cf_dfl_xxx() and parsing cf_opt_xxx() functions. */
#define CFERROR (~0) // all set
#define CFOK 0
#define CFEMPTY (1<<0)
#define CFDUPLICATE (1<<1)
#define CFARRAYOVERFLOW (1<<2)
#define CFSTRINGOVERFLOW (1<<3)
#define CFINCOMPLETE (1<<4)
#define CFINVALID (1<<5)
#define CFUNSUPPORTED (1<<6)
#define CF__SUB_SHIFT 16
#define CFSUB(f) ((f) << CF__SUB_SHIFT)
#define CF__SUBFLAGS CFSUB(~0)
#define CF__FLAGS (~0 & ~CF__SUBFLAGS)
strbuf strbuf_cf_flags(strbuf, int);
strbuf strbuf_cf_flag_reason(strbuf sb, int flags);
/* The Configuration Object Model (COM). The config file is parsed into a tree of these structures
* first, then those structures are passed as arguments to the schema parsing functions.
*/
@ -220,29 +246,11 @@ struct cf_om_node {
struct cf_om_node *nodv[10]; // malloc()
};
struct cf_om_node *cf_parse_to_om(const char *source, const char *buf, size_t len);
int cf_parse_to_om(const char *source, const char *buf, size_t len, struct cf_om_node **rootp);
int cf_get_child(const struct cf_om_node *parent, const char *key);
void cf_free_node(struct cf_om_node *node);
void cf_free_node(struct cf_om_node **nodep);
void cf_dump_node(const struct cf_om_node *node, int indent);
/* Return bit flags for config schema default cf_dfl_xxx() and parsing cf_opt_xxx() functions. */
#define CFERROR (~0) // all set
#define CFOK 0
#define CFEMPTY (1<<0)
#define CFARRAYOVERFLOW (1<<1)
#define CFSTRINGOVERFLOW (1<<2)
#define CFINCOMPLETE (1<<3)
#define CFINVALID (1<<4)
#define CFUNSUPPORTED (1<<5)
#define CF__SUB_SHIFT 16
#define CFSUB(f) ((f) << CF__SUB_SHIFT)
#define CF__SUBFLAGS CFSUB(~0)
#define CF__FLAGS (~0 & ~CF__SUBFLAGS)
strbuf strbuf_cf_flags(strbuf, int);
strbuf strbuf_cf_flag_reason(strbuf sb, int flags);
/* Diagnostic functions for use in config schema parsing functions, cf_opt_xxx(). */
void _cf_warn_nodev(struct __sourceloc __whence, const struct cf_om_node *node, const char *key, const char *fmt, va_list ap);
@ -290,7 +298,7 @@ void _cf_warn_array_value(struct __sourceloc __whence, const struct cf_om_node *
struct config_##__name __element;
#define END_STRUCT \
};
#define ARRAY(__name, __validator...) \
#define ARRAY(__name, __flags, __validator...) \
struct config_##__name { \
unsigned ac; \
struct config_##__name##__element {
@ -338,7 +346,7 @@ void _cf_warn_array_value(struct __sourceloc __whence, const struct cf_om_node *
#define SUB_STRUCT(__name, __element, __flags)
#define NODE_STRUCT(__name, __element, __parser, __flags)
#define END_STRUCT
#define ARRAY(__name, __validator...) \
#define ARRAY(__name, __flags, __validator...) \
int cf_dfl_config_##__name(struct config_##__name *a);
#define KEY_ATOM(__type, __eltparser, __cmpfunc...)
#define KEY_STRING(__strsize, __eltparser, __cmpfunc...)
@ -384,7 +392,7 @@ void _cf_warn_array_value(struct __sourceloc __whence, const struct cf_om_node *
#define NODE_STRUCT(__name, __element, __parser, __flags) \
int __parser(struct config_##__name *, const struct cf_om_node *);
#define END_STRUCT
#define ARRAY(__name, __validator...) \
#define ARRAY(__name, __flags, __validator...) \
int cf_opt_config_##__name(struct config_##__name *, const struct cf_om_node *); \
__VALIDATOR(__name, ##__validator)
#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
@ -429,7 +437,7 @@ void _cf_warn_array_value(struct __sourceloc __whence, const struct cf_om_node *
#define SUB_STRUCT(__name, __element, __flags)
#define NODE_STRUCT(__name, __element, __parser, __flags)
#define END_STRUCT
#define ARRAY(__name, __validator...) \
#define ARRAY(__name, __flags, __validator...) \
typedef int __compare_func__config_##__name##__t
#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
(const __type *, const __type *);
@ -445,7 +453,7 @@ void _cf_warn_array_value(struct __sourceloc __whence, const struct cf_om_node *
#undef ARRAY
#undef KEY_ATOM
#undef KEY_STRING
#define ARRAY(__name, __validator...) \
#define ARRAY(__name, __flags, __validator...) \
__compare_func__config_##__name##__t __dummy__compare_func__config_##__name
#define KEY_ATOM(__type, __eltparser, __cmpfunc...) \
,##__cmpfunc;

View File

@ -29,14 +29,16 @@ int main(int argc, char **argv)
perror("read");
exit(1);
}
struct cf_om_node *root = cf_parse_to_om(argv[i], buf, st.st_size);
struct cf_om_node *root = NULL;
int ret = cf_parse_to_om(argv[i], buf, st.st_size, &root);
close(fd);
DEBUGF("ret = %s", strbuf_str(strbuf_cf_flags(strbuf_alloca(128), ret)));
//cf_dump_node(root, 0);
struct config_main config;
memset(&config, 0, sizeof config);
cf_dfl_config_main(&config);
int result = cf_opt_config_main(&config, root);
cf_free_node(root);
int result = root ? cf_opt_config_main(&config, root) : CFEMPTY;
cf_free_node(&root);
free(buf);
DEBUGF("result = %s", strbuf_str(strbuf_cf_flags(strbuf_alloca(128), result)));
DEBUGF("config.log.file = %s", alloca_str_toprint(config.log.file));

14
mem.c
View File

@ -20,16 +20,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <string.h>
#include "mem.h"
void *_emalloc(struct __sourceloc __whence, size_t len)
void *_emalloc(struct __sourceloc __whence, size_t bytes)
{
char *new = malloc(len + 1);
char *new = malloc(bytes);
if (!new) {
WHYF_perror("malloc(%lu)", (long)len);
WHYF_perror("malloc(%lu)", (long)bytes);
return NULL;
}
return new;
}
void *_emalloc_zero(struct __sourceloc __whence, size_t bytes)
{
char *new = _emalloc(__whence, bytes);
if (new)
memset(new, 0, bytes);
return new;
}
char *_strn_edup(struct __sourceloc __whence, const char *str, size_t len)
{
char *new = _emalloc(__whence, len + 1);

8
mem.h
View File

@ -29,6 +29,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
void *_emalloc(struct __sourceloc, size_t bytes);
/* Equivalent to malloc(3) followed by memset(3) to zerofill, but logs an error
* before returning NULL.
*
* @author Andrew Bettison <andrew@servalproject.com>
*/
void *_emalloc_zero(struct __sourceloc, size_t bytes);
/* Equivalent to strdup(3)/strndup(3), but logs an error before returning NULL.
*
* Why aren't these in str.h? Because str.c must not depend on log.h/log.c! str.c is used in link
@ -40,6 +47,7 @@ char *_str_edup(struct __sourceloc, const char *str);
char *_strn_edup(struct __sourceloc, const char *str, size_t len);
#define emalloc(bytes) _emalloc(__HERE__, (bytes))
#define emalloc_zero(bytes) _emalloc_zero(__HERE__, (bytes))
#define str_edup(str) _str_edup(__HERE__, (str))
#define strn_edup(str, len) _strn_edup(__HERE__, (str), (len))