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