options.c
Go to the documentation of this file.
1 #ifdef LINUX
2 
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE
5 #endif
6 
7 /* for realpath() */
8 #ifndef __USE_BSD
9 #define __USE_BSD
10 #endif
11 
12 #endif /* LINUX */
13 
14 #include <errno.h>
15 #include <limits.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <sys/param.h>
19 #include <ctype.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include <libgen.h>
23 #include <string.h>
24 
25 #include "options.h"
26 
27 
28 void display_table(FILE*f, char**table, int rows, int columns, int padding);
29 
30 
31 const char * options_banner_string = "";
32 
33 void options_banner(const char*message) {
34  options_banner_string = message;
35 }
36 
38 char * strdup_(const char *s) {
39  size_t len = strlen(s) + 1; /* null byte */
40  char * t = (char*) malloc(len);
41  memcpy(t,s,len);
42  return t;
43 }
44 
45 
47 int get_int(int*p, const char*s) {
48  int value;
49  errno = 0;
50  value = strtol(s, (char **)NULL, 10);
51  if(0 == errno) {
52  *p = value;
53  return 1;
54  } else return 0;
55 }
56 
58 int get_double(double*p, const char*s) {
59  char *endptr;
60  *p = strtod(s, &endptr);
61  return endptr != s;
62 }
63 
65 
66 int options_parse_args(struct option*ops, int argc, const char* argv[]) {
67  int i;
68  for (i=1; i<argc; i++) {
69  const char * name = argv[i];
70  while(*name == '-') name++;
71 
72  if(!strcmp("config_dump", name)) {
73  options_dump(ops, stdout, 0);
74  exit(0);
75  }
76 
77  if(!strcmp("help",name) || !strcmp("h",name) ) {
78  options_print_help(ops, stdout);
79  exit(0);
80  }
81 
82  if(!strcmp("config", name)) {
83  if(i>=argc-1) {
84  fprintf(stderr, "Please specify config file.\n");
85  if(!options_tolerant) return 0;
86  }
87  if(!options_parse_file(ops, ".", argv[i+1])) {
88  if(!options_tolerant) return 0;
89  }
90  i++;
91  continue;
92  }
93 
94  struct option * o;
95  if(0 == (o =options_find(ops, name)) ) {
96  fprintf(stderr, "Option '%s' not found (use -help to get list of options).\n", name);
97  if(!options_tolerant) return 0;
98  }
99 
102  if(i>=argc-1) {
103  fprintf(stderr, "Argument %s needs value.\n", o->name);
104  if(!options_tolerant) return 0;
105  }
106  if(!options_set(o, argv[i+1])) {
107  if(!options_tolerant) return 0;
108  }
109  i++;
110  }
111 
112  } /* for */
113 
114  return 1;
115 }
116 
117 
118 
120 void options_set_passed(struct option*o) {
121  if(o->set_pointer)
122  *(o->set_pointer) = 1;
123 }
124 
127  return o->value_pointer != 0;
128 }
129 
130 
131 int options_parse_stream(struct option*ops, const char*pwd, FILE*file) {
132  #define MAX_LINE_LENGTH 10000
133  char linesto[MAX_LINE_LENGTH];
134  while(fgets(linesto, MAX_LINE_LENGTH-1, file)) {
135  char *line=linesto; while(*line) { if(*line=='\n') *line=0; line++; }
136  line = linesto;
137  while(isspace(*line)) line++;
138  if(*line == '#') continue;
139  if(*line == '<') { line++;
140  while(isspace(*line)) line++;
141  if(!options_parse_file(ops, pwd, line)) {
142  if(!options_tolerant) return 0;
143  }
144  continue;
145  }
146  if(!*line) continue;
147  /* Here starts the name; later we put a terminating 0 */
148  const char * name = line;
149  /* name continus until nonspace char */
150  while(!isspace(*line)) line++;
151 
152  char empty[5] = "";
153  char * value;
154  if(*line == 0) value = empty; else {
155  *line = 0; /* terminating 0 for name */
156  line++;
157  /* ignore spaces */
158  while(isspace(*line)) line++;
159  /* ignore possible "=" */
160  if(*line == '=') line++;
161  /* ignore spaces */
162  while(isspace(*line)) line++;
163 
164  /* here starts the value */
165  value = line;
166  /* delete final spaces */
167  int len = strlen(value);
168  while(isspace(value[len-1]) && len > 0) {
169  value[len-1] = 0; len--;
170  }
171  }
172 
173  if(!options_try_pair(ops, name, value) && !options_tolerant) {
174  return 0;
175  }
176  }
177  return 1;
178 }
179 
180 int options_parse_file(struct option*ops, const char*pwd, const char*filename) {
181  char concat[PATH_MAX*2+1];
182 
183  if(filename[0] != '/') {
184  strcpy(concat, pwd);
185  strcat(concat, "/");
186  strcat(concat, filename);
187  } else {
188  strcpy(concat, filename);
189  }
190 
191  char resolved_path[PATH_MAX];
192  char *resolved;
193  if(! (resolved = realpath(concat, resolved_path))) {
194  fprintf(stderr, "Could not resolve '%s' ('%s').\n", concat, resolved);
195  return 0;
196  }
197 
198  const char * newdir = dirname(resolved);
199  if(!newdir) {
200  fprintf(stderr, "Could not get dirname for '%s'.\n", resolved);
201  free(resolved);
202  return 0;
203  }
204 
205  FILE * file;
206  file = fopen(resolved,"r");
207  if(file==NULL) {
208  fprintf(stderr, "Could not open '%s': %s.\n", resolved, strerror(errno));
209  /* free(resolved); */
210  return 0;
211  }
212 
213  /* free(resolved); */
214  return options_parse_stream(ops, newdir, file);
215 }
216 
217 
219 struct option * options_find(struct option*ops, const char * name) {
220  int j;
221  for(j=0;options_valid(ops+j);j++)
222  if(!strcmp(name,ops[j].name))
223  return ops+j;
224 
225  return 0;
226 }
227 
228 int options_try_pair(struct option*ops, const char*name, const char*value) {
229  struct option* o;
230  if(0 == (o = options_find(ops, name))) {
231  /* error, option does not exist */
232  fprintf(stderr, "Option '%s' does not exist.\n", name);
233  return 0;
234  }
235  return options_set(o, value);
236 }
237 
238 int options_valid(struct option*o) {
239  return o->name != 0;
240 }
241 
242 int options_set(struct option*o, const char*value) {
243  switch(o->type) {
244  case(OPTION_INT): {
245  int * value_pointer = (int*) o->value_pointer;
246  int ok = get_int(value_pointer, value);
247  if(!ok) {
248  fprintf(stderr, "Could not parse int: '%s' = '%s'.\n", o->name, value);
249  return 0;
250  }
251  return 1;
252  }
253 
254  case(OPTION_STRING): {
255  char** value_pointer = (char**) o->value_pointer;
256  *value_pointer = (char*) strdup_(value);
257 /* fprintf(stderr,
258  "String %s, value_pointer=%p void pointer=%p *value_pointer=%p result=%s\n"
259  ,argv[i+1], value_pointer, o->op[j].value_pointer, *value_pointer,
260  *value_pointer);*/
261  return 1;
262  }
263 
264  case(OPTION_DOUBLE): {
265  double * value_pointer = (double*) o->value_pointer;
266  int ok = get_double(value_pointer, value);
267  if(!ok) {
268  fprintf(stderr, "Could not parse double: '%s' = '%s'.\n", o->name, value);
269  return 0;
270  }
271  return 1;
272  }
273 
274  case(OPTION_ALTERNATIVE): {
275  int * value_pointer = (int*) o->value_pointer;
276  struct option_alternative * a = o->alternative;
277  for(; a->label; a++) {
278  if( !strcasecmp(a->label, value) ) {
279  *value_pointer = a->value;
280  return 1;
281  }
282  }
283  fprintf(stderr, "Could not recognize '%s' as one of the alternative for %s: ",
284  value, o->name);
285 
286  for(a = o->alternative; a->label; a++) {
287  fprintf(stderr, "\"%s\"", a->label);
288  if( (a+1)->label ) fprintf(stderr, ", ");
289  }
290  fprintf(stderr, ".\n");
291  return 0;
292  }
293 
294 
295 
296  default: {
297  /* XXX ERROR */
298  fprintf(stderr, "Could not parse type %d: '%s' = '%s'.\n", (int) o->type, o->name, value);
299  return 0;
300  }
301  }
302 }
303 
304 const char*options_value_as_string(struct option*o);
305 
306 void display_table(FILE*f, char**table, int rows, int columns, int padding) {
307  int col_size[columns];
308 
309  int i,j;
310  for(j=0;j<columns;j++) {
311  col_size[j]=0;
312  for(i=0;i<rows;i++) {
313  const char * s = table[j+i*columns];
314  col_size[j] = MAX(col_size[j], (int) strlen(s));
315  }
316  col_size[j] += padding;
317  }
318 
319  for(i=0;i<rows;i++) {
320  for(j=0;j<columns;j++) {
321  const char * s = table[j+i*columns];
322  /* don't add padding to last column */
323  if(j != columns - 1)
324  fprintf(f, "%s%*s", s, (int)(col_size[j]-strlen(s)), "");
325  else
326  fputs(s, f);
327  }
328  fprintf(f, "\n");
329  }
330 }
331 
332 void options_dump(struct option * options, FILE*f, int write_desc) {
333  int n; for (n=0;options_valid(options+n);n++);
334 
335  int nrows = n + 2;
336  char**table = malloc(sizeof(char*)*nrows*3);
337 
338  int row = 0;
339  if(write_desc) {
340  table[row*3 +0] = strdup_("Option name");
341  table[row*3 +1] = strdup_("Default");
342  table[row*3 +2] = strdup_("Description");
343  row++;
344  table[row*3 +0] = strdup_("-----------");
345  table[row*3 +1] = strdup_("-------");
346  table[row*3 +2] = strdup_("-----------");
347  row++;
348  } else {
349  table[row*3 +0] = strdup_("");
350  table[row*3 +1] = strdup_("");
351  table[row*3 +2] = strdup_("");
352  row++;
353  table[row*3 +0] = strdup_("");
354  table[row*3 +1] = strdup_("");
355  table[row*3 +2] = strdup_("");
356  row++;
357  }
358 
359  int i;
360  for (i=0;i<n;i++) {
361  table[row*3 +0] = strdup_(options[i].name);
362  table[row*3 +1] = strdup_(options_value_as_string(options+i));
363  table[row*3 +2] = write_desc ? strdup_(options[i].desc) : strdup_("");
364 
365  if( write_desc)
366  if(options[i].type == OPTION_ALTERNATIVE) {
367  char extended[1000];
368  strcat(extended, options[i].desc);
369  strcat(extended, " Possible options are: ");
370 
371  struct option_alternative * a = options[i].alternative;
372  for(; a->label; a++) {
373  strcat(extended, "\"");
374  strcat(extended, a->label);
375  strcat(extended, "\"");
376  if(a->desc) {
377  strcat(extended, ": ");
378  strcat(extended, a->desc);
379  } else {
380  }
381  if((a+1)->label)
382  strcat(extended, ", ");
383  }
384  strcat(extended, ".");
385 
386  table[row*3 +2] = strdup_(extended);
387  }
388 
389  row ++;
390  }
391 
392  display_table(f, table, nrows, 3, 2);
393 
394  int a; for(a=0;a<nrows*3;a++) free((void*)table[a]);
395  free((void*)table);
396 }
397 
398 void options_print_help(struct option * options, FILE*f) {
399  fprintf(f, "%s", options_banner_string);
400  fprintf(f,
401  "Generic options: \n"
402  " -help Displays this help.\n"
403  " -config_dump Dumps the configuration on the standard output. \n"
404  " -config FILE Loads a config file in the format used by config_dump.\n"
405  "\n");
406 
407  options_dump(options, f, 1);
408 }
409 
410 static char options_value_as_string_buf[1000];
411 const char*options_value_as_string(struct option*o) {
412  if(!o->value_pointer) {
413  return "NULL";
414  }
415 
416  switch(o->type) {
417  case(OPTION_INT): {
418  int * value_pointer = (int*) o->value_pointer;
419  sprintf(options_value_as_string_buf, "%d", *value_pointer);
420  break;
421  }
422 
423  case(OPTION_STRING): {
424  char** value_pointer = (char**) o->value_pointer;
425  sprintf(options_value_as_string_buf, "%s", *value_pointer); /* should I add "" ? */
426  break;
427  }
428 
429  case(OPTION_DOUBLE): {
430  double * value_pointer = (double*) o->value_pointer;
431  sprintf(options_value_as_string_buf, "%g", *value_pointer);
432  break;
433  }
434 
435  case(OPTION_ALTERNATIVE): {
436  int * value_pointer = (int*) o->value_pointer;
437  struct option_alternative * a = o->alternative;
438  for(; a->label; a++) {
439  if( a->value == *value_pointer )
440  sprintf(options_value_as_string_buf, "%s", a->label);
441  }
442  break;
443  }
444 
445  default:
446  strcpy(options_value_as_string_buf, "?");
447  } /* switch */
448 
450 }
451 
void options_banner(const char *message)
Definition: options.c:33
int options_set(struct option *o, const char *value)
Definition: options.c:242
#define MAX_LINE_LENGTH
const char * desc
Definition: options.h:83
int * set_pointer
Definition: options.h:74
int get_double(double *p, const char *s)
Definition: options.c:58
int options_valid(struct option *o)
Definition: options.c:238
const char * options_value_as_string(struct option *o)
Definition: options.c:411
int options_parse_stream(struct option *ops, const char *pwd, FILE *file)
Definition: options.c:131
struct option * ops
Definition: rb_sm.c:31
char * strdup_(const char *s)
Definition: options.c:38
void options_dump(struct option *options, FILE *f, int write_desc)
Definition: options.c:332
int options_tolerant
Definition: options.c:64
const char * options_banner_string
Definition: options.c:31
Definition: options.h:49
int get_int(int *p, const char *s)
Definition: options.c:47
int options_parse_file(struct option *ops, const char *pwd, const char *filename)
Definition: options.c:180
const char * label
Definition: options.h:81
static char options_value_as_string_buf[1000]
Definition: options.c:410
struct @0 p
const char * name
Definition: options.h:51
struct option_alternative * alternative
Definition: options.h:77
void display_table(FILE *f, char **table, int rows, int columns, int padding)
Definition: options.c:306
void * value_pointer
Definition: options.h:70
void options_set_passed(struct option *o)
Definition: options.c:120
int options_requires_argument(struct option *o)
Definition: options.c:126
void options_print_help(struct option *options, FILE *f)
Definition: options.c:398
enum option_type type
Definition: options.h:55
int options_try_pair(struct option *ops, const char *name, const char *value)
Definition: options.c:228
struct option * options_find(struct option *ops, const char *name)
Definition: options.c:219
const char * desc
Definition: options.h:52
int options_parse_args(struct option *ops, int argc, const char *argv[])
Definition: options.c:66


csm
Author(s): Andrea Censi
autogenerated on Tue May 11 2021 02:18:23