ossp-pkg/l2/l2_ut_param.c
/*
** OSSP l2 - Flexible Logging
** Copyright (c) 2001-2005 Cable & Wireless <http://www.cw.com/>
** Copyright (c) 2001-2005 The OSSP Project <http://www.ossp.org/>
** Copyright (c) 2001-2005 Ralf S. Engelschall <rse@engelschall.com>
**
** This file is part of OSSP l2, a flexible logging library which
** can be found at http://www.ossp.org/pkg/lib/l2/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** l2_ut_param.c: parameter parsing support
*/
#include "l2.h"
#include "l2_p.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <math.h>
#include <ctype.h>
l2_result_t l2_util_setparams(l2_env_t *env, l2_param_t pa[], const char *fmt, va_list ap)
{
char *cpB, *cpE;
char *spec;
int ok;
int i;
int n;
/* argument sanity check */
if (env == NULL || pa == NULL || fmt == NULL)
return L2_ERR_ARG;
/* on-the-fly create or just take over parameter specification string */
spec = l2_util_vasprintf(fmt, ap);
/* enter the parsing loop */
cpE = spec;
while (*cpE != '\0') {
/* determine begin of parameter name */
cpB = cpE;
if ((n = strspn(cpB, " \t\r\n")) > 0)
cpB += n;
/* determine end of parameter name */
cpE = cpB;
if (!isalpha((int)*cpE)) {
l2_env_errorinfo(env, L2_ERR_ARG,
"expected alpha-numerical parameter "
"start character, got '%c'", *cpE);
return L2_ERR_ARG;
}
cpE++;
while (isalnum((int)*cpE))
cpE++;
if (*cpE != '=') {
l2_env_errorinfo(env, L2_ERR_ARG,
"expected assignment operator ('='), "
"got '%c'", *cpE);
return L2_ERR_ARG;
}
*cpE++ = '\0';
/* try to match with configured parameters */
ok = FALSE;
for (i = 0; pa[i].name != NULL; i++) {
if (strcmp(pa[i].name, cpB) == 0) {
ok = TRUE;
break;
}
}
if (!ok) {
l2_env_errorinfo(env, L2_ERR_ARG, "unknown parameter name '%s'", cpB);
return L2_ERR_ARG;
}
/* determine parameter value */
cpB = cpE;
if ((n = strspn(cpB, " \t\r\n")) > 0)
cpB += n;
if (*cpB == '"') {
cpB++;
while (1) {
cpE = cpB;
if ((cpE = strchr(cpE+1, '"')) == NULL) {
l2_env_errorinfo(env, L2_ERR_ARG, "closing quote ('\"') not found");
return L2_ERR_ARG;
}
if (*(cpE-1) != '\\')
break;
}
}
else {
cpE = cpB;
while (1) {
if ((n = strcspn(cpE, " \t\r\n,")) > 0) {
cpE += n;
if (*(cpE-1) == '\\') {
cpE++;
continue;
}
}
break;
}
}
*cpE++ = '\0';
/* store parameter value */
switch (pa[i].type) {
case L2_TYPE_INT: {
/* integer parameter */
long val;
if (strlen(cpB) > 2 && cpB[0] == '0' && cpB[1] == 'x')
val = strtol(cpB+2, &cpE, 16);
else if (strlen(cpB) > 1 && cpB[0] == '0')
val = strtol(cpB+1, &cpE, 8);
else
val = strtol(cpB, &cpE, 10);
if ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) {
l2_env_errorinfo(env, L2_ERR_ARG,
"numerical parameter value out of range "
"('%s')", cpB);
return L2_ERR_ARG;
}
if (*cpE != '\0') {
l2_env_errorinfo(env, L2_ERR_ARG,
"expected valid numerical parameter value, "
"got '%c' character", *cpE);
return L2_ERR_ARG;
}
*(int *)(pa[i].store) = (int)val;
break;
}
case L2_TYPE_FLT: {
/* floating point parameter */
double val = strtod(cpB, &cpE);
if (val == HUGE_VAL && errno == ERANGE) {
l2_env_errorinfo(env, L2_ERR_ARG,
"floating point parameter value too huge "
"('%s')", cpB);
return L2_ERR_ARG;
}
if (val == 0 && cpE == cpB) {
l2_env_errorinfo(env, L2_ERR_ARG,
"floating point parameter value conversion failed "
"('%s')", cpB);
}
if (*cpE != '\0') {
l2_env_errorinfo(env, L2_ERR_ARG,
"expected valid floating point parameter value, "
"got '%c' character", *cpE);
return L2_ERR_ARG;
}
*(float *)(pa[i].store) = (float)val;
break;
}
case L2_TYPE_STR: {
/* string parameter */
if (*(char **)(pa[i].store) != NULL)
free(*(char **)(pa[i].store));
*(char **)(pa[i].store) = strdup(cpB);
break;
}
}
/* skip delimiter */
if ((n = strspn(cpE, " \t\r\n,")) > 0)
cpE += n;
}
free(spec);
return L2_OK;
}