options.c
Go to the documentation of this file.
00001 #ifdef LINUX
00002 
00003 #ifndef _GNU_SOURCE
00004 #define _GNU_SOURCE
00005 #endif
00006 
00007 /* for realpath() */
00008 #ifndef __USE_BSD
00009 #define __USE_BSD
00010 #endif
00011 
00012 #endif /* LINUX */
00013 
00014 #include <errno.h>
00015 #include <limits.h>
00016 #include <stdlib.h>
00017 #include <stdio.h>
00018 #include <sys/param.h>
00019 #include <ctype.h>
00020 #include <sys/stat.h>
00021 #include <unistd.h>
00022 #include <libgen.h>
00023 #include <string.h>
00024 
00025 #include "options.h"
00026 
00027 
00028 void display_table(FILE*f,  char**table, int rows, int columns, int padding);
00029 
00030 
00031 const char * options_banner_string = "";
00032 
00033 void options_banner(const char*message) {
00034         options_banner_string = message;
00035 }
00036 
00038 char * strdup_(const char *s) {
00039         size_t len = strlen(s) + 1; /* null byte */
00040         char * t = (char*) malloc(len);
00041         memcpy(t,s,len);
00042         return t;
00043 }
00044 
00045 
00047 int get_int(int*p, const char*s) {
00048         int value;
00049         errno = 0;
00050         value = strtol(s, (char **)NULL, 10);
00051         if(0 == errno) {
00052                 *p = value;
00053                 return 1;
00054         } else return 0;
00055 }
00056 
00058 int get_double(double*p, const char*s) {
00059         char *endptr;
00060         *p = strtod(s, &endptr);
00061         return endptr != s;
00062 }
00063 
00064 int options_tolerant = 0;
00065 
00066 int options_parse_args(struct option*ops, int argc, const char* argv[]) {
00067         int i;
00068         for (i=1; i<argc; i++) {
00069                 const char * name = argv[i];
00070                 while(*name == '-') name++;
00071                 
00072                 if(!strcmp("config_dump", name)) {
00073                         options_dump(ops, stdout, 0);
00074                         exit(0);
00075                 }
00076                 
00077                 if(!strcmp("help",name) || !strcmp("h",name) ) {
00078                         options_print_help(ops, stdout);
00079                         exit(0);
00080                 }
00081                 
00082                 if(!strcmp("config", name)) {
00083                         if(i>=argc-1) {
00084                                 fprintf(stderr, "Please specify config file.\n");
00085                                 if(!options_tolerant) return 0;
00086                         }
00087                         if(!options_parse_file(ops, ".", argv[i+1])) {
00088                                 if(!options_tolerant) return 0;
00089                         }
00090                         i++;
00091                         continue;
00092                 }
00093                 
00094                 struct option * o;
00095                 if(0 == (o =options_find(ops, name)) ) {
00096                         fprintf(stderr, "Option '%s' not found (use -help to get list of options).\n", name);
00097                         if(!options_tolerant) return 0;
00098                 }
00099 
00100                 options_set_passed(o);
00101                 if(options_requires_argument(o)) {
00102                         if(i>=argc-1) {
00103                                 fprintf(stderr, "Argument %s needs value.\n", o->name);
00104                                 if(!options_tolerant) return 0;
00105                         }
00106                         if(!options_set(o, argv[i+1])) {
00107                                 if(!options_tolerant) return 0;
00108                         }
00109                         i++;
00110                 } 
00111 
00112         } /* for */
00113         
00114         return 1;
00115 }
00116 
00117 
00118 
00120 void options_set_passed(struct option*o) {
00121         if(o->set_pointer) 
00122                 *(o->set_pointer) = 1;
00123 }
00124 
00126 int options_requires_argument(struct option*o) {
00127         return o->value_pointer != 0;
00128 }
00129 
00130 
00131 int options_parse_stream(struct option*ops, const char*pwd, FILE*file) {
00132         #define MAX_LINE_LENGTH 10000
00133         char linesto[MAX_LINE_LENGTH];
00134         while(fgets(linesto, MAX_LINE_LENGTH-1, file)) {
00135                 char *line=linesto; while(*line) { if(*line=='\n') *line=0; line++; }
00136                 line = linesto;
00137                 while(isspace(*line)) line++;
00138                 if(*line == '#') continue;
00139                 if(*line == '<') { line++;
00140                         while(isspace(*line)) line++;
00141                         if(!options_parse_file(ops, pwd, line)) {
00142                                 if(!options_tolerant) return 0;
00143                         }
00144                         continue;
00145                 }
00146                 if(!*line) continue;
00147                 /* Here starts the name; later we put a terminating 0 */
00148                 const char * name = line;
00149                 /* name continus until nonspace char */
00150                 while(!isspace(*line)) line++;
00151 
00152                 char empty[5] = "";
00153                 char * value;
00154                 if(*line == 0) value = empty; else {
00155                         *line = 0; /* terminating 0 for name */
00156                         line++;
00157                         /* ignore spaces */
00158                         while(isspace(*line)) line++;
00159                         /* ignore possible "=" */
00160                         if(*line == '=') line++;
00161                         /* ignore spaces */
00162                         while(isspace(*line)) line++;
00163 
00164                         /* here starts the value */
00165                         value = line;
00166                         /* delete final spaces */
00167                         int len = strlen(value);
00168                         while(isspace(value[len-1]) && len > 0) {
00169                                 value[len-1] = 0; len--;
00170                         }
00171                 }
00172                                 
00173                 if(!options_try_pair(ops, name, value) && !options_tolerant) {
00174                         return 0;
00175                 }
00176         }
00177         return 1;
00178 }
00179 
00180 int options_parse_file(struct option*ops, const char*pwd, const char*filename) {
00181         char concat[PATH_MAX*2+1];
00182 
00183         if(filename[0] != '/') {
00184                 strcpy(concat, pwd);
00185                 strcat(concat, "/");
00186                 strcat(concat, filename);
00187         } else {
00188                 strcpy(concat, filename);       
00189         }
00190         
00191         char resolved_path[PATH_MAX];
00192         char *resolved;
00193         if(! (resolved = realpath(concat, resolved_path))) {
00194                 fprintf(stderr, "Could not resolve '%s' ('%s').\n", concat, resolved); 
00195                 return 0;
00196         }
00197 
00198         const char * newdir = dirname(resolved);
00199         if(!newdir) {
00200                 fprintf(stderr, "Could not get dirname for '%s'.\n",  resolved); 
00201                 free(resolved);
00202                 return 0;
00203         }
00204         
00205         FILE * file;
00206         file = fopen(resolved,"r");
00207         if(file==NULL) {
00208                 fprintf(stderr, "Could not open '%s': %s.\n", resolved, strerror(errno)); 
00209                 /* free(resolved); */
00210                 return 0;
00211         }
00212         
00213         /* free(resolved); */
00214         return options_parse_stream(ops, newdir, file);
00215 }
00216 
00217 
00219 struct option * options_find(struct option*ops, const char * name) {
00220         int j;
00221         for(j=0;options_valid(ops+j);j++) 
00222                 if(!strcmp(name,ops[j].name)) 
00223                 return ops+j;
00224         
00225         return 0;
00226 }
00227 
00228 int options_try_pair(struct option*ops, const char*name, const char*value) {
00229         struct option* o;
00230         if(0 == (o = options_find(ops, name))) {
00231                 /* error, option does not exist */
00232                 fprintf(stderr, "Option '%s' does not exist.\n", name);
00233                 return 0;
00234         }
00235         return options_set(o, value);
00236 }
00237 
00238 int options_valid(struct option*o) {
00239         return o->name != 0;
00240 }
00241 
00242 int options_set(struct option*o, const char*value) {
00243         switch(o->type) {       
00244                 case(OPTION_INT): {
00245                         int * value_pointer = (int*) o->value_pointer;
00246                         int ok = get_int(value_pointer, value);
00247                         if(!ok) {
00248                                 fprintf(stderr, "Could not parse int: '%s' = '%s'.\n", o->name, value);
00249                                 return 0;
00250                         }
00251                         return 1;
00252                 }
00253 
00254                 case(OPTION_STRING): {
00255                         char** value_pointer = (char**) o->value_pointer;
00256                         *value_pointer = (char*) strdup_(value);
00257 /*                      fprintf(stderr, 
00258                                 "String %s, value_pointer=%p void pointer=%p *value_pointer=%p result=%s\n"
00259                          ,argv[i+1], value_pointer, o->op[j].value_pointer, *value_pointer,
00260                          *value_pointer);*/
00261                         return 1;
00262                 }
00263 
00264                 case(OPTION_DOUBLE): {
00265                         double * value_pointer = (double*) o->value_pointer;
00266                         int ok = get_double(value_pointer, value);
00267                         if(!ok) {
00268                                 fprintf(stderr, "Could not parse double: '%s' = '%s'.\n", o->name, value);
00269                                 return 0;
00270                         }
00271                         return 1;
00272                 }
00273 
00274                 case(OPTION_ALTERNATIVE): {
00275                         int * value_pointer = (int*) o->value_pointer;
00276                         struct option_alternative * a = o->alternative;
00277                         for(; a->label; a++) {
00278                                 if( !strcasecmp(a->label, value) ) {
00279                                         *value_pointer = a->value;
00280                                         return 1;
00281                                 }
00282                         }
00283                         fprintf(stderr, "Could not recognize '%s' as one of the alternative for %s: ", 
00284                                 value, o->name);
00285                         
00286                         for(a = o->alternative; a->label; a++) {
00287                                 fprintf(stderr, "\"%s\"", a->label);
00288                                 if( (a+1)->label )      fprintf(stderr, ", ");
00289                         }
00290                         fprintf(stderr, ".\n");
00291                         return 0;
00292                 }
00293                 
00294                 
00295                 
00296                 default: {
00297                         /* XXX ERROR */
00298                         fprintf(stderr, "Could not parse type %d: '%s' = '%s'.\n", (int) o->type, o->name, value);
00299                         return 0;
00300                 }
00301         }
00302 }
00303 
00304 const char*options_value_as_string(struct option*o);
00305 
00306 void display_table(FILE*f,  char**table, int rows, int columns, int padding) {
00307         int col_size[columns];
00308         
00309         int i,j;
00310         for(j=0;j<columns;j++)  {
00311                 col_size[j]=0;
00312                 for(i=0;i<rows;i++) {
00313                         const char * s = table[j+i*columns];
00314                         col_size[j] = MAX(col_size[j], (int) strlen(s));
00315                 }
00316                 col_size[j] += padding;
00317         }
00318         
00319         for(i=0;i<rows;i++) {
00320                 for(j=0;j<columns;j++)  {
00321                         const char * s = table[j+i*columns];
00322                         /* don't add padding to last column */
00323                         if(j != columns - 1)
00324                                 fprintf(f, "%s%*s", s, (int)(col_size[j]-strlen(s)), "");
00325                         else
00326                                 fputs(s, f);
00327                 }
00328                 fprintf(f, "\n");
00329         }
00330 }
00331 
00332 void options_dump(struct option * options, FILE*f, int write_desc) {
00333         int n; for (n=0;options_valid(options+n);n++);
00334 
00335         int nrows = n + 2;
00336         char**table = malloc(sizeof(char*)*nrows*3);
00337 
00338         int row = 0;
00339         if(write_desc) {
00340                 table[row*3 +0] = strdup_("Option name");
00341                 table[row*3 +1] = strdup_("Default");
00342                 table[row*3 +2] = strdup_("Description");
00343                 row++;
00344                 table[row*3 +0] = strdup_("-----------");
00345                 table[row*3 +1] = strdup_("-------");
00346                 table[row*3 +2] = strdup_("-----------");
00347                 row++;
00348         } else {
00349                 table[row*3 +0] = strdup_("");
00350                 table[row*3 +1] = strdup_("");
00351                 table[row*3 +2] = strdup_("");
00352                 row++;
00353                 table[row*3 +0] = strdup_("");
00354                 table[row*3 +1] = strdup_("");
00355                 table[row*3 +2] = strdup_("");
00356                 row++;
00357         }
00358         
00359         int i;
00360         for (i=0;i<n;i++) {
00361                 table[row*3 +0] = strdup_(options[i].name);
00362                 table[row*3 +1] = strdup_(options_value_as_string(options+i));
00363                 table[row*3 +2] = write_desc ? strdup_(options[i].desc) : strdup_(""); 
00364 
00365                 if( write_desc)
00366                 if(options[i].type == OPTION_ALTERNATIVE) {
00367                         char extended[1000];
00368                         strcat(extended, options[i].desc);
00369                         strcat(extended, "  Possible options are: ");
00370         
00371                         struct option_alternative * a = options[i].alternative;
00372                         for(; a->label; a++) {
00373                                 strcat(extended, "\"");
00374                                 strcat(extended, a->label);
00375                                 strcat(extended, "\"");
00376                                 if(a->desc) {
00377                                 strcat(extended, ": ");
00378                                 strcat(extended, a->desc);
00379                                 } else {
00380                                 }
00381                                 if((a+1)->label)
00382                                         strcat(extended, ", ");
00383                         }       
00384                         strcat(extended, ".");
00385                         
00386                         table[row*3 +2] =  strdup_(extended);   
00387                 }
00388                 
00389                 row ++;
00390         }
00391 
00392         display_table(f, table, nrows, 3, 2);
00393 
00394         int a; for(a=0;a<nrows*3;a++) free((void*)table[a]);
00395         free((void*)table);
00396 }
00397 
00398 void options_print_help(struct option * options, FILE*f) {
00399         fprintf(f, "%s", options_banner_string);
00400         fprintf(f, 
00401         "Generic options: \n"
00402         "  -help          Displays this help.\n"
00403         "  -config_dump   Dumps the configuration on the standard output. \n"
00404         "  -config FILE   Loads a config file in the format used by config_dump.\n"
00405         "\n");
00406         
00407         options_dump(options, f, 1);
00408 }
00409 
00410 static char options_value_as_string_buf[1000];
00411 const char*options_value_as_string(struct option*o) {
00412         if(!o->value_pointer) {
00413                 return "NULL";
00414         }
00415         
00416         switch(o->type) {
00417                 case(OPTION_INT): {
00418                         int * value_pointer = (int*) o->value_pointer;
00419                         sprintf(options_value_as_string_buf, "%d", *value_pointer);
00420                         break;
00421                 }
00422 
00423                 case(OPTION_STRING): {
00424                         char** value_pointer = (char**) o->value_pointer;
00425                         sprintf(options_value_as_string_buf, "%s", *value_pointer); /* should I add "" ? */
00426                         break;
00427                 }
00428                 
00429                 case(OPTION_DOUBLE): {
00430                         double * value_pointer = (double*) o->value_pointer;
00431                         sprintf(options_value_as_string_buf, "%g", *value_pointer);
00432                         break;
00433                 }
00434                 
00435                 case(OPTION_ALTERNATIVE): {
00436                         int * value_pointer = (int*) o->value_pointer;
00437                         struct option_alternative * a = o->alternative;
00438                         for(; a->label; a++) {
00439                                 if( a->value == *value_pointer )
00440                                         sprintf(options_value_as_string_buf, "%s", a->label);
00441                         }
00442                         break;
00443                 }
00444                 
00445                 default: 
00446                 strcpy(options_value_as_string_buf, "?");
00447         } /* switch */  
00448         
00449         return options_value_as_string_buf;
00450 }
00451 


csm
Author(s): Andrea Censi
autogenerated on Mon Jan 16 2017 03:48:29