Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * $Id$ | |
3 * | |
4 * Copyright (C) 1&1 Internet AG | |
5 * | |
6 * This file is part of SIP-router, a free SIP server. | |
7 * | |
8 * SIP-router is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version | |
12 * | |
13 * SIP-router is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
22 | |
23 /*! | |
24 * \file parser_carrierroute.c | |
25 * \brief Functions for parsing the config file of cr when using file mode. | |
26 * \ingroup carrierroute | |
27 * - Module; \ref carrierroute | |
28 */ | |
29 | |
30 #include <stdio.h> | |
31 #include <string.h> | |
32 #include <ctype.h> | |
33 #include <stdlib.h> | |
34 #include <limits.h> | |
35 #include <float.h> | |
36 #include <math.h> | |
37 #include <errno.h> | |
38 #include "parser_carrierroute.h" | |
39 | |
40 #include "../../ut.h" | |
41 #include "../../trim.h" | |
42 | |
43 #define assert_not_null(s) do { \ | |
44 if ( NULL == (s) ){ \ | |
45 LM_INFO("Unexpected null option \n"); \ | |
46 return ERROR_IN_PARSING;\ | |
47 } \ | |
48 } while (0) | |
49 | |
50 | |
51 /** | |
52 * Gets index of given option inside option list | |
53 * | |
54 * @param opt_name name of option | |
55 * @param opt_list points to the option list | |
56 * @param no_options size of option list | |
57 * | |
58 * @return index of option inside option list, -1 not found | |
59 */ | |
60 int get_option_position(char* opt_name, option_description* opt_list, int no_opt ions){ | |
61 int i; | |
62 for (i = 0; i<no_options; i++){ | |
63 if (strcmp(opt_name, opt_list[i].name) == 0){ | |
64 return i; | |
65 } | |
66 } | |
67 return -1; | |
68 } | |
69 | |
70 | |
71 /** | |
72 * Fills special structure with params from src string | |
73 * | |
74 * @param int_list string of type {INT_VAL [, INT_VAL]*} | |
75 * @param opts destination option_description variable | |
76 * | |
77 * @return number of integers in int_list, on success | |
78 * ERROR_IN_PARSING, on error | |
79 */ | |
80 int parse_int_list(char *int_list, option_description* opts){ | |
81 char *pch, *endptr; | |
82 long val; | |
83 | |
84 pch = strtok (int_list,", \t"); | |
85 | |
86 while ( pch != NULL ) | |
87 { | |
88 LM_DBG("Parsing [%s] \n", pch); | |
89 if ( INT_LIST_MAX_SIZE == opts->no_elems){ | |
90 LM_ERR("INT LIST exceeds max allowed size of: %d \n", IN T_LIST_MAX_SIZE); | |
91 return ERROR_IN_PARSING; | |
92 } | |
93 | |
94 endptr = NULL; | |
95 val = strtol(pch, &endptr, 10); | |
96 | |
97 if ( val < 0 || val> INT_MAX){ | |
98 LM_ERR("Parsed value is out of bounds \n"); | |
99 return ERROR_IN_PARSING; | |
100 } | |
101 | |
102 if (*endptr != '\0'){ | |
103 LM_ERR("Parsed value is not integer \n"); | |
104 return ERROR_IN_PARSING; | |
105 } | |
106 | |
107 opts->value.int_list[opts->no_elems] = (int) val; | |
108 opts->no_elems ++; | |
109 pch = strtok (NULL, ", \t"); | |
110 } | |
111 | |
112 if ( 0 == opts->no_elems ){ | |
113 LM_ERR("The number of int elements cannot be 0 \n"); | |
114 return ERROR_IN_PARSING; | |
115 } | |
116 return opts->no_elems; | |
117 } | |
118 | |
119 /** | |
120 * Tries to parse right value string into an option | |
121 * | |
122 * @param src str source | |
123 * @param opt the option to be filled | |
124 * | |
125 * @return SUCCESSFUL_PARSING, ERROR_IN_PARSING | |
126 */ | |
127 int parse_rv_option(str src, option_description* opt){ | |
128 long l_val; | |
129 double d_val; | |
130 char* endptr; | |
131 int i, ret = ERROR_IN_PARSING; | |
132 | |
133 switch (opt->type) | |
134 { | |
135 case CFG_INT: | |
136 l_val = strtol(src.s, &endptr, 10); | |
137 | |
138 if (errno == ERANGE && (l_val == LONG_MAX || l_val == LO NG_MIN)) { | |
139 LM_ERR("Conversion error for %s\n", src. s); | |
140 }else | |
141 if (*endptr != '\0'){ | |
142 LM_ERR("Value is not integer \n"); | |
143 }else | |
144 if ( l_val < 0 || l_val> INT_MAX){ | |
145 LM_ERR("The number is out of bounds \n"); | |
146 } | |
147 else{// successful rv conversion | |
148 opt->value.int_data = l_val; | |
149 LM_DBG("Key=<%s>, value=<%i> \n", opt->name, opt ->value.int_data); | |
150 ret = SUCCESSFUL_PARSING; | |
151 } | |
152 break; | |
153 case CFG_FLOAT: | |
154 d_val = strtod(src.s, &endptr); | |
155 | |
156 if (errno == ERANGE && (d_val == -HUGE_VAL || d_val == H UGE_VAL)) { | |
157 LM_ERR("Conversion error for %s\n", src.s); | |
158 }else | |
159 if (*endptr != '\0'){ | |
160 LM_ERR("Value is not float \n"); | |
161 }else | |
162 if ( d_val < 0.0 || d_val> FLT_MAX){ | |
163 LM_ERR("The number is out of bounds \n"); | |
164 }else{ | |
165 opt->value.float_data = d_val; | |
166 LM_DBG("Key=<%s>, value=<%f> \n", opt->name, opt ->value.float_data); | |
167 ret = SUCCESSFUL_PARSING; | |
168 } | |
169 break; | |
170 case CFG_STR: | |
171 if ((src.s[0] != '"') && (src.s[src.len-1] != '"')){ | |
172 LM_ERR("Not a string \n"); | |
173 } | |
174 else{ | |
175 // we now expect a string with NO " inside | |
176 for (i=1; i< src.len-2; i++) | |
177 if (src.s[i] == '"') { | |
178 LM_ERR("Not a string \n"); | |
179 return ERROR_IN_PARSING; | |
180 } | |
181 strcpy( opt->value.string_data.s, src.s); | |
182 opt->value.string_data.len = src.len; | |
183 LM_DBG("String Key=<%s>, value=<%s> \n", opt->na me, opt->value.string_data.s); | |
184 ret = SUCCESSFUL_PARSING; | |
185 } | |
186 break; | |
187 case CFG_INT_LIST: | |
188 // int list looks like: lv = {NO1 [,NO]*} | |
189 if ((src.len == 2) || ((src.s[0] != '{') && (src.s[src.l en-1] != '}'))){ | |
190 LM_ERR("Not an int list \n"); | |
191 } | |
192 else{ | |
193 src.s[src.len-1]='\0';src.s++; src.len = src.len -2; | |
194 //parse a list of comma separated integers | |
195 if ( parse_int_list(src.s, opt) != ERROR_IN_PARS ING ){ | |
196 // dbg printing of parsed values | |
197 LM_DBG("The number of elements in int_li st: %d \n", opt->no_elems); | |
198 for ( i =0; i< opt->no_elems; i++ ){ | |
199 LM_DBG(" value=<%d> \n", opt->value.int_list[i]); | |
200 } | |
201 ret = SUCCESSFUL_PARSING; | |
202 } | |
203 } | |
204 break; | |
205 default: | |
206 break; | |
207 } | |
208 | |
209 opt->visited = VISITED; | |
210 return ret; | |
211 } | |
212 | |
213 /** | |
214 * Parses the options part in a file and populates a destination structure. | |
215 * The end of the options part should be signaled by end_str string. | |
216 * | |
217 * @param file pointer to source file | |
218 * @param opts destiation option structure to be populated | |
219 * @param no_options expected number of options | |
220 * @param end_str the delimiter that signals end of options zone | |
221 * | |
222 * @return SUCCESSFUL_PARSING on success, ERROR_IN_PARSING on error | |
223 */ | |
224 int parse_options(FILE* file, option_description* opts, int no_options, char* en d_str){ | |
225 str data, lv_str, rv_str; | |
226 char *pch, buf[CR_MAX_LINE_SIZE], lv[CR_MAX_LINE_SIZE], rv[CR_MAX_LINE_S IZE]; | |
227 int opt_pos, full_line_len, ret; | |
228 | |
229 ret = ERROR_IN_PARSING; | |
230 data.s = buf; | |
231 | |
232 /* refactor data.s = buf using get_non_blank_line */ | |
233 while ( get_non_blank_line( &data, CR_MAX_LINE_SIZE, file, &full_line_le n) == 0 ) /* read a line */ | |
234 { | |
235 LM_DBG("Parsing line: %.*s \n", data.len, data.s); | |
236 | |
237 /* parsing stops when end_str is reached: e.g: }, target */ | |
238 if ( strncmp(data.s, end_str, strlen(end_str)) == 0){ | |
239 LM_DBG("End of options list received \n"); | |
240 fseek(file, -full_line_len, SEEK_CUR); | |
241 ret = SUCCESSFUL_PARSING; | |
242 break; | |
243 } | |
244 | |
245 /* Line must be of type lv = rv */ | |
246 if ( (pch = strchr(data.s,'=')) == NULL){ | |
247 LM_ERR("Parsed line does not contain = delimiter \n"); | |
248 break; | |
249 } | |
250 else{ /* parse lv, rv */ | |
251 strncpy(lv, data.s, pch-data.s); lv[pch-data.s]='\0'; | |
252 strncpy(rv, pch+1, CR_MAX_LINE_SIZE-1); rv[CR_MAX_LINE_S IZE-1]='\0'; | |
253 LM_DBG("lv=%s, rv=%s\n", lv, rv); | |
254 lv_str.s=lv; lv_str.len=(int)strlen(lv); trim(&lv_str); lv_str.s[lv_str.len] = '\0'; | |
255 rv_str.s=rv; rv_str.len=(int)strlen(rv); trim(&rv_str); rv_str.s[rv_str.len] = '\0'; | |
256 | |
257 if ( (lv_str.len == 0) || (rv_str.len == 0)){ | |
258 LM_ERR("String is not lv = rv \n"); | |
259 break; | |
260 } | |
261 | |
262 /* Parsing lv */ | |
263 if ( (opt_pos = get_option_position(lv_str.s, opts, no_o ptions )) < 0){ | |
264 LM_ERR("Unexpected option received: %s \n", lv); | |
265 break; | |
266 } | |
267 | |
268 if ( VISITED == opts[opt_pos].visited ){ | |
269 LM_ERR("Duplicate option definition %s \n", opts [opt_pos].name); | |
270 break; | |
271 } | |
272 | |
273 /* Parsing rv: this is the only case the options parsing continues */ | |
274 if ( (rv_str.len != 0 ) && (parse_rv_option(rv_str, &opt s[opt_pos]) == ERROR_IN_PARSING )) | |
275 { | |
276 LM_ERR("Error in parsing rv value \n"); | |
277 break; | |
278 } | |
279 } | |
280 } | |
281 return ret; | |
282 } | |
283 | |
284 | |
285 /** | |
286 * Searches for next content line in the src file | |
287 * | |
288 * @param data the destination trimmed non blank line | |
289 * @param size maximum accepted line length | |
290 * @param file source file | |
291 * @param p_full_len initial lenght of contents line | |
292 * | |
293 * @return 0 on success, -1 on error, 1 on EOF | |
294 */ | |
295 int get_non_blank_line(str* line, int size, FILE* file, int* pFull_len ){ | |
296 char* buf = line->s; | |
297 | |
298 while ( line->s = buf, fgets( line->s, size, file) != NULL ) /* read a l ine */ | |
299 { | |
300 *pFull_len = line->len = strlen(line->s); | |
301 LM_DBG("line is %s ", line->s); | |
302 /* missing newline indicates the line length was too big */ | |
303 if ( line->s[line->len-1] != '\n' ){ | |
304 LM_ERR("Unaccepted line length \n"); | |
305 return -1; | |
306 } | |
307 trim(line); | |
308 if( line->len != 0 ){ /* we have a non blank line */ | |
309 line->s[line->len] = '\0'; /* just mark end of string*/ | |
310 return 0; | |
311 } | |
312 } | |
313 //EOF | |
314 return 1; | |
315 } | |
316 | |
317 | |
318 /** | |
319 * Parses the header of structure part in the source file and retrieves name. | |
320 * | |
321 * @param file pointer to source file | |
322 * @param expected_struct_type name of expected structure | |
323 * @param struct_name the parsed name of the structure. | |
324 * | |
325 * @return SUCCESSFUL_PARSING, EOF_REACHED, ERROR_IN_PARSING | |
326 */ | |
327 int parse_struct_header(FILE* file, char* expected_struct_type, str* struct_name ){ | |
328 str data; | |
329 char *pch; | |
330 char buf[CR_MAX_LINE_SIZE], name[CR_MAX_LINE_SIZE]; | |
331 char str2[CR_MAX_LINE_SIZE], format[CR_MAX_LINE_SIZE]; | |
332 int no_toks, full_line_len, ret; | |
mariuszbi
2013/11/23 20:05:24
fix indenting. Set Tab to 4 spaces. Set consistent
mariuszbi
2013/11/23 20:05:24
init ret to something different of SUCCESSFULL_PAR
| |
333 | |
334 ret = ERROR_IN_PARSING; | |
335 | |
336 data.s = buf; | |
337 if( get_non_blank_line( &data, CR_MAX_LINE_SIZE, file, &full_line_len) = = 1 ) {/* read a line */ | |
338 LM_DBG("Graceful exit out of parse struct \n"); | |
339 return EOF_REACHED; | |
340 } | |
341 | |
342 sprintf(format, " %s %%s %%s %%*s", expected_struct_type); | |
mariuszbi
2013/11/23 20:05:24
Use safer snprintf
| |
343 no_toks = sscanf(data.s, format, name, str2); | |
344 LM_DBG("no_tok=<%d>, name=<%s> , delim=<%s>\n", no_toks, name, str2); | |
345 | |
346 switch (no_toks) | |
347 { | |
mariuszbi
2013/11/23 20:05:24
Be consistent with starting new block Either { is
| |
348 /* With 1 token parsed, correct is: "domain_name" OR "domain_name{" */ | |
349 case 1: | |
350 if ( name[strlen(name)-1] == '{' ){ | |
351 if (strlen(name) > 1){ | |
352 name[strlen(name)-1]='\0'; | |
353 ret = SUCCESSFUL_PARSING; | |
354 } | |
355 else{ | |
356 LM_ERR("Domain name seems to be empty \n"); | |
357 } | |
358 } | |
359 else{ /* is the following non blank line a "{" ? */ | |
360 str new_line; | |
361 char new_line_buf[CR_MAX_LINE_SIZE]; | |
362 new_line.s = new_line_buf; | |
363 | |
364 if ( get_non_blank_line(&new_line, CR_MAX_LINE_SIZE, fil e, &full_line_len) != 0 ){ | |
365 LM_ERR("Unexpected end of file while waiting for { \n"); | |
366 }else | |
367 if ( strcmp(new_line.s, "{") != 0){ | |
368 LM_ERR("Unexpected %s token while waiting for { \n", pch); | |
mariuszbi
2013/11/23 20:05:24
pch is not written in this function, it is left un
| |
369 } | |
370 else | |
371 ret = SUCCESSFUL_PARSING; | |
372 } | |
373 break; | |
374 /* with 2 tokens parsed, the second must be "{" */ | |
375 case 2: | |
376 if (( strcmp(str2,"{") != 0) ) | |
mariuszbi
2013/11/23 20:05:24
strncmp
| |
377 LM_ERR("Wrongly formatted line: %s\n", data.s); | |
378 else | |
379 ret = SUCCESSFUL_PARSING; | |
380 break; | |
381 default: | |
382 LM_ERR("Wrong number of tokens in line: %s\n", data.s); | |
383 } | |
384 | |
385 if ( SUCCESSFUL_PARSING == ret ){ | |
386 LM_DBG( "Sucessfully parsed struct %s - <%s> header\n", expected _struct_type, name); | |
387 struct_name->len = strlen(name); | |
388 memcpy(struct_name->s, name, struct_name->len); | |
389 struct_name->s[struct_name->len]='\0'; | |
390 } | |
391 else | |
392 fseek(file, -full_line_len, SEEK_CUR); | |
393 | |
394 return ret; | |
395 } | |
396 | |
397 int parse_struct_stop(FILE* file){ | |
398 char buf[CR_MAX_LINE_SIZE]; | |
399 str data; | |
400 int full_line_len; | |
401 data.s = buf; | |
402 | |
403 if ( get_non_blank_line(&data, CR_MAX_LINE_SIZE, file, &full_line_len) = = -1 ) { | |
404 LM_INFO("EOF received \n"); | |
405 return ERROR_IN_PARSING; | |
406 } | |
407 | |
408 if (strcmp(data.s, "}") != 0){ | |
409 LM_INFO("Unexpected <%s> while waiting for } \n", data.s); | |
410 return ERROR_IN_PARSING; | |
411 } | |
412 return SUCCESSFUL_PARSING; | |
413 } | |
OLD | NEW |