--- a/src/error.c Sat May 23 00:33:23 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,242 +0,0 @@
-
-#include "error.h"
-
-// for the error_desc tables
-#include "sock.h"
-#include "ssl_internal.h"
-#include "module.h"
-
-#include <string.h>
-#include <stdio.h>
-
-struct error_desc _core_error_desc[] = {
- { ERR_CALLOC, "calloc", ERR_EXTRA_NONE },
- { ERR_STRDUP, "strdup", ERR_EXTRA_NONE },
- { ERR_SIGACTION, "sigaction", ERR_EXTRA_ERRNO },
- { ERR_ACCESS_READ, "access(R_OK)", ERR_EXTRA_ERRNO },
- { ERR_GETADDRINFO, "getaddrinfo", ERR_EXTRA_GAI },
- { ERR_GETADDRINFO_EMPTY, "getaddrinfo: no results", ERR_EXTRA_NONE },
- { ERR_EVENT_NEW, "event_new", ERR_EXTRA_NONE },
- { ERR_EVENT_ADD, "event_add", ERR_EXTRA_NONE },
- { ERR_EVSQL_NEW_PQ, "evsql_new_pq", ERR_EXTRA_NONE },
- { ERR_EVSQL_QUERY_EXEC, "evsql_query_exec", ERR_EXTRA_NONE },
- { ERR_CMD_OPT, "argv", ERR_EXTRA_STR },
- { _ERR_INVALID, NULL, 0 }
-
-}, _sock_error_desc[] = {
- { ERR_SOCKET, "socket", ERR_EXTRA_ERRNO },
- { ERR_CONNECT, "connect", ERR_EXTRA_ERRNO },
- { ERR_READ, "read", ERR_EXTRA_ERRNO },
- { ERR_WRITE, "write", ERR_EXTRA_ERRNO },
- { ERR_WRITE_EOF, "write: EOF", ERR_EXTRA_NONE },
- { ERR_FCNTL, "fcntl", ERR_EXTRA_ERRNO },
- { ERR_CLOSE, "close", ERR_EXTRA_ERRNO },
- { ERR_GETSOCKOPT, "getsockopt", ERR_EXTRA_ERRNO },
- { ERR_OPEN, "open", ERR_EXTRA_ERRNO },
- { ERR_ACCEPT, "accept", ERR_EXTRA_ERRNO },
- { ERR_BIND, "bind", ERR_EXTRA_ERRNO },
- { ERR_LISTEN, "listen", ERR_EXTRA_ERRNO },
- { _ERR_INVALID, NULL, 0 }
-
-}, _sock_gnutls_error_desc[] = {
- { ERR_GNUTLS_CERT_ALLOC_CRED, "gnutls_certificate_allocate_credentials", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_GLOBAL_INIT, "gnutls_global_init", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_SET_DEFAULT_PRIORITY, "gnutls_set_default_priority", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_CRED_SET, "gnutls_credentials_set", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_HANDSHAKE, "gnutls_handshake", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_RECORD_SEND, "gnutls_record_send", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_RECORD_RECV, "gnutls_record_recv", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_RECORD_GET_DIRECTION, "gnutls_record_get_direction", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_CERT_VERIFY_PEERS2, "gnutls_certificate_verify_peers2", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_CERT_VERIFY, "X.509 Certificate verification failed", ERR_EXTRA_STR },
- { ERR_GNUTLS_CERT_SET_X509_TRUST_FILE,"gnutls_certificate_set_x509_trust_file", ERR_EXTRA_GNUTLS },
- { ERR_GNUTLS_CERT_SET_X509_KEY_FILE, "gnutls_certificate_set_x509_key_file", ERR_EXTRA_GNUTLS },
- { _ERR_INVALID, NULL, 0 }
-
-}, _irc_error_desc[] = {
- { ERR_LINE_TOO_LONG, "IRC line is too long", ERR_EXTRA_NONE },
- { ERR_LINE_INVALID_TOKEN, "Illegal token value for IRC line", ERR_EXTRA_NONE },
- { ERR_INVALID_NM, "Invalid nickmask", ERR_EXTRA_NONE },
- { ERR_INVALID_NICK_LENGTH, "Nickname is too long", ERR_EXTRA_NONE },
-
- // extra: the name of the invalid field
- { ERR_IRC_NET_INFO, "invalid irc_net_info", ERR_EXTRA_STR },
- { ERR_IRC_NET_STATE, "invalid irc_net state for operation", ERR_EXTRA_NONE },
- { ERR_IRC_CHAN_STATE, "invalid irc_chan state for operation", ERR_EXTRA_NONE },
-
- { _ERR_INVALID, NULL, 0 }
-
-}, _config_error_desc[] = {
- { ERR_CONFIG_NAME, "unknown config option", ERR_EXTRA_STR },
- { ERR_CONFIG_TYPE, "invalid config type", ERR_EXTRA_NONE },
- { ERR_CONFIG_REQUIRED, "missing required value", ERR_EXTRA_STR },
- { ERR_CONFIG_VALUE, "invalid value", ERR_EXTRA_STR },
- { ERR_CONFIG_PARAMS, "invalid number of paramters", ERR_EXTRA_NONE },
-
- { _ERR_INVALID, NULL, 0 }
-
-}, _module_error_desc[] = {
- { ERR_MODULE_NAME, "invalid module name", ERR_EXTRA_NONE },
- { ERR_MODULE_DUP, "module already loaded", ERR_EXTRA_NONE },
- { ERR_MODULE_PATH, "invalid module path", ERR_EXTRA_STR },
- { ERR_MODULE_OPEN, "module dlopen() failed", ERR_EXTRA_STR },
- { ERR_MODULE_SYM, "module dlsym() failed", ERR_EXTRA_STR },
- { ERR_MODULE_INIT_FUNC, "invalid module init func", ERR_EXTRA_STR },
- { ERR_MODULE_CONF, "module_conf", ERR_EXTRA_STR },
- { _ERR_INVALID, NULL, 0 }
-
-}, _lua_error_desc[] = {
- { ERR_LUA_MEM, "lua: out of memory", ERR_EXTRA_STR },
- { ERR_LUA_SYNTAX, "lua: syntax error", ERR_EXTRA_STR },
- { ERR_LUA_RUN, "lua: runtime error", ERR_EXTRA_STR },
- { ERR_LUA_ERR, "lua: error handling error", ERR_EXTRA_STR },
- { ERR_LUA_FILE, "lua: error loading file", ERR_EXTRA_STR },
- { _ERR_INVALID, NULL, 0 }
-
-}, _pcre_error_desc[] = {
- { ERR_PCRE_COMPILE, "pcre_compile", ERR_EXTRA_STR },
- { ERR_PCRE_EXEC, "pcre_exec", ERR_EXTRA_STR },
- { _ERR_INVALID, NULL, 0 }
-}, _general_error_desc[] = {
- { ERR_MISC, "miscellaneous error", ERR_EXTRA_STR },
- { ERR_CMD_OPT, "invalid command line option", ERR_EXTRA_STR },
- { ERR_DUP_NAME, "duplicate name", ERR_EXTRA_STR },
- { ERR_EOF, "EOF", ERR_EXTRA_NONE },
- { ERR_MEM, "memory allocation error", ERR_EXTRA_NONE },
- { ERR_NOT_IMPLEMENTED, "function not implemented", ERR_EXTRA_NONE },
- { _ERR_INVALID, NULL, 0 }
-};
-
-/**
- * Array of error_desc tables
- */
-static struct error_desc* _desc_tables[] = {
- _core_error_desc,
- _sock_error_desc,
- _sock_gnutls_error_desc,
- _irc_error_desc,
- _config_error_desc,
- _module_error_desc,
- _lua_error_desc,
- _pcre_error_desc,
- _general_error_desc,
- NULL
-};
-
-const struct error_desc* error_lookup (err_t code)
-{
- struct error_desc **desc_table, *desc = NULL;
-
- // iterate over each defined error_desc array
- for (desc_table = _desc_tables; *desc_table; desc_table++) {
- for (desc = *desc_table; desc->code && desc->name; desc++) {
- // compare code
- if (desc->code == code)
- // found
- return desc;
- }
- }
-
- // not found
- return NULL;
-}
-
-const char *error_name (err_t code)
-{
- const struct error_desc *desc;
-
- if (!code)
- // no error...
- return "success";
-
- else if ((desc = error_lookup(code)))
- // found an error_desc for it
- return desc->name;
-
- else
- // unknown
- return "[unknown]";
-}
-
-const char *error_msg (const struct error_info *err)
-{
- static char msg[ERROR_MSG_MAXLEN];
- const struct error_desc *desc;
-
- // do we have an error_desc for it?
- if ((desc = error_lookup(err->code)) == NULL)
- // ???
- snprintf(msg, ERROR_MSG_MAXLEN, "[%#.8x]: %#.8x", err->code, err->extra);
-
- else
- // intrepret .extra
- switch (desc->extra_type) {
- case ERR_EXTRA_NONE:
- // no additional info
- snprintf(msg, ERROR_MSG_MAXLEN, "%s", desc->name);
- break;
-
- case ERR_EXTRA_ERRNO:
- // strerror
- snprintf(msg, ERROR_MSG_MAXLEN, "%s: %s", desc->name, strerror(err->extra));
- break;
-
- case ERR_EXTRA_GAI:
- // gai_strerror
- snprintf(msg, ERROR_MSG_MAXLEN, "%s: %s", desc->name, gai_strerror(err->extra));
- break;
-
- case ERR_EXTRA_GNUTLS:
- // gnutls_strerror
- snprintf(msg, ERROR_MSG_MAXLEN, "%s: %s", desc->name, gnutls_strerror(err->extra));
- break;
-
- case ERR_EXTRA_STR:
- // static error message string
- snprintf(msg, ERROR_MSG_MAXLEN, "%s: %s", desc->name, err->extra_str);
- break;
-
- default:
- // ???
- snprintf(msg, ERROR_MSG_MAXLEN, "%s: %#.8x", desc->name, err->extra);
- break;
- }
-
- // return static pointer
- return msg;
-}
-
-bool error_cmp_eq (const error_t *a, const error_t *b)
-{
- const struct error_desc *desc;
-
- // compare the top-level code
- if (a->code != b->code)
- return false;
-
- // lookup the extra type
- if ((desc = error_lookup(a->code)) == NULL)
- // not good...
- return false;
-
- // compare by type
- switch (desc->extra_type) {
- case ERR_EXTRA_NONE:
- return true;
-
- case ERR_EXTRA_ERRNO:
- case ERR_EXTRA_GAI:
- case ERR_EXTRA_GNUTLS:
- // integer comparison
- return (a->extra == b->extra);
-
- case ERR_EXTRA_STR:
- // string comparison
- return a->extra_str && b->extra_str && (strcmp(a->extra_str, b->extra_str) == 0);
-
- default:
- // ???
- return false;
- }
-}
-
--- a/src/error.h Sat May 23 00:33:23 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-#ifndef ERROR_H
-#define ERROR_H
-
-/**
- * @file
- *
- * Error-handling functions
- */
-#include <errno.h>
-#include <stdbool.h>
-
-/**
- * The type used for error codes is an explicitly *unsigned* int, meaning that error codes themselves are positive.
- * Negative error codes (as signed ints) also exist in some places, and they are just a negative err_t.
- */
-typedef unsigned int err_t;
-
-/**
- * Ways to interpret error_info.extra
- */
-enum error_extra_types {
- /** No extra info */
- ERR_EXTRA_NONE = 0,
-
- /** libc errno, using strerror() */
- ERR_EXTRA_ERRNO,
-
- /** libc resolver, using gai_strerror() */
- ERR_EXTRA_GAI,
-
- /** GnuTLS, using gnutls_strerror() */
- ERR_EXTRA_GNUTLS,
-
- /** Static error message string */
- ERR_EXTRA_STR,
-};
-
-/**
- * List of defined error codes, organized mostly by function name
- */
-enum error_code {
- _ERR_INVALID = 0x000000,
-
- /** stdlib.h functions */
- _ERR_STDLIB = 0x000100,
- ERR_CALLOC,
- ERR_STRDUP,
- ERR_SIGACTION,
- ERR_ACCESS_READ,
-
- /** DNS resolver */
- _ERR_RESOLVER = 0x000200,
- ERR_GETADDRINFO,
- ERR_GETADDRINFO_EMPTY,
-
- /** socket/IO errors */
- _ERR_SOCK = 0x000300,
- ERR_SOCKET, ///< socket(2) failed
- ERR_CONNECT, ///< connect(2) error - either direct or async
- ERR_READ, ///< read(2) error - will probably show up as an ERR_WRITE as well
- ERR_WRITE, ///< write(2) error - data was unsent, will probably show up as an ERR_READ as well
- ERR_WRITE_EOF, ///< write(2) gave EOF - zero bytes written
- ERR_FCNTL, ///< fcntl(2) failed
- ERR_CLOSE, ///< close(2) failed, some written data was probably not sent
- ERR_GETSOCKOPT, ///< getsockopt(2) failed
- ERR_OPEN, ///< open(2) failed
- ERR_ACCEPT, ///< accept(2) failed
- ERR_BIND, ///< bind(2) failed
- ERR_LISTEN, ///< listen(2) failed
-
- /** @see sock_gnutls_error_code */
- _ERR_GNUTLS = 0x000400,
-
- /** Libevent errors */
- _ERR_LIBEVENT = 0x000500,
- ERR_EVENT_NEW,
- ERR_EVENT_ADD,
- ERR_EVENT_DEL,
-
- /** Evsql errors */
- _ERR_EVSQL = 0x000600,
- ERR_EVSQL_NEW_PQ,
- ERR_EVSQL_QUERY_EXEC,
-
- /** irc_proto errors */
- _ERR_IRC_LINE = 0x000700,
- ERR_LINE_TOO_LONG,
- ERR_LINE_INVALID_TOKEN,
- ERR_INVALID_NM,
- ERR_INVALID_NICK_LENGTH,
-
- /** irc_conn errors */
- _ERR_IRC_CONN = 0x000800,
- ERR_IRC_CONN_REGISTER_STATE,
- ERR_IRC_CONN_QUIT_STATE,
-
- /** irc_net errors */
- _ERR_IRC_NET = 0x000900,
- ERR_IRC_NET_INFO,
- ERR_IRC_NET_STATE,
-
- /** @see module_error_code */
- _ERR_MODULE = 0x000a00,
-
- /** config errors */
- _ERR_CONFIG = 0x000b00,
- ERR_CONFIG_NAME, ///< unknown option name
- ERR_CONFIG_TYPE, ///< invalid value type for parameter
- ERR_CONFIG_REQUIRED, ///< missing value for required parameter
- ERR_CONFIG_VALUE, ///< invalid value
- ERR_CONFIG_PARAMS, ///< invalid number of parameters
-
- /** lua errors */
- _ERR_LUA = 0x000c00,
- ERR_LUA_MEM,
- ERR_LUA_SYNTAX,
- ERR_LUA_RUN,
- ERR_LUA_ERR,
- ERR_LUA_FILE,
-
- /** irc_chan errors */
- _ERR_IRC_CHAN = 0x000d00,
- ERR_IRC_CHAN_STATE,
-
- /** pcre errors */
- _ERR_PCRE = 0x000e00,
- ERR_PCRE_COMPILE, ///< pcre_compile: <error_msg>
- ERR_PCRE_EXEC, ///< pcre_exec: <error code>
-
- /** str errors */
- _ERR_STR = 0x000f00,
-
- /** Transport errors */
- _ERR_TRANSPORT = 0x001000,
-
- /** General errors */
- _ERR_GENERAL = 0xffff00,
- ERR_MISC, ///< general error
- ERR_CMD_OPT, ///< invalid commandline option
- ERR_UNKNOWN,
- ERR_DUP_NAME, ///< duplicate name
- ERR_EOF, ///< end of file
- ERR_MEM, ///< memory allocation error
- ERR_NOT_IMPLEMENTED, ///< function not implemented
-};
-
-/**
- * Table of error descriptions
- */
-struct error_desc {
- /** The flat error code */
- err_t code;
-
- /** The short name */
- const char *name;
-
- /** How to interpret .extra */
- enum error_extra_types extra_type;
-};
-
-/**
- * An error code and associated extra infos
- */
-struct error_info {
- /**
- * The base error code.
- *
- * This is a signed int because we need to be able to manipulate negative errors codes as well.
- */
- signed int code;
-
- union {
- /** Additional detail info, usually some third-party error code, as defined by the code's ERR_EXTRA_* */
- int extra;
-
- /** Additional info, stored as a pointer to a static string (note how dangerous this is) */
- const char *extra_str;
- };
-};
-
-/**
- * The public names
- */
-typedef struct error_info error_t;
-
-/**
- * Translate an err_t into a function name.
- */
-const char *error_name (err_t code);
-
-/**
- * Look up the error_desc for the given error code
- */
-const struct error_desc* error_lookup (err_t code);
-
-/**
- * Maximum length of error messages returned by error_msg (including NUL byte)
- */
-#define ERROR_MSG_MAXLEN 1024
-
-/**
- * Translate an error_info into a message.
- *
- * This is returned as a pointer into a statically allocated buffer. It is not re-entrant.
- */
-const char *error_msg (const error_t *err);
-
-/**
- * Compare the given errors for equivalency
- */
-bool error_cmp_eq (const error_t *a, const error_t *b);
-
-/** No error, evaulates as logical false */
-#define SUCCESS (0)
-
-/** Evaulates to error_info.code as lvalue */
-#define ERROR_CODE(err_info_ptr) ((err_info_ptr)->code)
-
-/** Evaulates to error_info.extra as lvalue */
-#define ERROR_EXTRA(err_info_ptr) ((err_info_ptr)->extra)
-
-/** Set error_info.code to SUCCESS, evaulates as zero */
-#define RESET_ERROR(err_info_ptr) ((err_info_ptr)->code = SUCCESS)
-
-/** Compare error_info.code != 0 */
-#define IS_ERROR(err_info_ptr) (!!(err_info_ptr)->code)
-
-/** Compare the err_code/err_extra for an err_info */
-#define MATCH_ERROR(err_info_ptr, err_code, err_extra) ((err_info_ptr)->code == (err_code) && (err_info_ptr)->extra == (err_extra))
-
-/** Set error_info.code, but leave err_extra as-is. Evaluates to err_code */
-#define SET_ERROR(err_info_ptr, err_code) ((err_info_ptr)->code = (err_code))
-
-/** Set error_info.code/extra. XXX: should evaluate to err_code */
-#define _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra = (err_extra)
-#define SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); } while (0)
-
-/** Set error_info.code to err_code, and .extra to errno. XXX: should evaulate to err_code */
-#define _SET_ERROR_ERRNO(err_info_ptr, err_code) _SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
-#define SET_ERROR_ERRNO(err_info_ptr, err_code) SET_ERROR_EXTRA(err_info_ptr, err_code, errno);
-
-/**
- * Set error_info.code to err_code, and .extra_str to str. The given string pointer should remain valid while the error
- * is being handled down-stack.
- */
-#define _SET_ERROR_STR(err_info_ptr, err_code, err_str) (err_info_ptr)->code = (err_code); (err_info_ptr)->extra_str = (err_str)
-#define SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); } while(0)
-
-/** Set error_info from another error_info. Evaluates to the new error_info */
-#define SET_ERROR_INFO(err_info_ptr, from_ptr) (*err_info_ptr = *from_ptr)
-
-/** Same as above, but also return err_code from func. XXX: use 'return SET_ERROR...' instead */
-#define RETURN_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); return (err_code); } while (0)
-#define RETURN_SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); return (err_code); } while (0)
-#define RETURN_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); return (err_code); } while (0)
-#define RETURN_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); return (from_ptr->code); } while (0)
-#define RETURN_SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); return (err_code); } while (0)
-
-/** Same as above, but also do a 'goto error' */
-#define JUMP_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); goto error; } while (0)
-#define JUMP_SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); goto error; } while (0)
-#define JUMP_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); goto error; } while (0)
-#define JUMP_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); goto error; } while (0)
-#define JUMP_SET_ERROR_STR(err_info_ptr, err_code, err_str) do { _SET_ERROR_STR(err_info_ptr, err_code, err_str); goto error; } while (0)
-
-/**
- * Macro used to mark code segments that should never be executed (e.g. switch-default), kind of like assert
- */
-#include <stdlib.h>
-#define NOT_REACHED(val) abort()
-
-#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/error.c Wed May 27 23:07:00 2009 +0300
@@ -0,0 +1,226 @@
+#include "error.h"
+#include "log.h"
+
+const struct error_type* error_lookup_code (const struct error_list *list, err_t code)
+{
+ const struct error_type *type;
+
+ // find matching code
+ for (type = list->list; type->code; type++) {
+ if (type->code == code)
+ // found
+ return type;
+ }
+
+ // not found
+ return NULL;
+}
+
+const struct error_type* error_lookup (const error_t *err)
+{
+ struct error_item *item;
+ struct error_type *type = NULL, *list;
+
+ // traverse stack
+ for (item = err->cur; item && item >= err->stack; item--) {
+ if (!list)
+ // initial type
+ list = item->list;
+
+ // verify list/type
+ if (!list)
+ log_warn("Uknown type");
+
+ else if (!(type = error_lookup_code(list, item->code)))
+ log_warn("Uknown code %#04x for list %s", item->code, list->name);
+
+ else
+ // expected list for next item
+ list = type->sublist;
+ }
+
+ // return what we found
+ return type;
+}
+
+const char* error_name (const error_t *err)
+{
+ struct error_type *type;
+
+ // just do a lookup
+ if ((type = error_lookup(err)))
+ return "[unknown]";
+
+ else
+ return type->name;
+}
+
+const char* error_msg (const error_t *err)
+{
+ // XXX: bad to have a single buffer
+ static char buf[ERROR_MSG_MAX];
+
+ char *buf_ptr = buf;
+ size_t buf_size = sizeof(buf);
+
+ struct error_item *item;
+ struct error_type *type;
+
+ // traverse stack
+ for (item = err->cur; item && item >= err->stack; item--) {
+ if (!list)
+ // initial lookup table
+ list = item->list;
+
+ // verify list/type
+ if (!list) {
+ // no type info at all
+ buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, "[%#04x]", item->code));
+
+ } else if (!(type = error_lookup_code(list, item->code))) {
+ // couldn't find code in list
+ buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, "[%s:%#02x]", list->name, item->code));
+
+ } else {
+ // found code's type
+ // delimit using colons, except at the end
+ buf_ptr += str_advance(&buf_size, NULL, str_append(buf_ptr, buf_size, "[%s] %s%s",
+ list->name, type->name, item == err->stack ? "" : ": "
+ ));
+
+ // expected list for next item
+ list = type->sublist;
+ }
+ }
+
+ // add info for extra
+ if (err->extra_type != type->extra_type) {
+ // type mismatch
+ buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, ": [error_extra type mismatch: %s <=> %s",
+ err->extra_type ? err->extra_type->name : NULL,
+ item->extra_type ? item->extra_type->name : NULL
+ ));
+
+ } else if (err->extra_type) {
+ // add extra info
+ buf_ptr += str_advance(&buf_size, NULL, str_append_fmt(buf_ptr, buf_size, ": %s",
+ err->extra_type->msg_func(item->extra_type, &item->extra_value)
+ ));
+
+ }
+
+ // ok, return message
+ return buf;
+}
+
+bool error_cmp_eq (const error_t *a, const error_t *b)
+{
+ // XXX: implement
+ return true;
+}
+
+/**
+ * Advance error stack to next position, and return pointer.
+ *
+ * Returns NULL if the stack runs out of space.
+ */
+struct error_item* error_next (error_t *err)
+{
+ if (!err->cur)
+ // initial position
+ return (err->cur = err->stack);
+
+ else if (err->cur < err->stack + ERR_DEPTH_MAX)
+ return (err->cur++);
+
+ else
+ return NULL;
+}
+
+void error_set (error_t *err, const struct error_list *list, err_t code)
+{
+ struct error_item *item;
+
+ // empty
+ error_reset(err);
+
+ // next
+ if (!(item = error_next(err)))
+ return;
+
+ // store
+ item->code = code;
+ item->list = list;
+}
+
+void error_set_extra (error_t *err, const struct error_list *list, err_t code, const struct error_extra_type *type, union error_extra extra)
+{
+ struct error_item *item;
+
+ // empty
+ error_reset(err);
+
+ // next
+ if (!(item = error_next(err)))
+ return;
+
+ // store
+ item->code = code;
+ item->list = list;
+ err->extra_type = type;
+ err->extra_value = extra;
+}
+
+void error_push (error_t *err, const struct error_list *list, err_t code)
+{
+ struct error_item *item;
+
+ // next
+ if (!(item = error_next(err)))
+ return;
+
+ // store
+ item->code = code;
+ item->list = list;
+}
+
+void error_copy (error_t *dst, const error_t *src)
+{
+ struct error_item *item;
+
+ // reset
+ error_reset(dst);
+
+ // copy each item
+ for (item = src->stack; src->cur && item <= src->cur; item++)
+ // push it on separately
+ error_push(dst, item->list, item->code);
+
+ // store extra
+ dst->extra_type = src->extra_type;
+ dst->extra_value = src->extra_value;
+}
+
+/*
+ * Weird trickery to call log_msg_va2 with the fmt's in the right order (prefix).
+ *
+ * XXX: log should provide similar functionality
+ */
+void _error_abort_ (const char *fmt2, va_list fmtargs2, const char *fmt1, ...)
+{
+ va_list vargs;
+
+ va_start(vargs, fmt1);
+ _log_msg_va2(LOG_FATAL, "error_abort", fmt1, vargs, fmt2, fmtargs2);
+ va_end(vargs);
+}
+
+void _error_abort (const char *file, const char *line, const char *func, const char *fmt, ...)
+{
+ va_list vargs;
+
+ va_start(vargs, fmt);
+ _error_abort_(fmt, vargs, "%s:%d[%s]", file, line, func);
+ va_end(vargs);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/error.h Wed May 27 23:07:00 2009 +0300
@@ -0,0 +1,278 @@
+#ifndef LIBQMSK_ERROR_H
+#define LIBQMSK_ERROR_H
+
+/**
+ * @file
+ *
+ * Support for error handling, using explicit function return codes and error info contexts.
+ *
+ * This is designed to support multiple "namespaces" of errors, which are entirely independent of eachother. These
+ * namespaces can then reference one another, to build a 'tree' of useable error codes. Hence, each 'level' of this
+ * tree has it's own set of error codes, and then error info contexts contain a stack of these error codes, which can
+ * then be used to trace the error down.
+ */
+
+/**
+ * The type used to represent a scalar error code, there are only unique per level.
+ *
+ * Note that this type is signed to avoid nastyness with negating error codes, but all valid ERR_* codes are *always*
+ * greater than zero in value.
+ */
+typedef signed short err_t;
+
+/**
+ * Standardized err_t code to mean no error, evaluates as logical false.
+ */
+static const err_t SUCCESS = 0;
+
+/**
+ * Extra information about an error, used to reference error codes in external libraries etc.
+ */
+union error_extra {
+ /** (signed) integer code */
+ int int_;
+
+ /** Constant string */
+ const char *str;
+};
+
+/**
+ * Errors can contain 'extra' information to reference things like error codes from external libraries; when these are
+ * used, a 'type' must be specified to handle these.
+ */
+struct error_extra_type {
+ /** Short name */
+ const char *name;
+
+ /** Conversion func, must return a static pointer */
+ const char * (*msg_func) (const struct error_extra_type *type, const union error_extra *extra);
+};
+
+/**
+ * error_extra_type for libc errno values
+ */
+const struct error_extra_type error_extra_errno;
+
+/**
+ * error_extra_type for string error values
+ */
+const struct error_extra_type error_extra_string;
+
+/**
+ * Description of an error code
+ */
+struct error_type {
+ /** The actual code */
+ err_t code;
+
+ /** The short name of the error */
+ const char *name;
+
+ /** The type of any contained extra info */
+ const struct error_extra_type *extra_type;
+
+ /** Any linked error_code table for looking up sub-errors */
+ const struct error_list *sublist;
+};
+
+/**
+ * Helper macros to define error_type's
+ */
+#define ERROR_TYPE(code, name) \
+ { (code), (name), NULL, NULL }
+
+#define ERROR_TYPE_ERRNO(code, name) \
+ { (code), (name), &error_extra_errno, NULL }
+
+#define ERROR_TYPE_STRING(code, name) \
+ { (code), (name), &error_extra_string, NULL }
+
+#define ERROR_TYPE_CUSTOM(code, name, type) \
+ { (code), (name), (type), NULL }
+
+#define ERROR_TYPE_SUB(code, name, sub) \
+ { (code), (name), NULL, (sub) }
+
+#define ERROR_TYPE_END \
+ { 0, NULL, NULL, NULL }
+
+/**
+ * List of error types
+ */
+struct error_list {
+ /** Name of sublib */
+ const char *name;
+
+ /** The list */
+ struct error_type list[];
+};
+
+/**
+ * Helper macro to define an error_list
+ */
+#define ERROR_LIST(name, ...) \
+ { (name), __VA_ARGS__, ERROR_TYPE_END }
+
+/**
+ * Maximum number of nesting levels supported for errors
+ */
+#define ERROR_DEPTH_MAX 8
+
+/**
+ * Information about an actual error
+ */
+typedef struct error_state {
+ /** The stack of error codes */
+ struct error_item {
+ /** This level's error code */
+ err_t code;
+
+ /** Optional table for interpreting error_code, can be used instead of error_code::next */
+ const struct error_list *list;
+
+ } stack[ERROR_DEPTH_MAX];
+
+ /** Current top of stack for accumulating errors, NULL means empty stack */
+ struct error_info_level *cur;
+
+ /** Type info for external error info */
+ const struct error_extra_type *extra_type;
+
+ /** Value of external error info */
+ union error_extra extra_value;
+
+} error_t;
+
+/**
+ * Look up the error_type for the given table and scalar code.
+ */
+const struct error_type* error_lookup_code (const struct error_list *list, err_t code);
+
+/**
+ * Look up the error_type for for the given root table and error_info.
+ */
+const struct error_type* error_lookup (const error_t *err);
+
+/**
+ * Return the error name for the lowest level error in the given state's stack.
+ */
+const char* error_name (const error_t *err);
+
+/**
+ * Maximum length of messages returned by error_msg
+ */
+#define ERROR_MSG_MAX 1024
+
+/**
+ * Return a pointer to a statically allocated string describing the given full error
+ */
+const char* error_msg (const error_t *err);
+
+/**
+ * Compare the given errors for equivalency
+ */
+bool error_cmp_eq (const error_t *a, const error_t *b);
+
+
+/**
+ * Reset the given error state to an empty state
+ */
+static inline void error_reset (error_t *err)
+{
+ memset(err, 0, sizeof(*err));
+}
+
+/**
+ * Evaluates to the current top of the error stack,
+ */
+static struct error_item* error_top (const error_t *err)
+{
+ return err->cur ? err->cur : err->stack;
+}
+
+/**
+ * Evaluate to the most recent error code pushed, or SUCCESS if none
+ */
+static inline err_t error_code (error_t *err)
+{
+ return err->cur ? err->cur->code : SUCCESS;
+}
+
+/**
+ * Reset the error state, push the given initial err.
+ */
+void error_set (error_t *err, const struct error_list *list, err_t code);
+
+/**
+ * Reset, push err, and set extra.
+ */
+void error_set_extra (error_t *err, const struct error_list *list, err_t code, const struct error_extra_type *type, union error_extra extra);
+
+/**
+ * Push an additional level of error info onto the error state's stack. If it doesn't fit, XXX: it is ignored.
+ */
+void error_push (error_t *err, const struct error_list *list, err_t code);
+
+/**
+ * Copy value of error
+ */
+void error_copy (error_t *dst, const error_t *src);
+
+/** Evalutes to the lvalue representing the error code at the top of the stack */
+#define ERROR_CODE(err_state) \
+ (error_top(err_state)->code)
+
+/** Push a new error code onto the given state */
+#define PUSH_ERROR(err_state, err_list, err_code) ({ \
+ error_push(err_state, err_list, err_code); \
+ err_code; })
+
+/** Set the error to the given value */
+#define SET_ERROR(err_state, err_list, err_code) ({ \
+ error_set(err_state, err_list, err_code); \
+ err_code; })
+
+/* Helper macro to use error_set_extra */
+#define _ERROR_SET_EXTRA(err_state, err_list, err_code, err_extra_type, _err_extra_field_, err_extra_value) \
+ error_set_extra(err_state, err_list, err_code, err_extra_type, ((union error_extra) { ._err_extra_field_ = (err_extra_value)}))
+
+/** Set the error with extra info as integer */
+#define SET_ERROR_EXTRA(err_state, err_list, err_code, err_extra_type, err_extra_int) ({ \
+ _ERROR_SET_EXTRA(err_state, err_list, err_code, err_extra_type, int_, err_extra); \
+ err_code; })
+
+/** Set the error with extra info as the libc errno */
+#define SET_ERROR_ERRNO(err_state, err_list, err_code) ({ \
+ _ERROR_SET_EXTRA(err_state, err_list, err_code, &error_extra_errno, int_, errno); \
+ err_code; })
+
+/** Set the error with extra info as the given static string */
+#define SET_ERROR_STR(err_state, err_list, err_code, err_str) ({ \
+ _ERROR_SET_EXTRA(err_state, err_list, err_code, &error_extra_string, str, err_str); \
+ err_code; })
+
+/** Set the error with the contents of the given error */
+#define SET_ERROR_COPY(err_state_dst, err_state_src) ({ \
+ error_code(err_state_dst); })
+
+/** Same as above, but also do a 'goto error' jump */
+#define JUMP_PUSH_ERROR(...) do { PUSH_ERROR(__VA_ARGS__); goto error; } while (0)
+#define JUMP_SET_ERROR(...) do { SET_ERROR(__VA_ARGS__); goto error; } while (0)
+#define JUMP_SET_ERROR_EXTRA(...) do { SET_ERROR_EXTRA(__VA_ARGS__); goto error; } while (0)
+#define JUMP_SET_ERROR_ERRNO(...) do { SET_ERROR_ERRNO(__VA_ARGS__); goto error; } while (0)
+#define JUMP_SET_ERROR_STR(...) do { SET_ERROR_STR(__VA_ARGS__); goto error; } while (0)
+#define JUMP_SET_ERROR_INFO(...) do { SET_ERROR_INFO(__VA_ARGS__); goto error; } while (0)
+
+
+/**
+ * Abort execution of process with error message
+ */
+void _error_abort (const char *file, const char *line, const char *func, const char *fmt, ...);
+#define error_abort(...) _error_abort(__FILE__, __LINE__, __func__, __VA_ARGS__);
+
+/**
+ * Used to mark unexpcted conditions for switch-default. The given val must be an integer, as passed to switch
+ */
+#define NOT_REACHED(val) error_abort("%s = %#x", #val, (int) (val));
+
+#endif /* LIBQMSK_ERROR_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/str.c Wed May 27 23:07:00 2009 +0300
@@ -0,0 +1,320 @@
+#include "str.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <assert.h>
+
+const struct error_list str_errors = ERROR_LIST("str",
+ ERROR_TYPE( ERR_STR_FMT_TAG, "invalid parameter tag syntax" ),
+ ERROR_TYPE( ERR_STR_FMT_NAME_LEN, "invalid parameter name length" ),
+ ERROR_TYPE( ERR_STR_FMT_NAME, "invalid/unknown parameter name" ),
+ ERROR_TYPE( ERR_STR_FMT_FLAGS_LEN, "invalid paramter flags length" ),
+ ERROR_TYPE( ERR_STR_FMT_FLAG, "invalid paramter flag" ),
+ ERROR_TYPE( ERR_STR_FMT_BUF_LEN, "output buffer ran out" )
+);
+
+size_t str_append_num (char *buf, size_t buf_size, const char *str, ssize_t len)
+{
+ size_t str_len;
+
+ // copy the bytes
+ // len will either be >0 or <0
+ for (str_len = 0; *str && buf_size > 1 && len != 0; str_len++, buf_size--, len--)
+ *buf++ = *str++;
+
+ // count the rest
+ for (; *str && len != 0; str++, len--)
+ str_len++;
+
+ if (buf_size)
+ // NUL-terminate
+ *buf = '\0';
+
+ // ok
+ return str_len;
+
+}
+
+size_t str_append (char *buf, size_t buf_size, const char *str)
+{
+ return str_append_num(buf, buf_size, str, -1);
+}
+
+size_t str_append_char (char *buf, size_t buf_size, char c)
+{
+ if (buf_size > 1)
+ *buf++ = c;
+
+ if (buf_size > 0)
+ *buf = '\0';
+
+ return 1;
+}
+
+size_t str_append_fmt_va (char *buf, size_t buf_size, const char *fmt, va_list vargs)
+{
+ int ret;
+
+ // do the formatting
+ ret = vsnprintf(buf, buf_size, fmt, vargs);
+
+ // XXX: not all vsnprintf implementations do this
+ assert(ret >= 0);
+
+ // ok
+ return ret;
+}
+
+size_t str_append_fmt (char *buf, size_t buf_size, const char *fmt, ...)
+{
+ va_list vargs;
+ int ret;
+
+ va_start(vargs, fmt);
+ ret = str_append_fmt_va(buf, buf_size, fmt, vargs);
+ va_end(vargs);
+
+ return ret;
+}
+
+static const struct str_quote_item {
+ /** The char value to quote */
+ char c;
+
+ /** The quoted value */
+ const char *out;
+} _quote_table[] = {
+ { '\'', "\\'" },
+ { '\\', "\\\\" },
+ { '\0', "\\0" },
+ { '\r', "\\r" },
+ { '\n', "\\n" },
+ { 0, NULL }
+};
+
+size_t str_quote_char (char *buf, size_t buf_size, char c)
+{
+ const struct str_quote_item *quote_item = _quote_table;
+
+ // special quote?
+ for (quote_item = _quote_table; quote_item->c || quote_item->out; quote_item++) {
+ if (quote_item->c == c)
+ return str_append(buf, buf_size, quote_item->out);
+ }
+
+ // output directly?
+ if (isprint(c))
+ return str_append_char(buf, buf_size, c);
+
+ else
+ return str_append_fmt(buf, buf_size, "\\x%02x", c);
+}
+
+size_t str_advance (size_t *data_size, size_t *buf_size, size_t len)
+{
+ if (data_size)
+ *data_size += len;
+
+ if (len > *buf_size)
+ *buf_size = 0;
+
+ else
+ *buf_size -= len;
+
+ return len;
+}
+
+/**
+ * Number of bytes reserved by str_quote for the trailing overflow stuff
+ */
+#define STR_QUOTE_RESERVED 5
+
+size_t str_quote (char *buf, size_t buf_size, const char *str, ssize_t str_len)
+{
+ size_t data_size = 0;
+
+ // NULL?
+ if (str == NULL) {
+ return str_append(buf, buf_size, "NULL");
+
+ } else {
+ // calc length?
+ if (str_len < 0)
+ str_len = strlen(str);
+
+ // quote
+ buf += str_advance(&data_size, &buf_size, str_append_char(buf, buf_size, '\''));
+
+ // dump each char
+ while (str_len--) {
+ if (buf_size > STR_QUOTE_RESERVED) {
+ size_t char_size;
+
+ // output and count the chars
+ char_size = str_quote_char(buf, buf_size, *str++);
+
+ // if there's still enough room left, commit this and continue
+ if (buf_size > char_size && buf_size - char_size >= STR_QUOTE_RESERVED)
+ buf += str_advance(&data_size, &buf_size, char_size);
+
+ else
+ // keep the buf pointer intact, we'll overwrite it now
+ data_size += char_size;
+
+ } else {
+ // continue counting the chars, but don't output anything anymore
+ data_size += str_quote_char(NULL, 0, *str++);
+ }
+ }
+
+ // end quote
+ buf += str_advance(&data_size, &buf_size, str_append_char(buf, buf_size, '\''));
+ }
+
+ // overflow -> mark
+ if (buf_size < STR_QUOTE_RESERVED)
+ buf += str_advance(NULL, &buf_size, str_append(buf, buf_size, "..."));
+
+ // the total outputted chars
+ return data_size;
+}
+
+/**
+ * Output the data for a single parameter
+ */
+static err_t str_format_param (char **buf, size_t *buf_size, const char *name, const char *flags, str_format_cb func, void *arg)
+{
+ const char *value;
+ ssize_t value_len = -1;
+ char flag;
+ bool use_quote = false;
+ err_t err;
+
+ // look it up
+ if ((err = func(name, &value, &value_len, arg)))
+ return err;
+
+ // not found?
+ if (!value)
+ return ERR_STR_FMT_NAME;
+
+ // parse flags
+ while ((flag = *flags++)) {
+ switch (flag) {
+ case 'r':
+ // quote
+ use_quote = true;
+
+ break;
+
+ default:
+ // unknown flag
+ return ERR_STR_FMT_FLAG;
+
+ }
+ }
+
+ // output value
+ if (use_quote)
+ *buf += str_advance(NULL, buf_size, str_quote(*buf, *buf_size, value, value_len));
+
+ else
+ *buf += str_advance(NULL, buf_size, str_append_num(*buf, *buf_size, value, value_len));
+
+ // ok
+ return SUCCESS;
+}
+
+err_t str_format (char *buf, size_t buf_size, const char *format, str_format_cb func, void *arg, error_t *err)
+{
+ char name_buf[STR_FORMAT_PARAM_MAX + 1], *name_ptr;
+ size_t name_size;
+ char flags_buf[STR_FORMAT_FLAGS_MAX + 1], *flags_ptr;
+ size_t flags_size;
+ bool in_param = false, in_param_flags = false;
+
+ // iterate over the format string
+ do {
+ // check buffer state
+ if (!buf_size)
+ return SET_ERROR(err, &str_errors, ERR_STR_FMT_BUF_LEN);
+
+ // inspect this char
+ switch (*format) {
+ case '{':
+ // syntax
+ if (in_param)
+ return SET_ERROR(err, &str_errors, ERR_STR_FMT_TAG);
+
+ // init state
+ in_param = true;
+ name_ptr = name_buf;
+ name_size = sizeof(name_buf);
+ flags_ptr = flags_buf;
+ flags_size = sizeof(flags_buf);
+
+ *name_ptr = *flags_ptr = '\0';
+
+ break;
+
+ case '}':
+ // syntax
+ if (!in_param)
+ return SET_ERROR(err, &str_errors, ERR_STR_FMT_TAG);
+
+ // reset state
+ in_param = false;
+ in_param_flags = false;
+
+ // output token
+ if (str_format_param(&buf, &buf_size, name_buf, flags_buf, func, arg, err))
+ return error_code(err);
+
+ break;
+
+ case ':':
+ if (in_param) {
+ // set state
+ in_param_flags = true;
+
+ break;
+ }
+
+ /* Fallthrough */
+
+ default:
+ if (in_param && in_param_flags ) {
+ // add to param flags
+ flags_ptr += str_advance(NULL, &flags_size, str_append_char(flags_ptr, flags_size, *format));
+
+ if (!flags_size)
+ return SET_ERROR(err, &str_errors, ERR_STR_FMT_FLAGS_LEN);
+
+ } else if (in_param) {
+ // add to param name
+ name_ptr += str_advance(NULL, &name_size, str_append_char(name_ptr, name_size, *format));
+
+ if (!name_size)
+ return SET_ERROR(err, &str_errors, ERR_STR_FMT_NAME_LEN);
+
+ } else {
+ // add to output
+ buf += str_advance(NULL, &buf_size, str_append_char(buf, buf_size, *format));
+
+ }
+
+ break;
+ }
+ } while (*format++);
+
+ // syntax
+ if (in_param)
+ return SET_ERROR(err, &str_errors, ERR_STR_FMT_TAG);
+
+ // ok
+ return SUCCESS;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/str.h Wed May 27 23:07:00 2009 +0300
@@ -0,0 +1,126 @@
+#ifndef STR_H
+#define STR_H
+
+/**
+ * @file
+ *
+ * Miscellaneous string utility functions
+ */
+#include <sys/types.h>
+#include <stdarg.h>
+#include "error.h"
+
+/**
+ * Error codes
+ */
+enum str_error_code {
+ ERR_STR_NONE,
+ ERR_STR_FMT_TAG, ///< invalid parameter tag syntax
+ ERR_STR_FMT_NAME_LEN, ///< invalid parameter name length
+ ERR_STR_FMT_NAME, ///< invalid/unknown parameter name
+ ERR_STR_FMT_FLAGS_LEN, ///< invalid paramter flags length
+ ERR_STR_FMT_FLAG, ///< invalid paramter flag
+ ERR_STR_FMT_BUF_LEN, ///< output buffer ran out
+};
+
+/**
+ * Error list
+ */
+const struct error_list str_errors;
+
+/**
+ * Writes the given string into the given buffer, reading at most len bytes (or up to NUL if -1), and writing at most
+ * buf_size bytes, including the terminating NUL.
+ *
+ * Returns the number of input bytes that would have been written, not including the terminating NUL.
+ */
+size_t str_append_num (char *buf, size_t buf_size, const char *str, ssize_t len);
+
+/**
+ * Like str_append_num with len = -1.
+ *
+ * @see str_append_num()
+ */
+size_t str_append (char *buf, size_t buf_size, const char *str);
+
+/**
+ * Like str_append, but only a single char.
+ *
+ * @see str_append()
+ */
+size_t str_append_char (char *buf, size_t buf_size, char c);
+
+/**
+ * Like str_append, but using formatted input instead.
+ *
+ * @see str_append()
+ */
+size_t str_append_fmt (char *buf, size_t buf_size, const char *fmt, ...);
+
+/**
+ * Like str_append_fmt, but using a vargs list instead.
+ *
+ * @see str_append_fmt()
+ */
+size_t str_append_fmt_va (char *buf, size_t buf_size, const char *fmt, va_list vargs);
+
+/**
+ * Use str_append* to write out the quoted char value to the given buffer.
+ */
+size_t str_quote_char (char *buf, size_t buf_size, char c);
+
+/**
+ * Update data_size to add len (if given), then update buf_size to remove to min(buf_size, len), and return len.
+ *
+ * Intended to be used like:
+ * \code
+ * buf += str_advance(&data_size, &buf_size, str_append_fmt(buf, buf_size, "...", ...));
+ * \endcode
+ */
+size_t str_advance (size_t *data_size, size_t *buf_size, size_t len);
+
+/**
+ * Copy the given \a str into \buf, surrounding it with quotes and escaping any data inside.
+ *
+ * At most \a str_len bytes of input will be read, unless given as -1, whereupon str will be read up to the first \0 byte.
+ *
+ * At most \a buf_size bytes of output will be written, if the output string was truncated, it will end in '...', and a
+ * value larger than \a buf_size will be returned.
+ *
+ * As a special case, if \a str is NULL, only the string "NULL" will be output.
+ *
+ * @param buf the buffer to write the output to
+ * @param buf_size the size of the given output buffer
+ * @param str the input string
+ * @param str_len number of bytes of input to process, or -1 to use strlen()
+ * @return the total number of bytes that would have been written out, may be more than buf_size
+ */
+size_t str_quote (char *buf, size_t buf_size, const char *str, ssize_t str_len);
+
+/**
+ * Callback function used by str_format to look up a value for a parameter.
+ *
+ * @param name the name of the paramter in the format string
+ * @param value returned pointer to param value
+ * @param value_len returned param value length, or -1 for strlen
+ * @param arg the context arg given to str_format
+ * @return the parameter value, or NULL to error out
+ */
+typedef err_t (*str_format_cb) (const char *name, const char **value, ssize_t *value_len, void *arg);
+
+/**
+ * Maximum length of a parameter name
+ */
+#define STR_FORMAT_PARAM_MAX 32
+
+/**
+ * Maximum length of a parameter flags section
+ */
+#define STR_FORMAT_FLAGS_MAX 8
+
+/**
+ * Format an output string based on the given template, filling in parameter values using a callback function.
+ */
+err_t str_format (char *buf, size_t buf_size, const char *format, str_format_cb func, void *arg, error_t *err);
+
+#endif
--- a/src/log.c Sat May 23 00:33:23 2009 +0300
+++ b/src/log.c Wed May 27 23:07:00 2009 +0300
@@ -72,7 +72,7 @@
_log_output_ctx.arg = arg;
}
-void log_output_tag (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...)
+void log_output_tag_va (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, va_list log_fmtargs)
{
char buf[LOG_MSG_MAX], *buf_ptr = buf;
size_t buf_size = sizeof(buf);
@@ -89,16 +89,21 @@
buf_ptr += str_advance(NULL, &buf_size, str_append_fmt_va(buf_ptr, buf_size, user_fmt, user_fmtargs));
// output the suffix
- if (log_fmt) {
- va_list vargs;
-
- va_start(vargs, log_fmt);
- buf_ptr += str_advance(NULL, &buf_size, str_append_fmt_va(buf_ptr, buf_size, log_fmt, vargs));
- va_end(vargs);
- }
+ if (log_fmt)
+ buf_ptr += str_advance(NULL, &buf_size, str_append_fmt_va(buf_ptr, buf_size, log_fmt, log_fmtargs));
// send it to the output func
_log_output_ctx.func(buf, _log_output_ctx.arg);
+
+}
+
+void log_output_tag (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, ...)
+{
+ va_list vargs;
+
+ va_start(vargs, log_fmt);
+ log_output_tag_va(level, tag, func, user_fmt, user_fmtargs, log_fmt, vargs);
+ va_end(vargs);
}
void _log_msg (enum log_level level, const char *func, const char *format, ...)
@@ -111,6 +116,11 @@
va_end(vargs);
}
+void _log_msg_va2 (enum log_level level, const char *func, const char *fmt1, va_list fmtargs1, const char *fmt2, va_list fmtargs2)
+{
+ log_output_tag_va(level, log_level_name(level), func, fmt1, fmtargs1, fmt2, fmtargs2);
+}
+
void _log_err (enum log_level level, err_t err, const char *func, const char *format, ...)
{
va_list vargs;
--- a/src/log.h Sat May 23 00:33:23 2009 +0300
+++ b/src/log.h Wed May 27 23:07:00 2009 +0300
@@ -63,6 +63,11 @@
__attribute__ ((format (printf, 6, 7)));
/**
+ * va_list version of log_output_tag
+ */
+void log_output_tag_va (enum log_level level, const char *tag, const char *func, const char *user_fmt, va_list user_fmtargs, const char *log_fmt, va_list log_fmtargs);
+
+/**
* Log a message with the given level
*/
#define log_msg(level, ...) _log_msg(level, __func__, __VA_ARGS__)
@@ -70,6 +75,13 @@
__attribute__ ((format (printf, 3, 4)));
/**
+ * Log a message with the given level with the given format and varargs
+ */
+#define log_msg_va2(level, fmt1, vargs1, fmt2, vargs2) _log_msg_va(level, __func__, fmt1, vargs1, fmt2, vargs2)
+void _log_msg_va2 (enum log_level level, const char *func, const char *fmt1, va_list fmtargs1, const char *fmt2, va_list fmtargs2);
+
+
+/**
* Shorthand for log_msg
*/
#define log_debug(...) log_msg(LOG_DEBUG, __VA_ARGS__)
--- a/src/str.c Sat May 23 00:33:23 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,311 +0,0 @@
-#include "str.h"
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdbool.h>
-
-#include <assert.h>
-
-size_t str_append_num (char *buf, size_t buf_size, const char *str, ssize_t len)
-{
- size_t str_len;
-
- // copy the bytes
- // len will either be >0 or <0
- for (str_len = 0; *str && buf_size > 1 && len != 0; str_len++, buf_size--, len--)
- *buf++ = *str++;
-
- // count the rest
- for (; *str && len != 0; str++, len--)
- str_len++;
-
- if (buf_size)
- // NUL-terminate
- *buf = '\0';
-
- // ok
- return str_len;
-
-}
-
-size_t str_append (char *buf, size_t buf_size, const char *str)
-{
- return str_append_num(buf, buf_size, str, -1);
-}
-
-size_t str_append_char (char *buf, size_t buf_size, char c)
-{
- if (buf_size > 1)
- *buf++ = c;
-
- if (buf_size > 0)
- *buf = '\0';
-
- return 1;
-}
-
-size_t str_append_fmt_va (char *buf, size_t buf_size, const char *fmt, va_list vargs)
-{
- int ret;
-
- // do the formatting
- ret = vsnprintf(buf, buf_size, fmt, vargs);
-
- // XXX: not all vsnprintf implementations do this
- assert(ret >= 0);
-
- // ok
- return ret;
-}
-
-size_t str_append_fmt (char *buf, size_t buf_size, const char *fmt, ...)
-{
- va_list vargs;
- int ret;
-
- va_start(vargs, fmt);
- ret = str_append_fmt_va(buf, buf_size, fmt, vargs);
- va_end(vargs);
-
- return ret;
-}
-
-static const struct str_quote_item {
- /** The char value to quote */
- char c;
-
- /** The quoted value */
- const char *out;
-} _quote_table[] = {
- { '\'', "\\'" },
- { '\\', "\\\\" },
- { '\0', "\\0" },
- { '\r', "\\r" },
- { '\n', "\\n" },
- { 0, NULL }
-};
-
-size_t str_quote_char (char *buf, size_t buf_size, char c)
-{
- const struct str_quote_item *quote_item = _quote_table;
-
- // special quote?
- for (quote_item = _quote_table; quote_item->c || quote_item->out; quote_item++) {
- if (quote_item->c == c)
- return str_append(buf, buf_size, quote_item->out);
- }
-
- // output directly?
- if (isprint(c))
- return str_append_char(buf, buf_size, c);
-
- else
- return str_append_fmt(buf, buf_size, "\\x%02x", c);
-}
-
-size_t str_advance (size_t *data_size, size_t *buf_size, size_t len)
-{
- if (data_size)
- *data_size += len;
-
- if (len > *buf_size)
- *buf_size = 0;
-
- else
- *buf_size -= len;
-
- return len;
-}
-
-/**
- * Number of bytes reserved by str_quote for the trailing overflow stuff
- */
-#define STR_QUOTE_RESERVED 5
-
-size_t str_quote (char *buf, size_t buf_size, const char *str, ssize_t str_len)
-{
- size_t data_size = 0;
-
- // NULL?
- if (str == NULL) {
- return str_append(buf, buf_size, "NULL");
-
- } else {
- // calc length?
- if (str_len < 0)
- str_len = strlen(str);
-
- // quote
- buf += str_advance(&data_size, &buf_size, str_append_char(buf, buf_size, '\''));
-
- // dump each char
- while (str_len--) {
- if (buf_size > STR_QUOTE_RESERVED) {
- size_t char_size;
-
- // output and count the chars
- char_size = str_quote_char(buf, buf_size, *str++);
-
- // if there's still enough room left, commit this and continue
- if (buf_size > char_size && buf_size - char_size >= STR_QUOTE_RESERVED)
- buf += str_advance(&data_size, &buf_size, char_size);
-
- else
- // keep the buf pointer intact, we'll overwrite it now
- data_size += char_size;
-
- } else {
- // continue counting the chars, but don't output anything anymore
- data_size += str_quote_char(NULL, 0, *str++);
- }
- }
-
- // end quote
- buf += str_advance(&data_size, &buf_size, str_append_char(buf, buf_size, '\''));
- }
-
- // overflow -> mark
- if (buf_size < STR_QUOTE_RESERVED)
- buf += str_advance(NULL, &buf_size, str_append(buf, buf_size, "..."));
-
- // the total outputted chars
- return data_size;
-}
-
-/**
- * Output the data for a single parameter
- */
-static err_t str_format_param (char **buf, size_t *buf_size, const char *name, const char *flags, str_format_cb func, void *arg)
-{
- const char *value;
- ssize_t value_len = -1;
- char flag;
- bool use_quote = false;
- err_t err;
-
- // look it up
- if ((err = func(name, &value, &value_len, arg)))
- return err;
-
- // not found?
- if (!value)
- return ERR_STR_FMT_NAME;
-
- // parse flags
- while ((flag = *flags++)) {
- switch (flag) {
- case 'r':
- // quote
- use_quote = true;
-
- break;
-
- default:
- // unknown flag
- return ERR_STR_FMT_FLAG;
-
- }
- }
-
- // output value
- if (use_quote)
- *buf += str_advance(NULL, buf_size, str_quote(*buf, *buf_size, value, value_len));
-
- else
- *buf += str_advance(NULL, buf_size, str_append_num(*buf, *buf_size, value, value_len));
-
- // ok
- return SUCCESS;
-}
-
-err_t str_format (char *buf, size_t buf_size, const char *format, str_format_cb func, void *arg)
-{
- char name_buf[STR_FORMAT_PARAM_MAX + 1], *name_ptr;
- size_t name_size;
- char flags_buf[STR_FORMAT_FLAGS_MAX + 1], *flags_ptr;
- size_t flags_size;
- bool in_param = false, in_param_flags = false;
- err_t err;
-
- // iterate over the format string
- do {
- // check buffer state
- if (!buf_size)
- return ERR_STR_FMT_BUF_LEN;
-
- // inspect this char
- switch (*format) {
- case '{':
- // syntax
- if (in_param)
- return ERR_STR_FMT_TAG;
-
- // init state
- in_param = true;
- name_ptr = name_buf;
- name_size = sizeof(name_buf);
- flags_ptr = flags_buf;
- flags_size = sizeof(flags_buf);
-
- *name_ptr = *flags_ptr = '\0';
-
- break;
-
- case '}':
- // syntax
- if (!in_param)
- return ERR_STR_FMT_TAG;
-
- // reset state
- in_param = false;
- in_param_flags = false;
-
- // output token
- if ((err = str_format_param(&buf, &buf_size, name_buf, flags_buf, func, arg)))
- return err;
-
- break;
-
- case ':':
- if (in_param) {
- // set state
- in_param_flags = true;
-
- break;
- }
-
- /* Fallthrough */
-
- default:
- if (in_param && in_param_flags ) {
- // add to param flags
- flags_ptr += str_advance(NULL, &flags_size, str_append_char(flags_ptr, flags_size, *format));
-
- if (!flags_size)
- return ERR_STR_FMT_FLAGS_LEN;
-
- } else if (in_param) {
- // add to param name
- name_ptr += str_advance(NULL, &name_size, str_append_char(name_ptr, name_size, *format));
-
- if (!name_size)
- return ERR_STR_FMT_NAME_LEN;
-
- } else {
- // add to output
- buf += str_advance(NULL, &buf_size, str_append_char(buf, buf_size, *format));
-
- }
-
- break;
- }
- } while (*format++);
-
- // syntax
- if (in_param)
- return ERR_STR_FMT_TAG;
-
- // ok
- return SUCCESS;
-}
--- a/src/str.h Sat May 23 00:33:23 2009 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-#ifndef STR_H
-#define STR_H
-
-/**
- * @file
- *
- * Miscellaneous string utility functions
- */
-#include <sys/types.h>
-#include <stdarg.h>
-#include "error.h"
-
-/**
- * Error codes
- */
-enum str_error_code {
- _ERR_STR_BEGIN = _ERR_STR,
- ERR_STR_FMT_TAG, ///< invalid parameter tag syntax
- ERR_STR_FMT_NAME_LEN, ///< invalid parameter name length
- ERR_STR_FMT_NAME, ///< invalid/unknown parameter name
- ERR_STR_FMT_FLAGS_LEN, ///< invalid paramter flags length
- ERR_STR_FMT_FLAG, ///< invalid paramter flag
- ERR_STR_FMT_BUF_LEN, ///< output buffer ran out
-};
-
-/**
- * Writes the given string into the given buffer, reading at most len bytes (or up to NUL if -1), and writing at most
- * buf_size bytes, including the terminating NUL.
- *
- * Returns the number of input bytes that would have been written, not including the terminating NUL.
- */
-size_t str_append_num (char *buf, size_t buf_size, const char *str, ssize_t len);
-
-/**
- * Like str_append_num with len = -1.
- *
- * @see str_append_num()
- */
-size_t str_append (char *buf, size_t buf_size, const char *str);
-
-/**
- * Like str_append, but only a single char.
- *
- * @see str_append()
- */
-size_t str_append_char (char *buf, size_t buf_size, char c);
-
-/**
- * Like str_append, but using formatted input instead.
- *
- * @see str_append()
- */
-size_t str_append_fmt (char *buf, size_t buf_size, const char *fmt, ...);
-
-/**
- * Like str_append_fmt, but using a vargs list instead.
- *
- * @see str_append_fmt()
- */
-size_t str_append_fmt_va (char *buf, size_t buf_size, const char *fmt, va_list vargs);
-
-/**
- * Use str_append* to write out the quoted char value to the given buffer.
- */
-size_t str_quote_char (char *buf, size_t buf_size, char c);
-
-/**
- * Update data_size to add len (if given), then update buf_size to remove to min(buf_size, len), and return len.
- *
- * Intended to be used like:
- * \code
- * buf += str_advance(&data_size, &buf_size, str_append_fmt(buf, buf_size, "...", ...));
- * \endcode
- */
-size_t str_advance (size_t *data_size, size_t *buf_size, size_t len);
-
-/**
- * Copy the given \a str into \buf, surrounding it with quotes and escaping any data inside.
- *
- * At most \a str_len bytes of input will be read, unless given as -1, whereupon str will be read up to the first \0 byte.
- *
- * At most \a buf_size bytes of output will be written, if the output string was truncated, it will end in '...', and a
- * value larger than \a buf_size will be returned.
- *
- * As a special case, if \a str is NULL, only the string "NULL" will be output.
- *
- * @param buf the buffer to write the output to
- * @param buf_size the size of the given output buffer
- * @param str the input string
- * @param str_len number of bytes of input to process, or -1 to use strlen()
- * @return the total number of bytes that would have been written out, may be more than buf_size
- */
-size_t str_quote (char *buf, size_t buf_size, const char *str, ssize_t str_len);
-
-/**
- * Callback function used by str_format to look up a value for a parameter.
- *
- * @param name the name of the paramter in the format string
- * @param value returned pointer to param value
- * @param value_len returned param value length, or -1 for strlen
- * @param arg the context arg given to str_format
- * @return the parameter value, or NULL to error out
- */
-typedef err_t (*str_format_cb) (const char *name, const char **value, ssize_t *value_len, void *arg);
-
-/**
- * Maximum length of a parameter name
- */
-#define STR_FORMAT_PARAM_MAX 32
-
-/**
- * Maximum length of a parameter flags section
- */
-#define STR_FORMAT_FLAGS_MAX 8
-
-/**
- * Format an output string based on the given template, filling in parameter values using a callback function.
- */
-err_t str_format (char *buf, size_t buf_size, const char *format, str_format_cb func, void *arg);
-
-#endif