Mercurial > mplayer.hg
annotate cfgparser.c @ 320:5427ff3e2e9d
status
author | szabii |
---|---|
date | Mon, 09 Apr 2001 21:06:54 +0000 |
parents | 452453f82bfa |
children | e24fe1b5b918 |
rev | line source |
---|---|
147 | 1 /* |
2 * command line and config file parser | |
3 */ | |
4 | |
5 //#define DEBUG | |
6 | |
7 #include <stdlib.h> | |
8 #include <stdio.h> | |
9 #include <ctype.h> | |
10 #include <unistd.h> | |
11 #include <fcntl.h> | |
12 #include <string.h> | |
13 | |
14 #define ERR_NOT_AN_OPTION -1 | |
15 #define ERR_MISSING_PARAM -2 | |
16 #define ERR_OUT_OF_RANGE -3 | |
150 | 17 #define ERR_FUNC_ERR -4 |
147 | 18 |
19 #define COMMAND_LINE 0 | |
20 #define CONFIG_FILE 1 | |
21 | |
177 | 22 #define MAX_RECURSION_DEPTH 8 |
166 | 23 |
147 | 24 #ifdef DEBUG |
25 #include <assert.h> | |
26 #endif | |
27 | |
28 #include "cfgparser.h" | |
29 | |
30 static struct config *config; | |
31 static int nr_options; /* number of options in 'conf' */ | |
32 static int parser_mode; /* COMMAND_LINE or CONFIG_FILE */ | |
166 | 33 static int recursion_depth = 0; |
147 | 34 |
35 static int init_conf(struct config *conf, int mode) | |
36 { | |
37 #ifdef DEBUG | |
38 assert(conf != NULL); | |
39 #endif | |
40 | |
41 /* calculate the number of options in 'conf' */ | |
42 for (nr_options = 0; conf[nr_options].name != NULL; nr_options++) | |
43 /* NOTHING */; | |
44 | |
45 config = conf; | |
46 #ifdef DEBUG | |
47 if (mode != COMMAND_LINE && mode != CONFIG_FILE) { | |
150 | 48 printf("init_conf: wrong mode!\n"); |
147 | 49 return -1; |
50 } | |
51 #endif | |
52 parser_mode = mode; | |
53 return 1; | |
54 } | |
55 | |
56 static int read_option(char *opt, char *param) | |
57 { | |
58 int i; | |
195 | 59 long tmp_int; |
60 double tmp_float; | |
160 | 61 int ret = -1; |
195 | 62 char *endptr; |
147 | 63 |
64 for (i = 0; i < nr_options; i++) { | |
65 if (!strcasecmp(opt, config[i].name)) | |
66 break; | |
67 } | |
160 | 68 if (i == nr_options) { |
69 printf("invalid option:\n"); | |
70 ret = ERR_NOT_AN_OPTION; | |
71 goto out; | |
72 } | |
73 if (config[i].flags & CONF_NOCFG && parser_mode == CONFIG_FILE) { | |
74 printf("this option can only be used on command line:\n"); | |
75 ret = ERR_NOT_AN_OPTION; | |
76 goto out; | |
77 } | |
78 if (config[i].flags & CONF_NOCMD && parser_mode == COMMAND_LINE) { | |
79 printf("this option can only be used in config file:\n"); | |
80 ret = ERR_NOT_AN_OPTION; | |
81 goto out; | |
82 } | |
150 | 83 |
147 | 84 switch (config[i].type) { |
85 case CONF_TYPE_FLAG: | |
86 /* flags need a parameter in config file */ | |
87 if (parser_mode == CONFIG_FILE) { | |
88 if (!strcasecmp(param, "yes") || /* any other language? */ | |
89 !strcasecmp(param, "ja") || | |
161
9008302e2dc0
Added support for spanish (Yes, I'm a C programer also ;o)
telenieko
parents:
160
diff
changeset
|
90 !strcasecmp(param, "si") || |
147 | 91 !strcasecmp(param, "igen") || |
92 !strcasecmp(param, "y") || | |
93 !strcasecmp(param, "i") || | |
94 !strcmp(param, "1")) | |
95 *((int *) config[i].p) = config[i].max; | |
151 | 96 else if (!strcasecmp(param, "no") || |
147 | 97 !strcasecmp(param, "nein") || |
98 !strcasecmp(param, "nicht") || | |
99 !strcasecmp(param, "nem") || | |
100 !strcasecmp(param, "n") || | |
101 !strcmp(param, "0")) | |
102 *((int *) config[i].p) = config[i].min; | |
160 | 103 else { |
104 printf("invalid parameter for flag:\n"); | |
105 ret = ERR_OUT_OF_RANGE; | |
106 goto out; | |
107 } | |
108 ret = 1; | |
147 | 109 } else { /* parser_mode == COMMAND_LINE */ |
110 *((int *) config[i].p) = config[i].max; | |
160 | 111 ret = 0; |
147 | 112 } |
113 break; | |
114 case CONF_TYPE_INT: | |
115 if (param == NULL) | |
160 | 116 goto err_missing_param; |
195 | 117 |
118 tmp_int = strtol(param, &endptr, 0); | |
119 if (*endptr) { | |
160 | 120 printf("parameter must be an integer:\n"); |
121 ret = ERR_OUT_OF_RANGE; | |
122 goto out; | |
123 } | |
147 | 124 |
153 | 125 if (config[i].flags & CONF_MIN) |
160 | 126 if (tmp_int < config[i].min) { |
127 printf("parameter must be >= %d:\n", (int) config[i].min); | |
128 ret = ERR_OUT_OF_RANGE; | |
129 goto out; | |
130 } | |
147 | 131 |
153 | 132 if (config[i].flags & CONF_MAX) |
160 | 133 if (tmp_int > config[i].max) { |
134 printf("parameter must be <= %d:\n", (int) config[i].max); | |
135 ret = ERR_OUT_OF_RANGE; | |
136 goto out; | |
137 } | |
147 | 138 |
139 *((int *) config[i].p) = tmp_int; | |
160 | 140 ret = 1; |
147 | 141 break; |
142 case CONF_TYPE_FLOAT: | |
143 if (param == NULL) | |
160 | 144 goto err_missing_param; |
195 | 145 |
146 tmp_float = strtod(param, &endptr); | |
147 if (*endptr) { | |
160 | 148 printf("parameter must be a floating point number:\n"); |
149 ret = ERR_MISSING_PARAM; | |
150 goto out; | |
151 } | |
147 | 152 |
153 | 153 if (config[i].flags & CONF_MIN) |
160 | 154 if (tmp_float < config[i].min) { |
155 printf("parameter must be >= %f:\n", config[i].min); | |
156 ret = ERR_OUT_OF_RANGE; | |
157 goto out; | |
158 } | |
147 | 159 |
153 | 160 if (config[i].flags & CONF_MAX) |
160 | 161 if (tmp_float > config[i].max) { |
162 printf("parameter must be <= %f:\n", config[i].max); | |
163 ret = ERR_OUT_OF_RANGE; | |
164 goto out; | |
165 } | |
147 | 166 |
167 *((float *) config[i].p) = tmp_float; | |
160 | 168 ret = 1; |
147 | 169 break; |
170 case CONF_TYPE_STRING: | |
171 if (param == NULL) | |
160 | 172 goto err_missing_param; |
147 | 173 |
153 | 174 if (config[i].flags & CONF_MIN) |
160 | 175 if (strlen(param) < config[i].min) { |
176 printf("parameter must be >= %d chars:\n", | |
177 (int) config[i].min); | |
178 ret = ERR_OUT_OF_RANGE; | |
179 goto out; | |
180 } | |
147 | 181 |
153 | 182 if (config[i].flags & CONF_MAX) |
160 | 183 if (strlen(param) > config[i].max) { |
184 printf("parameter must be <= %d chars:\n", | |
185 (int) config[i].max); | |
186 ret = ERR_OUT_OF_RANGE; | |
187 goto out; | |
188 } | |
147 | 189 |
190 *((char **) config[i].p) = strdup(param); | |
160 | 191 ret = 1; |
147 | 192 break; |
151 | 193 case CONF_TYPE_FUNC_PARAM: |
194 if (param == NULL) | |
160 | 195 goto err_missing_param; |
196 if ((((cfg_func_param_t) config[i].p)(config + i, param)) < 0) { | |
197 ret = ERR_FUNC_ERR; | |
198 goto out; | |
199 } | |
200 ret = 1; | |
151 | 201 break; |
150 | 202 case CONF_TYPE_FUNC: |
160 | 203 if ((((cfg_func_t) config[i].p)(config + i)) < 0) { |
204 ret = ERR_FUNC_ERR; | |
205 goto out; | |
206 } | |
207 ret = 0; | |
150 | 208 break; |
152 | 209 case CONF_TYPE_PRINT: |
210 printf("%s", (char *) config[i].p); | |
211 exit(1); | |
147 | 212 default: |
213 printf("picsaba\n"); | |
214 break; | |
215 } | |
160 | 216 out: |
217 return ret; | |
218 err_missing_param: | |
219 printf("missing parameter:\n"); | |
220 ret = ERR_MISSING_PARAM; | |
221 goto out; | |
147 | 222 } |
223 | |
224 int parse_config_file(struct config *conf, char *conffile) | |
225 { | |
226 #define PRINT_LINENUM printf("%s(%d): ", conffile, line_num) | |
227 #define MAX_LINE_LEN 1000 | |
228 #define MAX_OPT_LEN 100 | |
229 #define MAX_PARAM_LEN 100 | |
230 FILE *fp; | |
231 char *line; | |
179 | 232 char opt[MAX_OPT_LEN + 1]; |
233 char param[MAX_PARAM_LEN + 1]; | |
167 | 234 char c; /* for the "" and '' check */ |
147 | 235 int tmp; |
236 int line_num = 0; | |
237 int line_pos; /* line pos */ | |
238 int opt_pos; /* opt pos */ | |
239 int param_pos; /* param pos */ | |
240 int ret = 1; | |
241 | |
242 #ifdef DEBUG | |
243 assert(conffile != NULL); | |
244 #endif | |
166 | 245 if (++recursion_depth > MAX_RECURSION_DEPTH) { |
246 printf("too deep 'include'. check your configfiles\n"); | |
179 | 247 --recursion_depth; |
166 | 248 return -1; |
249 } | |
250 | |
147 | 251 printf("Reading config file: %s\n", conffile); |
252 | |
166 | 253 if (init_conf(conf, CONFIG_FILE) == -1) { |
254 ret = -1; | |
255 goto out; | |
256 } | |
147 | 257 |
179 | 258 if ((line = (char *) malloc(MAX_LINE_LEN + 1)) == NULL) { |
147 | 259 perror("parse_config_file: can't get memory for 'line'"); |
166 | 260 ret = -1; |
261 goto out; | |
147 | 262 } |
263 | |
264 if ((fp = fopen(conffile, "r")) == NULL) { | |
265 perror("parse_config_file: can't open filename"); | |
266 free(line); | |
166 | 267 ret = 0; |
268 goto out; | |
147 | 269 } |
270 | |
271 while (fgets(line, MAX_LINE_LEN, fp)) { | |
272 line_num++; | |
273 line_pos = 0; | |
274 | |
275 /* skip whitespaces */ | |
276 while (isspace(line[line_pos])) | |
277 ++line_pos; | |
278 | |
279 /* EOL / comment */ | |
280 if (line[line_pos] == '\0' || line[line_pos] == '#') | |
281 continue; | |
282 | |
283 /* read option. accept char if isalnum(char) */ | |
284 for (opt_pos = 0; isalnum(line[line_pos]); /* NOTHING */) { | |
285 opt[opt_pos++] = line[line_pos++]; | |
286 if (opt_pos >= MAX_OPT_LEN) { | |
287 PRINT_LINENUM; | |
288 printf("too long option\n"); | |
289 ret = -1; | |
290 continue; | |
291 } | |
292 } | |
293 if (opt_pos == 0) { | |
294 PRINT_LINENUM; | |
295 printf("parse error\n"); | |
296 ret = -1; | |
297 continue; | |
298 } | |
299 opt[opt_pos] = '\0'; | |
300 #ifdef DEBUG | |
301 PRINT_LINENUM; | |
302 printf("option: %s\n", opt); | |
303 #endif | |
304 | |
305 /* skip whitespaces */ | |
306 while (isspace(line[line_pos])) | |
307 ++line_pos; | |
308 | |
309 /* check '=' */ | |
310 if (line[line_pos++] != '=') { | |
311 PRINT_LINENUM; | |
312 printf("option without parameter\n"); | |
313 ret = -1; | |
314 continue; | |
315 } | |
316 | |
317 /* whitespaces... */ | |
318 while (isspace(line[line_pos])) | |
319 ++line_pos; | |
320 | |
321 /* read the parameter */ | |
167 | 322 if (line[line_pos] == '"' || line[line_pos] == '\'') { |
323 c = line[line_pos]; | |
324 ++line_pos; | |
325 for (param_pos = 0; line[line_pos] != c; /* NOTHING */) { | |
326 param[param_pos++] = line[line_pos++]; | |
327 if (param_pos >= MAX_PARAM_LEN) { | |
328 PRINT_LINENUM; | |
329 printf("too long parameter\n"); | |
330 ret = -1; | |
331 continue; | |
332 } | |
333 } | |
334 line_pos++; /* skip the closing " or ' */ | |
335 } else { | |
336 for (param_pos = 0; isprint(line[line_pos]) && !isspace(line[line_pos]) | |
337 && line[line_pos] != '#'; /* NOTHING */) { | |
338 param[param_pos++] = line[line_pos++]; | |
339 if (param_pos >= MAX_PARAM_LEN) { | |
340 PRINT_LINENUM; | |
341 printf("too long parameter\n"); | |
342 ret = -1; | |
343 continue; | |
344 } | |
147 | 345 } |
346 } | |
347 param[param_pos] = '\0'; | |
348 | |
349 /* did we read a parameter? */ | |
350 if (param_pos == 0) { | |
351 PRINT_LINENUM; | |
352 printf("option without parameter\n"); | |
353 ret = -1; | |
354 continue; | |
355 } | |
356 #ifdef DEBUG | |
357 PRINT_LINENUM; | |
358 printf("parameter: %s\n", param); | |
359 #endif | |
360 /* now, check if we have some more chars on the line */ | |
361 /* whitespace... */ | |
362 while (isspace(line[line_pos])) | |
363 ++line_pos; | |
364 | |
365 /* EOL / comment */ | |
366 if (line[line_pos] != '\0' && line[line_pos] != '#') { | |
367 PRINT_LINENUM; | |
368 printf("extra characters on line: %s\n", line+line_pos); | |
369 ret = -1; | |
370 } | |
371 | |
372 tmp = read_option(opt, param); | |
373 switch (tmp) { | |
374 case ERR_NOT_AN_OPTION: | |
375 case ERR_MISSING_PARAM: | |
376 case ERR_OUT_OF_RANGE: | |
150 | 377 case ERR_FUNC_ERR: |
378 PRINT_LINENUM; | |
160 | 379 printf("%s\n", opt); |
150 | 380 ret = -1; |
381 continue; | |
382 /* break */ | |
147 | 383 } |
384 } | |
385 | |
386 free(line); | |
387 fclose(fp); | |
166 | 388 out: |
389 --recursion_depth; | |
147 | 390 return ret; |
391 } | |
392 | |
393 int parse_command_line(struct config *conf, int argc, char **argv, char **envp, char **filename) | |
394 { | |
395 int i; | |
396 int found_filename = 0; | |
397 int tmp; | |
398 char *opt; | |
399 | |
400 #ifdef DEBUG | |
401 assert(argv != NULL); | |
402 assert(envp != NULL); | |
403 assert(argc >= 1); | |
404 #endif | |
405 | |
406 if (init_conf(conf, COMMAND_LINE) == -1) | |
407 return -1; | |
408 | |
409 for (i = 1; i < argc; i++) { | |
410 opt = argv[i]; | |
411 if (*opt != '-') | |
412 goto not_an_option; | |
413 | |
414 /* remove trailing '-' */ | |
415 opt++; | |
416 | |
417 tmp = read_option(opt, argv[i + 1]); | |
418 | |
419 switch (tmp) { | |
420 case ERR_NOT_AN_OPTION: | |
421 not_an_option: | |
422 /* opt is not an option -> treat it as a filename */ | |
423 if (found_filename) { | |
424 /* we already have a filename */ | |
160 | 425 goto err_out; |
147 | 426 } else { |
427 found_filename = 1; | |
428 *filename = argv[i]; | |
429 printf("parse_command_line: found filename: %s\n", *filename); | |
430 continue; /* next option */ | |
431 } | |
432 break; | |
433 case ERR_MISSING_PARAM: | |
434 case ERR_OUT_OF_RANGE: | |
150 | 435 case ERR_FUNC_ERR: |
160 | 436 goto err_out; |
150 | 437 /* break; */ |
147 | 438 } |
439 | |
440 i += tmp; /* we already processed the params (if there was any) */ | |
160 | 441 } |
147 | 442 return found_filename; |
160 | 443 err_out: |
444 printf("parse_command_line: %s\n", argv[i]); | |
445 return -1; | |
147 | 446 } |