1 /*
2 **  OSSP l2 - Flexible Logging
3 **  Copyright (c) 2001-2005 Cable & Wireless <http://www.cw.com/>
4 **  Copyright (c) 2001-2005 The OSSP Project <http://www.ossp.org/>
5 **  Copyright (c) 2001-2005 Ralf S. Engelschall <rse@engelschall.com>
6 **
7 **  This file is part of OSSP l2, a flexible logging library which
8 **  can be found at http://www.ossp.org/pkg/lib/l2/.
9 **
10 **  Permission to use, copy, modify, and distribute this software for
11 **  any purpose with or without fee is hereby granted, provided that
12 **  the above copyright notice and this permission notice appear in all
13 **  copies.
14 **
15 **  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
16 **  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 **  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
19 **  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 **  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 **  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
22 **  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 **  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 **  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 **  SUCH DAMAGE.
27 **
28 **  l2_ut_param.c: parameter parsing support
29 */
30 
31 #include "l2.h"
32 #include "l2_p.h"
33 
34 #include <stdlib.h>
35 #include <string.h>
36 #include <limits.h>
37 #include <math.h>
38 #include <ctype.h>
39 
l2_util_setparams(l2_env_t * env,l2_param_t pa[],const char * fmt,va_list * ap)40 l2_result_t l2_util_setparams(l2_env_t *env, l2_param_t pa[], const char *fmt, va_list *ap)
41 {
42     char *cpB, *cpE;
43     char *spec;
44     int ok;
45     int i;
46     int n;
47 
48     /* argument sanity check */
49     if (env == NULL || pa == NULL || fmt == NULL)
50         return L2_ERR_ARG;
51 
52     /* on-the-fly create or just take over parameter specification string */
53     spec = l2_util_vasprintf(fmt, ap);
54 
55     /* enter the parsing loop */
56     cpE = spec;
57     while (*cpE != '\0') {
58         /* determine begin of parameter name */
59         cpB = cpE;
60         if ((n = strspn(cpB, " \t\r\n")) > 0)
61             cpB += n;
62 
63         /* determine end of parameter name */
64         cpE = cpB;
65         if (!isalpha((int)*cpE)) {
66             l2_env_errorinfo(env, L2_ERR_ARG,
67                              "expected alpha-numerical parameter "
68                              "start character, got '%c'", *cpE);
69             return L2_ERR_ARG;
70         }
71         cpE++;
72         while (isalnum((int)*cpE))
73             cpE++;
74         if (*cpE != '=') {
75             l2_env_errorinfo(env, L2_ERR_ARG,
76                              "expected assignment operator ('='), "
77                              "got '%c'", *cpE);
78             return L2_ERR_ARG;
79         }
80         *cpE++ = '\0';
81 
82         /* try to match with configured parameters */
83         ok = FALSE;
84         for (i = 0; pa[i].name != NULL; i++) {
85             if (strcmp(pa[i].name, cpB) == 0) {
86                 ok = TRUE;
87                 break;
88             }
89         }
90         if (!ok) {
91             l2_env_errorinfo(env, L2_ERR_ARG, "unknown parameter name '%s'", cpB);
92             return L2_ERR_ARG;
93         }
94 
95         /* determine parameter value */
96         cpB = cpE;
97         if ((n = strspn(cpB, " \t\r\n")) > 0)
98             cpB += n;
99         if (*cpB == '"') {
100             cpB++;
101             while (1) {
102                 cpE = cpB;
103                 if ((cpE = strchr(cpE+1, '"')) == NULL) {
104                     l2_env_errorinfo(env, L2_ERR_ARG, "closing quote ('\"') not found");
105                     return L2_ERR_ARG;
106                 }
107                 if (*(cpE-1) != '\\')
108                     break;
109             }
110         }
111         else {
112             cpE = cpB;
113             while (1) {
114                 if ((n = strcspn(cpE, " \t\r\n,")) > 0) {
115                     cpE += n;
116                     if (*(cpE-1) == '\\') {
117                         cpE++;
118                         continue;
119                     }
120                 }
121                 break;
122             }
123         }
124         *cpE++ = '\0';
125 
126         /* store parameter value */
127         switch (pa[i].type) {
128             case L2_TYPE_INT: {
129                 /* integer parameter */
130                 long val;
131                 if (strlen(cpB) > 2 && cpB[0] == '0' && cpB[1] == 'x')
132                     val = strtol(cpB+2, &cpE, 16);
133                 else if (strlen(cpB) > 1 && cpB[0] == '0')
134                     val = strtol(cpB+1, &cpE, 8);
135                 else
136                     val = strtol(cpB, &cpE, 10);
137                 if ((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) {
138                     l2_env_errorinfo(env, L2_ERR_ARG,
139                                      "numerical parameter value out of range "
140                                      "('%s')", cpB);
141                     return L2_ERR_ARG;
142                 }
143                 if (*cpE != '\0') {
144                     l2_env_errorinfo(env, L2_ERR_ARG,
145                                      "expected valid numerical parameter value, "
146                                      "got '%c' character", *cpE);
147                     return L2_ERR_ARG;
148                 }
149                 *(int *)(pa[i].store) = (int)val;
150                 break;
151             }
152             case L2_TYPE_FLT: {
153                 /* floating point parameter */
154                 double val = strtod(cpB, &cpE);
155                 if (val == HUGE_VAL && errno == ERANGE) {
156                     l2_env_errorinfo(env, L2_ERR_ARG,
157                                      "floating point parameter value too huge "
158                                      "('%s')", cpB);
159                     return L2_ERR_ARG;
160                 }
161                 if (val == 0 && cpE == cpB) {
162                     l2_env_errorinfo(env, L2_ERR_ARG,
163                                      "floating point parameter value conversion failed "
164                                      "('%s')", cpB);
165                 }
166                 if (*cpE != '\0') {
167                     l2_env_errorinfo(env, L2_ERR_ARG,
168                                      "expected valid floating point parameter value, "
169                                      "got '%c' character", *cpE);
170                     return L2_ERR_ARG;
171                 }
172                 *(float *)(pa[i].store) = (float)val;
173                 break;
174             }
175             case L2_TYPE_STR: {
176                 /* string parameter */
177                 if (*(char **)(pa[i].store) != NULL)
178                     free(*(char **)(pa[i].store));
179                 *(char **)(pa[i].store) = strdup(cpB);
180                 break;
181             }
182         }
183 
184         /* skip delimiter */
185         if ((n = strspn(cpE, " \t\r\n,")) > 0)
186             cpE += n;
187     }
188 
189     free(spec);
190 
191     return L2_OK;
192 }
193 
194