summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorLuigi Rizzo <rizzo@icir.org>2007-07-17 14:32:15 +0000
committerLuigi Rizzo <rizzo@icir.org>2007-07-17 14:32:15 +0000
commit72b99a281758ca33a329c34cfebcf374abcb5e2d (patch)
tree2199112acfa0525a24f3d518d07bdc9d8f16b515 /main
parent35efc961efb80a419dd38ffc3e2880d7894db137 (diff)
Introduce ast_parse_arg() , a generic function to parse strings
in a consistent way. This is meant to replace the custom code which is repeated all over the place in the various files when parsing config files, CLI entries and other string information. Right now the code supports parsing int32, uint32 and sockaddr_in with optional default values and bound checks. It contains minimal error checking, but that can be easily extended as the need arises. Being a new API i am introducing this only in trunk, though I believe that once the interface has been ironed out it might become a worthwhile addition to 1.4 as well - basically, the first time we will need to fix a piece of argument parsing code, we might as well bring in this change and use the new API instead. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75379 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/config.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/main/config.c b/main/config.c
index 2568dc728..e9ba97fcc 100644
--- a/main/config.c
+++ b/main/config.c
@@ -37,6 +37,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
+#include <sys/socket.h> /* for AF_INET */
#define AST_INCLUDE_GLOB 1
#ifdef AST_INCLUDE_GLOB
#if defined(__Darwin__) || defined(__CYGWIN__)
@@ -1444,6 +1445,124 @@ int ast_destroy_realtime(const char *family, const char *keyfield, const char *l
return res;
}
+/*! \brief Helper function to parse arguments
+ * See documentation in config.h
+ */
+int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
+ void *p_result, ...)
+{
+ va_list ap;
+ int error = 0;
+
+ va_start(ap, p_result);
+ switch (flags & PARSE_TYPE) {
+ case PARSE_INT32:
+ {
+ int32_t *result = p_result;
+ int32_t x, def = result ? *result : 0,
+ high = (int32_t)0x7fffffff,
+ low = (int32_t)0x80000000;
+ /* optional argument: first default value, then range */
+ if (flags & PARSE_DEFAULT)
+ def = va_arg(ap, int32_t);
+ if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
+ /* range requested, update bounds */
+ low = va_arg(ap, int32_t);
+ high = va_arg(ap, int32_t);
+ }
+ x = strtol(arg, NULL, 0);
+ error = (x < low) || (x > high);
+ if (flags & PARSE_OUT_RANGE)
+ error = !error;
+ if (result)
+ *result = error ? def : x;
+ ast_debug(3,
+ "extract int from [%s] in [%d, %d] gives [%d](%d)\n",
+ arg, low, high,
+ result ? *result : x, error);
+ break;
+ }
+
+ case PARSE_UINT32:
+ {
+ uint32_t *result = p_result;
+ uint32_t x, def = result ? *result : 0,
+ low = 0, high = (uint32_t)~0;
+ /* optional argument: first default value, then range */
+ if (flags & PARSE_DEFAULT)
+ def = va_arg(ap, uint32_t);
+ if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
+ /* range requested, update bounds */
+ low = va_arg(ap, uint32_t);
+ high = va_arg(ap, uint32_t);
+ }
+ x = strtoul(arg, NULL, 0);
+ error = (x < low) || (x > high);
+ if (flags & PARSE_OUT_RANGE)
+ error = !error;
+ if (result)
+ *result = error ? def : x;
+ ast_debug(3,
+ "extract uint from [%s] in [%u, %u] gives [%u](%d)\n",
+ arg, low, high,
+ result ? *result : x, error);
+ break;
+ }
+
+ case PARSE_INADDR:
+ {
+ char *port, *buf;
+ struct sockaddr_in _sa_buf; /* buffer for the result */
+ struct sockaddr_in *sa = p_result ?
+ (struct sockaddr_in *)p_result : &_sa_buf;
+ /* default is either the supplied value or the result itself */
+ struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
+ va_arg(ap, struct sockaddr_in *) : sa;
+ struct hostent *hp;
+ struct ast_hostent ahp;
+
+ bzero(&_sa_buf, sizeof(_sa_buf)); /* clear buffer */
+ /* duplicate the string to strip away the :port */
+ port = ast_strdupa(arg);
+ buf = strsep(&port, ":");
+ sa->sin_family = AF_INET; /* assign family */
+ /*
+ * honor the ports flag setting, assign default value
+ * in case of errors or field unset.
+ */
+ flags &= PARSE_PORT_MASK; /* the only flags left to process */
+ if (port) {
+ if (flags == PARSE_PORT_FORBID) {
+ error = 1; /* port was forbidden */
+ sa->sin_port = def->sin_port;
+ } else if (flags == PARSE_PORT_IGNORE)
+ sa->sin_port = def->sin_port;
+ else /* accept or require */
+ sa->sin_port = htons(strtol(port, NULL, 0));
+ } else {
+ sa->sin_port = def->sin_port;
+ if (flags == PARSE_PORT_REQUIRE)
+ error = 1;
+ }
+ /* Now deal with host part, even if we have errors before. */
+ hp = ast_gethostbyname(buf, &ahp);
+ if (hp) /* resolved successfully */
+ memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
+ else {
+ error = 1;
+ sa->sin_addr = def->sin_addr;
+ }
+ ast_debug(3,
+ "extract inaddr from [%s] gives [%s:%d](%d)\n",
+ arg, ast_inet_ntoa(sa->sin_addr),
+ ntohs(sa->sin_port), error);
+ break;
+ }
+ }
+ va_end(ap);
+ return error;
+}
+
static int config_command(int fd, int argc, char **argv)
{
struct ast_config_engine *eng;