00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <stdlib.h>
00018 #include <stdarg.h>
00019 #include <stdio.h>
00020 #include <ctype.h>
00021 #include <string.h>
00022 #include <assert.h>
00023
00024 #include "parse_options.h"
00025
00026 #define MAX_LINE_LENGTH 4*1024
00027 #define MAX_OPTIONS 256
00028 #define MAX_FILENAME 256
00029
00030 #define OPTION 0
00031 #define ENUM_OPTION 1
00032 #define ARGUMENT 2
00033
00034 #define MIN_NAME_WIDTH 4
00035 #define MIN_TYPE_WIDTH 4
00036 #define MIN_DFLT_WIDTH 7
00037
00038 #define MAX_NAME_WIDTH 16
00039 #define MAX_TYPE_WIDTH 16
00040 #define MAX_DFLT_WIDTH 16
00041
00042 #define BUF_LEN 1024
00043
00044 #define MAX_LINE_WIDTH 70
00045
00046 #define MAX_ARGC MAX_OPTIONS
00047
00048 #define MIN(a,b) ((a)<(b)?(a):(b))
00049 #define MAX(a,b) ((a)>(b)?(a):(b))
00050
00051 static int option_class(char *name)
00052 {
00053 int cl;
00054
00055 switch(name[0]) {
00056 case '-':
00057 cl=OPTION;
00058 break;
00059 case '{':
00060 cl=ENUM_OPTION;
00061 break;
00062 default:
00063 cl=ARGUMENT;
00064 break;
00065 }
00066
00067 return cl;
00068 }
00069
00070
00071
00072
00073
00074
00075
00076 static int parse_ini_file(char *ini_filename, option_t options[], int option_found[], int nr_options);
00077
00078
00079
00080
00081
00082 static int string2int(char *s, char *set)
00083 {
00084 char *p;
00085 char *p2;
00086 unsigned int len;
00087 int pos;
00088 int i;
00089
00090
00091 p = set+1;
00092
00093 pos = -1;
00094 i=0;
00095 do {
00096 p2 = strpbrk(p,",}");
00097 assert (p2 != NULL);
00098
00099 len=p2-p;
00100 if ((strlen(s)==len) && !strncmp(s,p,len)) {
00101 pos = i;
00102 }
00103 p = p2+1;
00104 i++;
00105 } while( *p2 != '}' );
00106
00107 return pos;
00108 }
00109
00110
00111
00112
00113
00114 static char *int2string(int pos, char *set)
00115 {
00116 static char tmp[128];
00117 char *p;
00118 char *p2;
00119 unsigned int len;
00120 int i;
00121
00122
00123 p = set+1;
00124
00125 strcpy(tmp, "*ERROR*");
00126 i=0;
00127 do {
00128 p2 = strpbrk(p,",}");
00129 assert (p2 != NULL);
00130
00131 len=p2-p;
00132
00133 if (i==pos) {
00134 strncpy(tmp, p, len);
00135 tmp[len]='\0';
00136 }
00137
00138 p = p2+1;
00139 i++;
00140 } while( *p2 != '}' );
00141
00142 return tmp;
00143 }
00144
00145 static int enum_index(char *list, char *name)
00146 {
00147 int nr;
00148 char *p;
00149
00150
00151 if (list[0] == '{') {
00152 p = list+1;
00153 for(nr=0; p!=NULL; nr++) {
00154 if (!strncmp(p, name, strlen(name))) {
00155 char c = p[strlen(name)];
00156
00157 if ((c==',') || (c=='}')) {
00158 return nr;
00159 }
00160 }
00161
00162 p = strchr(p, ',');
00163 if (p!=NULL) {
00164 p++;
00165 }
00166 }
00167 }
00168
00169 return -1;
00170 }
00171
00172
00173
00174
00175
00176
00177 static void add_string(char ***list, char *s)
00178 {
00179 char **p;
00180 int i;
00181 int size;
00182 int new_size;
00183
00184
00185 p=(*list);
00186 size=0;
00187 while((*p!=NULL) && (**p!='\0')) {
00188 p++;
00189 size++;
00190 }
00191
00192 if (*p==NULL) {
00193
00194 new_size=2*(size+1);
00195 *list=(char **)realloc(*list, new_size*sizeof(char *));
00196 for(i=size; i<new_size-1; i++) {
00197 (*list)[i] = "";
00198 }
00199 (*list)[new_size-1] = NULL;
00200 p=(*list)+size;
00201 }
00202
00203 *p=s;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 static int store_strlist(char ***var_p, char *value)
00219 {
00220
00221
00222 char *tmp;
00223
00224 tmp = (char *)malloc(strlen(value)+1);
00225 if (tmp == NULL) {
00226 fprintf( stderr, "Cannot allocate memory for string...\n");
00227 exit(1);
00228 }
00229
00230 strcpy(tmp, value);
00231 add_string(var_p, tmp);
00232
00233 return 2;
00234 }
00235
00236 static int store_str(option_t option, char **var_p, char *value, char *location)
00237 {
00238
00239
00240 char *tmp;
00241 int ret;
00242
00243 if (value == NULL) {
00244 fprintf( stderr, "%sOption \"%s\" requires a string argument\n", location, option.name );
00245 return -1;
00246 }
00247
00248 if (!strncmp(option.type, "str{", 4)) {
00249 ret = string2int(value, option.type+3);
00250 if (ret < 0) {
00251 fprintf( stderr, "%sOption \"%s\" does not expect argument \"%s\"\n",
00252 location, option.name, value );
00253 return -2;
00254 }
00255 }
00256
00257 tmp = (char *)malloc(strlen(value)+1);
00258 if (tmp == NULL) {
00259 fprintf( stderr, "Cannot allocate memory for string...\n");
00260 exit(1);
00261 }
00262
00263 strcpy(tmp, value);
00264 *var_p = tmp;
00265
00266 return 2;
00267 }
00268
00269 static int store_enum(option_t option, int *var_p, char *value)
00270 {
00271 int i;
00272
00273 assert(value != NULL);
00274
00275 i = enum_index(option.name, value);
00276 assert(i>=0);
00277
00278 *var_p = i;
00279
00280 return 2;
00281 }
00282
00283 static int store_int_enum(option_t option, int *var_p, char *value, char *location)
00284 {
00285
00286
00287 int ret;
00288
00289 if (value == NULL) {
00290 fprintf( stderr, "%sOption \"%s\" requires a string argument\n", location, option.name );
00291 return -1;
00292 }
00293
00294 ret = string2int(value, option.type+3);
00295 if (ret < 0) {
00296 fprintf( stderr, "%sOption \"%s\" does not expect argument \"%s\"\n",
00297 location, option.name, value );
00298 return -2;
00299 }
00300
00301 *var_p = ret;
00302
00303 return 2;
00304 }
00305
00306 static int store_int(option_t option, int *var_p, char *value, char *location)
00307 {
00308
00309
00310 int min, max;
00311 int base;
00312 long i;
00313 unsigned long u;
00314 char *no1;
00315 char *no2;
00316 char *comma;
00317 char *bracket;
00318
00319 if (value == NULL) {
00320 base=10;
00321 i=0;
00322 u=0;
00323 }
00324 else {
00325
00326
00327
00328 base=((value[0]=='0') && (toupper(value[1])=='X')) ? 16 : 10;
00329 if (base == 10) {
00330 i=strtol(value, NULL, base);
00331 u=0;
00332 }
00333 else {
00334 u=strtoul(value, NULL, base);
00335 i=(long)u;
00336 }
00337 }
00338
00339 if (option.type[3]=='[') {
00340
00341 no1 = &option.type[4]; assert(no1 != NULL);
00342 comma = strchr(no1, ','); assert(comma != NULL);
00343 no2 = comma+1; assert(no2 != NULL);
00344 bracket = strchr(no2, ']'); assert(bracket != NULL);
00345 min = atoi(no1);
00346 max = atoi(no2);
00347
00348 if ((value == NULL) || (i<min) || (i>max)) {
00349 fprintf( stderr, "%sOption \"%s\" requires an integer argument with range [%d,%d]\n",
00350 location, option.name, min, max);
00351 return -2;
00352 }
00353 }
00354 else {
00355 if (value == NULL) {
00356 fprintf( stderr, "%sOption \"%s\" requires an integer argument\n",
00357 location, option.name);
00358 return -1;
00359 }
00360 }
00361
00362 if (base == 10) {
00363 *var_p = i;
00364 }
00365 else {
00366 *(unsigned int *)var_p = u;
00367 }
00368
00369 return 2;
00370 }
00371
00372 static int store_double(double *var_p, char *value)
00373 {
00374
00375
00376 double d;
00377
00378 d = (value == NULL) ? (double)0.0 : atof(value);
00379 *var_p = d;
00380
00381 return 2;
00382 }
00383
00384 static int store_float(float *var_p, char *value)
00385 {
00386
00387
00388 float f;
00389
00390 f = (value == NULL) ? (float)0.0 : (float)atof(value);
00391 *var_p = f;
00392
00393 return 2;
00394 }
00395
00396 static int store_char(char *var_p, char *value)
00397 {
00398
00399
00400 char c;
00401
00402 c = (value == NULL) ? 0 : *value;
00403 *var_p = c;
00404
00405 return 2;
00406 }
00407
00408 static int store_bool(int *var_p, char *value)
00409 {
00410
00411
00412 *var_p = ((value != NULL) && !strcmp(value, "true"));
00413 return 1;
00414 }
00415
00416 static int store_value(option_t option, char *value, char *location)
00417 {
00418 int ret;
00419 char *tmp;
00420 int i;
00421 int count;
00422
00423 tmp = strchr(option.type, '#');
00424 count = (tmp==NULL) ? 1 : atoi(tmp+1);
00425
00426 if (strstr(option.type, "strlist")!=NULL) {
00427 assert(count==1);
00428 ret=store_strlist(option.var, value);
00429 }
00430 else if (!strncmp(option.type, "str", 3)) {
00431 assert(count==1);
00432 ret=store_str(option, option.var, value, location);
00433 }
00434 else if (!strcmp(option.type, "enum")) {
00435 assert(count==1);
00436 ret=store_enum(option, option.var, value);
00437 }
00438 else if (!strcmp(option.type, "char")) {
00439 assert(count==1);
00440 ret=store_char(option.var, value);
00441 }
00442 else if (!strcmp(option.type, "bool") || !strcmp(option.type, "cmd")) {
00443 assert(count==1);
00444 ret=store_bool(option.var, value);
00445 }
00446 else if (!strncmp(option.type, "int", 3) || !strncmp(option.type, "double", 6) || !strncmp(option.type, "float", 5)) {
00447 tmp=value;
00448 ret=1;
00449 for(i=0; i<count; i++) {
00450 if (option.type[3] == '{') {
00451 ret=store_int_enum(option, ((int *)option.var)+i, tmp, location);
00452 }
00453 else if (option.type[0] == 'i') {
00454 ret=store_int(option, ((int *)option.var)+i, tmp, location);
00455 }
00456 else if (option.type[0] == 'd') {
00457 ret=store_double(((double *)option.var)+i, tmp);
00458 }
00459 else {
00460 ret=store_float(((float *)option.var)+i, tmp);
00461 }
00462
00463
00464 if (ret < 0) {
00465 return ret;
00466 }
00467
00468
00469 tmp=strchr(tmp, ',');
00470
00471 if (((i<count-1)&&(tmp==NULL)) || ((i==count-1)&&(tmp!=NULL))) {
00472 fprintf( stderr, "%sOption \"%s\" expects %d values\n",
00473 location, option.name, count );
00474 ret=-2;
00475 break;
00476 }
00477
00478 if (i<count-1) {
00479 tmp++;
00480 }
00481 }
00482 }
00483 else {
00484
00485 ret=0;
00486
00487 fprintf( stderr, "%sOption \"%s\" has unknown type \"%s\"\n",
00488 location, option.name, option.type );
00489 exit(1);
00490 }
00491
00492 return ret;
00493 }
00494
00495 static char *get_value(option_t *option)
00496 {
00497 static char str[1024];
00498 int i;
00499 char *p;
00500 char *p2;
00501 char **q;
00502 void *var;
00503
00504 char *p3 = strchr(option->type, '#');
00505 int count = (p3==NULL) ? 1 : atoi(p3+1);
00506
00507 var = option->var;
00508
00509
00510 str[0]='\0';
00511 while(count--) {
00512 char *end = str+strlen(str);
00513
00514 if (strstr(option->type, "strlist")) {
00515
00516 q=*(char ***)var;
00517 while(*q!=NULL) {
00518 strcpy(end+strlen(end), *q);
00519 q++;
00520 if (*q!=NULL) {
00521 strcpy(end+strlen(end), " ");
00522 }
00523 }
00524 }
00525 else if (strstr(option->type, "str")) {
00526
00527 p = *((char **)var);
00528 if (strlen(p) == 0) {
00529 strcpy(end, "\"\"");
00530 } else if (strchr(p, ' ') == NULL) {
00531 strcpy(end, p);
00532 } else {
00533 strcpy(end, "\"");
00534 strcpy(end+1, p);
00535 strcpy(end+1+strlen(p), "\"");
00536 }
00537 }
00538 else if (!strcmp(option->type, "enum")) {
00539
00540 p = option->name+1;
00541 for(i=0; i<*(int *)var; i++) {
00542 p = strchr(p, ',')+1;
00543 }
00544 p2 = strchr(p, ',');
00545 if (p2==NULL) {
00546 p2 = strchr(p, '}');
00547 }
00548 strncpy(end, p, p2-p);
00549 end[p2-p]='\0';
00550 }
00551 else if (!strncmp(option->type, "int{", 4)) {
00552 strcpy(end, int2string(*(int *)var, option->type+3));
00553 var = ((int *)var)+1;
00554 }
00555 else if (!strncmp(option->type, "int", 3)) {
00556 sprintf(end, "%d", *(int *)var);
00557 var = ((int *)var)+1;
00558 }
00559 else if (!strncmp(option->type, "double", 6)) {
00560 sprintf(end, "%6.4f", *(double *)var);
00561 var = ((double *)var)+1;
00562 }
00563 else if (!strncmp(option->type, "float", 5)) {
00564 sprintf(end, "%6.4f", *(float *)var);
00565 var = ((float *)var)+1;
00566 }
00567 else if (!strncmp(option->type, "char", 4)) {
00568 sprintf(end, "%c", *(char *)var);
00569 var = ((char *)var)+1;
00570 }
00571 else if (!strcmp(option->type, "bool")) {
00572 sprintf(end, "%s%s", *(int *)var ? "" : "-no", option->name);
00573 }
00574
00575 if (count!=0) {
00576 strcpy(end+strlen(end), ",");
00577 }
00578 }
00579
00580 return str;
00581 }
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597 static int parse_option(char *name, char *value, char *location, option_t options[], int option_found[],
00598 int nr_options)
00599 {
00600 int nr;
00601 int err;
00602 int i;
00603
00604 if ((name[0] != '-') || (name[1] == '\0')) {
00605
00606 for(i=0; i<nr_options; i++) {
00607 if ((option_class(options[i].name) == ARGUMENT) && !option_found[i]) {
00608
00609 nr=store_value(options[i],name,location);
00610 if (!strstr(options[i].type, "strlist")) {
00611 option_found[i] = 1;
00612 }
00613 return 1;
00614 }
00615 }
00616
00617 fprintf( stderr, "%sError: unexpected argument \"%s\"\n", location, name );
00618 return -1;
00619 }
00620 else if (!strcmp(name, "-ini")) {
00621 if (value != NULL) {
00622 err = parse_ini_file(value, options, option_found, nr_options);
00623 if (err) {
00624 fprintf(stderr, "Problem parsing ini-file \"%s\"\n", value);
00625 return -2;
00626 }
00627 else {
00628 return 2;
00629 }
00630 }
00631 else {
00632 fprintf( stderr, "%sOption \"%s\" requires a filename argument\n", location, name);
00633 return -1;
00634 }
00635 }
00636 else {
00637
00638 for(i=0; i != nr_options; i++) {
00639 if (enum_index(options[i].name, name)>=0) {
00640
00641 nr = store_value(options[i], name, location);
00642 option_found[i] = 1;
00643 return 1;
00644 }
00645 }
00646
00647
00648 for(i=0; i != nr_options; i++) {
00649 if (!strcmp(options[i].type, "bool") || !strcmp(options[i].type, "cmd")) {
00650 if (!strcmp(options[i].name, name)) {
00651 value = "true";
00652 }
00653 else if (!strncmp(name, "-no-", 4) && !strcmp(options[i].name, name+3)) {
00654 value = "false";
00655 }
00656 else {
00657
00658 continue;
00659 }
00660
00661 nr = store_value(options[i], value, location);
00662 option_found[i] = 1;
00663 return nr;
00664 }
00665 }
00666
00667
00668 for(i=0; i != nr_options; i++) {
00669 if (!strcmp(options[i].name, name)) {
00670 nr = store_value(options[i], value, location);
00671 if (nr != 0) {
00672 if (nr>0) {
00673 option_found[i] = 1;
00674 }
00675 return nr;
00676 }
00677 }
00678 }
00679 }
00680
00681 fprintf( stderr, "%sError: unrecognized option \"%s\"\n", location, name );
00682 return -1;
00683 }
00684
00685
00686
00687
00688
00689 static void remove_comment(char *s)
00690 {
00691 char *ch = s + strlen(s) - 1;
00692
00693
00694 if (*ch == '\n')
00695 *ch = '\0';
00696
00697
00698 ch = strchr(s, '#');
00699 if (ch != NULL)
00700 *ch = '\0';
00701
00702 }
00703
00704
00705
00706
00707
00708 static void remove_tabs(char *s)
00709 {
00710 char *ch = s + strlen(s) - 1;
00711
00712
00713 while (ch >= s) {
00714 if (*ch == '\t')
00715 *ch = ' ';
00716 ch--;
00717 }
00718 }
00719
00720
00721
00722
00723
00724 static void remove_leading_spaces(char *s)
00725 {
00726 char *ch = s;
00727
00728
00729 while (*ch == ' ')
00730 ch++;
00731
00732
00733 if (ch != s) {
00734 while (*ch != '\0')
00735 *s++ = *ch++;
00736 *s = '\0';
00737 }
00738 }
00739
00740
00741
00742
00743
00744 static void remove_trailing_spaces(char *s)
00745 {
00746 char *end = s + strlen(s) - 1;
00747
00748
00749 while ((end > s) && (*end == ' ')) {
00750 *end = '\0';
00751 end--;
00752 }
00753 }
00754
00755
00756
00757
00758
00759 static void remove_eqsign_spaces(char *s)
00760 {
00761 char *eqsign, *chleft, *chright;
00762
00763
00764 eqsign = strchr(s, '=');
00765 if (eqsign != NULL) {
00766
00767 chright = eqsign + 1;
00768 while (*chright == ' ')
00769 chright++;
00770
00771
00772 chleft = eqsign - 1;
00773 while ((*chleft == ' ') && (chleft >= s))
00774 chleft--;
00775
00776
00777 chleft++;
00778 *chleft++ = '=';
00779 while (*chright != '\0')
00780 *chleft++ = *chright++;
00781 *chleft = '\0';
00782 }
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796 static int parse_ini_file(char *ini_filename, option_t options[], int option_found[],
00797 int nr_options)
00798 {
00799 char buf[MAX_LINE_LENGTH];
00800 char location[MAX_FILENAME];
00801 FILE *f;
00802 int line;
00803 char *name, *value;
00804 char *p;
00805 char *name_ptr, *val_ptr;
00806 char name_val, val_val;
00807 int nr;
00808 int runin;
00809 int winfmt;
00810 int arguments;
00811 char *eqsign;
00812 char arg[MAX_FILENAME+40];
00813
00814 f = fopen(ini_filename, "r");
00815 if (f == NULL) {
00816 return -1;
00817 }
00818
00819 line = 1;
00820 runin = 1;
00821 winfmt = 0;
00822 arguments = 0;
00823 while( fgets(buf, MAX_LINE_LENGTH-1, f), !feof(f) ) {
00824 sprintf(location, "%s:%d ", ini_filename, line++);
00825
00826 remove_comment(buf);
00827 remove_tabs(buf);
00828 remove_leading_spaces(buf);
00829 remove_trailing_spaces(buf);
00830
00831 if (runin) {
00832
00833 if (*buf != '\0') {
00834
00835 if ((buf[0] == '[') && (buf[strlen(buf)-1] == ']')) {
00836 winfmt = 1;
00837 }
00838
00839 runin = 0;
00840 }
00841 }
00842
00843 if (winfmt) {
00844
00845
00846
00847 remove_eqsign_spaces(buf);
00848
00849 if (!strcmp(buf, "[arguments]")) {
00850 arguments = 1;
00851 } else if (*buf == '[') {
00852 arguments = 0;
00853 if (strchr(buf, ']') == NULL) {
00854 fprintf(stderr, "%sError: missing closing bracket\n", location);
00855 fclose(f);
00856 return 1;
00857 }
00858 if (*(strchr(buf, ']') + 1) != '\0') {
00859 fprintf(stderr, "%sError: illegal syntax\n", location);
00860 fclose(f);
00861 return 1;
00862 }
00863 } else if (*buf != '\0') {
00864 eqsign = strchr(buf, '=');
00865 if (eqsign == buf) {
00866 fprintf(stderr, "%sError: missing option name\n", location);
00867 fclose(f);
00868 return 1;
00869 }
00870 if (eqsign == NULL) {
00871 fprintf(stderr, "%sError: missing '='\n", location);
00872 fclose(f);
00873 return 1;
00874 }
00875
00876 if (arguments) {
00877
00878 value = eqsign + 1;
00879 nr = parse_option(value, NULL, location, options, option_found, nr_options);
00880 if (nr<=0) {
00881 fclose(f);
00882 return 1;
00883 }
00884 } else {
00885
00886 *eqsign = '\0';
00887 name = buf;
00888 value = eqsign + 1;
00889
00890
00891 if (*value != '\0') {
00892
00893 strcpy(arg, "-");
00894
00895
00896 if (!strcmp(value, "true") || !strcmp(value, "false")) {
00897
00898 if (!strcmp(value, "false"))
00899 strcat(arg, "no-");
00900
00901
00902 strcat(arg, name);
00903
00904
00905 nr = parse_option(arg, NULL, location, options, option_found, nr_options);
00906 if (nr<=0) {
00907 fclose(f);
00908 return 1;
00909 }
00910 }
00911 else {
00912
00913 strcat(arg, name);
00914
00915 if ((value[0] == '"') && (value[strlen(value)-1] == '"')) {
00916
00917 value++;
00918 value[strlen(value)-1] = '\0';
00919 }
00920 nr = parse_option(arg, value, location, options, option_found, nr_options);
00921 if (nr<=0) {
00922 fclose(f);
00923 return 1;
00924 }
00925 }
00926 }
00927 }
00928 }
00929
00930 } else {
00931
00932
00933
00934 name = buf;
00935 do {
00936 name_ptr = val_ptr = name;
00937 name_val = val_val = *name;
00938
00939 value = NULL;
00940 while((*name) && isspace((int)*name))
00941 name++;
00942
00943 p = name;
00944 while((*p) && !isspace((int)*p))
00945 p++;
00946
00947 if (*p) {
00948
00949 name_ptr = p;
00950 name_val = *p;
00951 *p = '\0';
00952
00953 value = p+1;
00954 while((*value) && isspace((int)*value))
00955 value++;
00956
00957
00958 if (*value == '"') {
00959 value++;
00960 p = value;
00961 while((*p) && (*p != '"')) {
00962 p++;
00963 }
00964 if (*p == '"') {
00965 val_ptr = p;
00966 val_val = *p;
00967 *p = '\0';
00968 }
00969 } else {
00970 p = value;
00971 while((*p) && !isspace((int)*p))
00972 p++;
00973 if (*p) {
00974
00975 val_ptr = p;
00976 val_val = *p;
00977 *p = '\0';
00978 }
00979 }
00980
00981 if (*value == '\0') {
00982 value = NULL;
00983 }
00984 }
00985
00986 if (name[0] == '\0') {
00987 name = NULL;
00988 }
00989
00990 if (name != NULL) {
00991 nr = parse_option(name, value, location, options, option_found, nr_options);
00992 if (nr<=0) {
00993 fclose(f);
00994 return 1;
00995 }
00996 switch (nr) {
00997 case 1:
00998
00999 name = value;
01000 break;
01001 case 2:
01002
01003 name = value + strlen(value) + 1;
01004 break;
01005 default:
01006 name = NULL;
01007 break;
01008 }
01009 }
01010 *name_ptr = name_val;
01011 *val_ptr = val_val;
01012 } while (name != NULL);
01013 }
01014 }
01015
01016 fclose(f);
01017 return 0;
01018 }
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032 static int parse_cmd_line(int argc, char *argv[], option_t options[], int option_found[],
01033 int nr_options )
01034 {
01035 int nr;
01036
01037 argv++;
01038 argc--;
01039 while(argc>0) {
01040 nr = parse_option(argv[0], argc>0 ? argv[1] : NULL, "", options, option_found, nr_options);
01041 if (nr<=0) {
01042 return 1;
01043 }
01044
01045 argv += nr;
01046 argc -= nr;
01047 }
01048
01049 return 0;
01050 }
01051
01052
01053
01054
01055
01056 static void build_ini_filename(char *ini_filename, char *appl_name)
01057 {
01058 int i, j=0;
01059
01060
01061
01062 for (i=0; appl_name[i]!='\0'; i++) {
01063 if (appl_name[i] == ' ')
01064 ini_filename[j++] = '_';
01065 else
01066 if (appl_name[i] != '-')
01067 ini_filename[j++] = appl_name[i];
01068 }
01069 sprintf(&ini_filename[j], ".ini");
01070
01071 }
01072
01073
01074
01075
01076
01077
01078 static int print(FILE *f, char **s, int *len, char *fmt, ...)
01079 {
01080 int n;
01081 char buf[BUF_LEN];
01082
01083 va_list ap;
01084 va_start(ap, fmt);
01085 n=vsprintf(buf, fmt, ap);
01086 va_end(ap);
01087
01088 if (f != NULL) {
01089 fprintf(f, "%s", buf);
01090 }
01091 else {
01092 if (*len>n) {
01093 strcpy(*s, buf);
01094 *s+=n;
01095 *len-=n;
01096 }
01097 else {
01098 n=0;
01099 }
01100 }
01101
01102 return n;
01103 }
01104
01105
01106
01107
01108
01109
01110 static int gen_print_options(FILE *f, char *s, int len, char *appl_name, option_t options[])
01111 {
01112 option_t *option;
01113 unsigned int name_width=MIN_NAME_WIDTH;
01114 unsigned int type_width=MIN_TYPE_WIDTH;
01115 unsigned int dflt_width=MIN_DFLT_WIDTH;
01116 int bools_present;
01117 char ini_filename[MAX_FILENAME];
01118
01119 bools_present=0;
01120 for(option=options;option->name!=NULL; option++) {
01121 if (strlen(option->name)<MAX_NAME_WIDTH) {
01122 name_width = MAX(name_width, strlen(option->name));
01123 }
01124 if (strlen(option->type)<MAX_TYPE_WIDTH) {
01125 type_width = MAX(type_width, strlen(option->type));
01126 }
01127 if ((option->default_value!=NULL) && (strlen(option->default_value)<MAX_DFLT_WIDTH)) {
01128 dflt_width = MAX(dflt_width, strlen(option->default_value));
01129 }
01130 if (!strcmp(option->type, "bool")) {
01131 bools_present=1;
01132 }
01133 }
01134
01135 if (!print(f, &s, &len, "Usage: %s [options]", appl_name)) return 0;
01136 for(option=options;option->name!=NULL; option++) {
01137 if (option_class(option->name) == ARGUMENT) {
01138 if (!print(f, &s, &len, " %s", option->name)) return 0;
01139 }
01140 }
01141 if (!print(f, &s, &len, "\n\n")) return 0;
01142
01143 if (!print(f, &s, &len, " %-*s %-*s %-*s %s\n",
01144 name_width, "name",
01145 type_width, "type",
01146 dflt_width, "default",
01147 "help text")) return 0;
01148
01149 if (!print(f, &s, &len, " %-*s %-*s %-*s %s\n",
01150 name_width, "----",
01151 type_width, "----",
01152 dflt_width, "-------",
01153 "---------")) return 0;
01154
01155 if (!print(f, &s, &len, " %-*s %-*s %-*s %s\n",
01156 name_width, "-ini",
01157 type_width, "str",
01158 dflt_width, "",
01159 "Parse options from an ini-file")) return 0;
01160
01161 option=options;
01162 while(option->name != NULL) {
01163 if (!print(f, &s, &len, " ")) return 0;
01164 if (!print(f, &s, &len, "%-*s", name_width, option->name)) return 0;
01165 if (strlen(option->name)>name_width) {
01166 if (!print(f, &s, &len, "\n %-*s", name_width, "")) return 0;
01167 }
01168
01169 if (!print(f, &s, &len, " ")) return 0;
01170 if (!print(f, &s, &len, "%-*s", type_width, option->type)) return 0;
01171 if (strlen(option->type)>type_width) {
01172 if (!print(f, &s, &len, "\n %-*s %-*s", name_width, "", type_width, "")) return 0;
01173 }
01174
01175 if (!print(f, &s, &len, " ")) return 0;
01176 if (option->default_value != NULL) {
01177 if (!print(f, &s, &len, "%-*s", dflt_width, option->default_value)) return 0;
01178 }
01179 else {
01180 if (!print(f, &s, &len, "%-*s", dflt_width, "")) return 0;
01181 }
01182
01183 if (!print(f, &s, &len, " ")) return 0;
01184 if (!print(f, &s, &len, "%s", option->help)) return 0;
01185 if (!print(f, &s, &len, "\n")) return 0;
01186
01187 option++;
01188 }
01189
01190 build_ini_filename(ini_filename, appl_name);
01191 if (!print(f, &s, &len, "Processing order: defaults, optional %s file, cmdline args\n", ini_filename)) return 0;
01192
01193 if (bools_present) {
01194 if (!print(f, &s, &len, "Note: for boolean options you can specify \"-opt\" and \"-no-opt\"\n")) return 0;
01195 }
01196
01197 return 1;
01198 }
01199
01200
01201
01202
01203
01204 int sprint_options(char *s, int len, char *appl_name, option_t options[])
01205 {
01206 return gen_print_options(NULL, s, len, appl_name, options);
01207 }
01208
01209 int fprint_options(FILE *f, char *appl_name, option_t options[])
01210 {
01211 return gen_print_options(f, NULL, 0, appl_name, options);
01212 }
01213
01214 int print_options(char *appl_name, option_t options[])
01215 {
01216 return gen_print_options(stdout, NULL, 0, appl_name, options);
01217 }
01218
01219
01220
01221
01222
01223
01224 static int gen_print_option_values(FILE *f, char *s, int len, char *prefix, option_t options[])
01225 {
01226 option_t *option;
01227 unsigned int name_width=MIN_NAME_WIDTH;
01228 unsigned int line_len=MAX_LINE_WIDTH;
01229 unsigned int n;
01230 char buf[BUF_LEN];
01231
01232 memset(buf, 0, BUF_LEN);
01233
01234 for(option=options;option->name!=NULL; option++) {
01235 if (strlen(option->name)<MAX_NAME_WIDTH) {
01236 name_width = MAX(name_width, strlen(option->name));
01237 }
01238 }
01239
01240 line_len -= print(f, &s, &len, "%s", prefix);
01241
01242 for (option=options; option->name != NULL; option++) {
01243 if (!strcmp(option->type, "cmd")) {
01244
01245 continue;
01246 }
01247
01248 strcpy(buf, " ");
01249 if ((option_class(option->name) == OPTION) && strcmp(option->type, "bool")) {
01250 sprintf(buf+strlen(buf), "%s ", option->name);
01251 }
01252 sprintf(buf+strlen(buf), "%s", get_value(option));
01253 n=strlen(buf);
01254 if ((s==NULL) && (line_len<n)) {
01255 line_len=MAX_LINE_WIDTH-n;
01256 if (!print(f, &s, &len, "\n")) return 0;
01257 } else {
01258 line_len-=n;
01259 }
01260
01261 if (!print(f, &s, &len, "%s", buf)) return 0;
01262 }
01263
01264 if (s==NULL) {
01265 if (!print(f, &s, &len, "\n")) return 0;
01266 }
01267
01268 return 1;
01269 }
01270
01271
01272
01273
01274
01275 int sprint_option_values(char *s, int len, char *prefix, option_t options[])
01276 {
01277 return gen_print_option_values(NULL, s, len, prefix, options);
01278 }
01279
01280 int fprint_option_values(FILE *f, char *prefix, option_t options[])
01281 {
01282 return gen_print_option_values(f, NULL, 0, prefix, options);
01283 }
01284
01285 int print_option_values(char *prefix, option_t options[])
01286 {
01287 return gen_print_option_values(stdout, NULL, 0, prefix, options);
01288 }
01289
01290
01291
01292
01293
01294 int parse_options(char *appl_name, int argc, char *argv[], option_t options[])
01295 {
01296 int i, j, n;
01297 int err;
01298 int nr_options;
01299 option_t *option;
01300 int option_found[MAX_OPTIONS];
01301 char ini_filename[MAX_FILENAME];
01302 char **strlist;
01303
01304 nr_options = 0;
01305 option=options;
01306 while(option->name != NULL) {
01307 nr_options++;
01308 option++;
01309 }
01310
01311
01312
01313 for(i=0; i != nr_options; i++) {
01314 char *def = options[i].default_value;
01315
01316 if (strstr(options[i].type, "strlist")) {
01317 char **list=(char **)malloc(2*sizeof(char *));
01318 list[0] = "";
01319 list[1] = NULL;
01320
01321 *(char ***)options[i].var = list;
01322 option_found[i] = 0;
01323 }
01324 else if (!strcmp(options[i].type, "bool") || !strcmp(options[i].type, "cmd")) {
01325
01326 *(int *)options[i].var = ((def != NULL) && !strcmp(def, "true"));
01327 option_found[i] = (def != NULL);
01328 }
01329 else if (options[i].default_value != NULL) {
01330 (void)store_value(options[i], def, "INTERNALPROBLEM: ");
01331 option_found[i] = (option_class(options[i].name) != ARGUMENT);
01332 }
01333 else {
01334
01335 option_found[i] = 0;
01336 }
01337 }
01338
01339 build_ini_filename(ini_filename, appl_name);
01340 err = parse_ini_file(ini_filename, options, option_found, nr_options);
01341 if (err>0) {
01342 return 1;
01343 }
01344
01345 err = parse_cmd_line(argc, argv, options, option_found, nr_options);
01346 if (err) {
01347 return 1;
01348 }
01349
01350
01351
01352
01353
01354
01355
01356
01357 for(i=0; i<nr_options; i++) {
01358 if (strstr(options[i].type, "strlist")) {
01359
01360 strlist=*((char ***)options[i].var);
01361 for(n=0; strlist[n]!=NULL; n++) {
01362
01363 if (strlist[n][0]=='\0') {
01364 strlist[n]=NULL;
01365 break;
01366 }
01367 }
01368
01369 for(j=nr_options-1; j>i; j--) {
01370 if (option_class(options[j].name)==ARGUMENT) {
01371
01372 if (n>0) {
01373 n--;
01374 *((char **)options[j].var)=strlist[n];
01375 strlist[n]=NULL;
01376 option_found[j]=1;
01377 }
01378 }
01379 }
01380
01381 option_found[i]=(strcmp(options[i].type, "strlist") || (n>0));
01382 break;
01383 }
01384 }
01385
01386
01387 for(i=0; i != nr_options; i++) {
01388 if (option_found[i] && !strcmp(options[i].type, "cmd")) {
01389 err=0;
01390 for(j=i+1; j!=nr_options; j++) {
01391 if (option_found[j] && !strcmp(options[j].type, "cmd")) {
01392
01393 fprintf(stderr, "Only one command option is allowed\n");
01394 err=1;
01395 }
01396 }
01397 return err;
01398 }
01399 }
01400
01401
01402 err=0;
01403 for(i=0; i != nr_options; i++) {
01404 if (!option_found[i] && strcmp(options[i].type, "cmd") && options[i].default_value==NULL) {
01405 err = 1;
01406 switch(option_class(options[i].name)) {
01407 case ARGUMENT:
01408 fprintf( stderr, "Mandatory argument \"%s\" missing\n", options[i].name );
01409 break;
01410 case OPTION:
01411 fprintf( stderr, "Mandatory option \"%s\" missing\n", options[i].name );
01412 break;
01413 case ENUM_OPTION:
01414 fprintf( stderr, "Mandatory option from \"%s\" missing\n", options[i].name );
01415 break;
01416 default:
01417 fprintf( stderr, "Internal error, invalid option_class(\"%s\") return value\n", options[i].name );
01418 break;
01419 }
01420 }
01421 }
01422 return err;
01423 }