libcfe  0.12.1
some useful C-functions
getparam.c
Go to the documentation of this file.
1 #include "config.h"
2 #include "getparam.h"
3 
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <string.h>
9 #include <libintl.h>
10 
11 #include "len.h"
12 #include "char_to_int.h"
13 #include "char_to_double.h"
14 
15 #define UNUSED(x) (void)(x)
16 
17 #define ISVAR(o) ((o.type & PARAM_ACTION_VAR) == PARAM_ACTION_VAR)
18 #define ISFUNC(o) ((o.type & PARAM_ACTION_FUNC) == PARAM_ACTION_FUNC)
19 #define CANARG(o) ((o.type & PARAM_OPTION_ARG_YES) == PARAM_OPTION_ARG_YES)
20 #define MAYARG(o) ((o.type & PARAM_OPTION_ARG_MAYBE) == PARAM_OPTION_ARG_MAYBE)
21 #define REQUIREARG(o) (CANARG(o) && !MAYARG(o))
22 #define NOARG(o) ((o.type & PARAM_OPTION_ARG_YES) == 0)
23 #define TYPEBOOL(o) ((o.type & PARAM_OPTION_BOOL) == PARAM_OPTION_BOOL)
24 #define TYPEINT(o) ((o.type & ARG_TYPE_DOUBLE) == ARG_TYPE_INT)
25 #define TYPESTR(o) ((o.type & ARG_TYPE_DOUBLE) == ARG_TYPE_STR)
26 #define TYPEDOUBLE(o) ((o.type & ARG_TYPE_DOUBLE) == ARG_TYPE_DOUBLE)
27 
28 #ifndef MIN
29 # define MIN(a, b) (a > b ? b : a)
30 #endif
31 #ifndef MAX
32 # define MAX(a, b) (a < b ? b : a)
33 #endif
34 
35 struct _typeless
36 {
37  short int type;
38  short int b;
39  long int i;
40  long double d;
41  char *s;
42 };
43 
44 #define TYPLESSVAR struct _typeless
45 #define SETBOOL(var, v) var.type=1; var.b=(short int)(v);
46 #define SETINT(var, v) var.type=2; var.i=(long int)(v);
47 #define SETDOUBLE(var, v) var.type=3; var.d=(long double)(v);
48 #define SETSTR(var, v) var.type=4; var.s=(char *)(v);
49 #define SETVOID(var, v) var.type=5; var.s=(void *)(v);
50 #define SETFAILED(var) var.type=6;
51 #define SETNULL(var) var.type=0;
52 #define ISNULL(var) (var.type==0?1:0)
53 #define ISBOOL(var) (var.type==1?1:0)
54 #define ISINT(var) (var.type==2?1:0)
55 #define ISDOUBLE(var) (var.type==3?1:0)
56 #define ISSTR(var) (var.type==4?1:0)
57 #define ISVOID(var) (var.type==5?1:0)
58 #define ISFAILED(var) (var.type==6?1:0)
59 #define GETVAL(var, t) (var.type==1?(t)var.b:(var.type==2?(t)var.i:(var.type==3?(t)var.d:(var.type==4?(t)var.s:(var.type==5?(t)var.s:(t)NULL)))))
60 #define GETNULL(var) ((void *)NULL)
61 #define GETBOOL(var) ((short int)var.b)
62 #define GETINT(var) ((long int)var.i)
63 #define GETDOUBLE(var) ((long double)var.d)
64 #define GETSTR(var) ((char *)var.s)
65 #define GETVOID(var) ((void *)var.s)
66 
67 #define BIT_SET(b, o) ((o & b) == b)
68 #define IS_FAIL_ON_UNKNOWN(o) (BIT_SET(FAIL_ON_UNKNOWN, o))
69 #define ARG(o) (TYPESTR(o)?arg_str:(TYPEINT(o)?arg_int:(TYPEDOUBLE(o)?arg_double:(TYPEBOOL(o)?arg_bool:""))))
70 
71 short int check_bool(const char *s, size_t len);
72 short int char_to_bool(const char *s, size_t len);
73 int applyopt(option_t **o_all, option_t o, TYPLESSVAR arg);
74 TYPLESSVAR check_arg(option_t o, void *arg);
75 
77 {
78  int i;
79  static char arg_bool[] = "=BOOLEAN";
80  static char arg_int[] = "=INTEGER";
81  static char arg_str[] = "=STRING";
82  static char arg_double[] = "=DECIMAL";
83  static char bool_no[] = "[no-]";
84 
85  for(i = 0; o[i].type != 0; i++)
86  {
87  if(o[i].shortopt != 0 || o[i].longopt != NULL)
88  {
89  int j = printf(" %c%c%c %s%s%s%c%s%c",
90  (o[i].shortopt != 0 ? '-': ' '),
91  (o[i].shortopt != 0 ? o[i].shortopt : ' '),
92  (o[i].shortopt != 0 && o[i].longopt != NULL ? ',' : ' '),
93  (o[i].longopt != NULL ? "--" : ""),
94  (TYPEBOOL(o[i]) ? bool_no : ""),
95  o[i].longopt,
96  (MAYARG(o[i]) ? '[' : 0),
97  ARG(o[i]),
98  (MAYARG(o[i]) ? ']' : 0));
99  printf("%*s\t%s\n", MAX(39 - j, 2), "", _(gettext(o[i].help_text)));
100  }
101  }
102 }
103 
105 {
106  int i;
107  static char arg_bool[] = "=BOOLEAN";
108  static char arg_int[] = "=INTEGER";
109  static char arg_str[] = "=STRING";
110  static char arg_double[] = "=DECIMAL";
111 
112  for(i = 0; o[i].type != 0; i++)
113  {
114  if(o[i].configname != NULL)
115  {
116  int j = printf(" %s%c%s%c",
117  o[i].configname,
118  (MAYARG(o[i]) ? '[' : 0),
119  ARG(o[i]),
120  (MAYARG(o[i]) ? ']' : 0));
121  printf("%*s\t%s\n", MAX(39 - j, 2), "", _(gettext(o[i].help_text)));
122  }
123  }
124 }
125 
126 size_t add_config_options(option_t **o_in, option_t add[])
127 {
128  size_t n_o_in, n_add, i;
129  if(*o_in != NULL)
130  for(n_o_in = 0; (*o_in)[n_o_in].type != 0; n_o_in++);
131  else
132  n_o_in = 0;
133  if(add == NULL) return n_o_in;
134  for(n_add = 0; add[n_add].type != 0; n_add++);
135  n_add++;
136  *o_in = (option_t *)realloc(*o_in, sizeof(option_t) * (n_o_in + n_add));
137  for(i = 0; i < n_add; i++)
138  (*o_in)[n_o_in + i] = add[i];
139  return n_o_in + n_add;
140 }
141 
142 short int check_bool(const char *s, size_t len)
143 {
144  UNUSED(len);
145  if(strcasecmp(s, "true") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcmp(s, "1") == 0 || strcasecmp(s, "false") == 0 || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcmp(s, "0") == 0)
146  return 1;
147  else
148  return 0;
149 }
150 
151 short int char_to_bool(const char *s, size_t len)
152 {
153  UNUSED(len);
154  if(strcasecmp(s, "true") == 0 || strcasecmp(s, "yes") == 0 || strcasecmp(s, "y") == 0 || strcmp(s, "1") == 0)
155  return 1;
156  else if(strcasecmp(s, "false") == 0 || strcasecmp(s, "no") == 0 || strcasecmp(s, "n") == 0 || strcmp(s, "0") == 0)
157  return 0;
158  return -1;
159 }
160 
161 int applyopt(option_t **o_all, option_t o, TYPLESSVAR arg)
162 {
163  UNUSED(o_all);
164 
165  if(o.ptr == NULL)
166  return 0;
167  if(!ISVAR(o))
168  return 0;
169  if(ISDOUBLE(arg))
170  *(double *)(o.ptr) = GETDOUBLE(arg);
171  else if(ISINT(arg))
172  *(int *)(o.ptr) = GETINT(arg);
173  else if(ISSTR(arg))
174  *(char **)(o.ptr) = GETSTR(arg);
175  else if(ISBOOL(arg))
176  *(int *)(o.ptr) = GETBOOL(arg);
177  else if(ISVOID(arg))
178  {
179  if(TYPEINT(o))
180  *(int *)(o.ptr) = GETINT(arg);
181  else if(TYPESTR(o))
182  *(char **)(o.ptr) = GETSTR(arg);
183  else if(TYPEDOUBLE(o))
184  *(double *)(o.ptr) = GETDOUBLE(arg);
185  else
186  *(void **)(o.ptr) = GETVOID(arg);
187  }
188  else if(ISNULL(arg))
189  *(char **)(o.ptr) = GETNULL(arg);
190  else if(ISFAILED(arg))
191  printf(_("option: %s / %c; FAILED\n"), o.longopt, o.shortopt);
192  return 0;
193 }
194 
196 {
197  TYPLESSVAR var;
198  if(TYPEBOOL(o))
199  {
200  if(!check_bool(arg, str_len(arg)))
201  {
202  if(!TYPEINT(o) && !TYPESTR(o) && !TYPEDOUBLE(o))
203  printf(_("argument %s for option --%s is not a boolean\n"), (char *)arg, o.longopt);
204  SETFAILED(var);
205  }
206  else
207  {
208  SETBOOL(var, (char_to_bool(arg, str_len(arg))?1:0));
209  return var;
210  }
211  }
212  if(TYPESTR(o))
213  {
214  SETSTR(var, arg);
215  }
216  else if(TYPEINT(o))
217  {
218  if(!check_int(arg, str_len(arg), 10))
219  {
220  printf(_("argument %s for option --%s is not a number\n"), (char *)arg, o.longopt);
221  SETFAILED(var);
222  }
223  else
224  {
225  SETINT(var, char_to_int((char *)arg, str_len(arg), 10));
226  }
227  }
228  else if(TYPEDOUBLE(o))
229  {
230  if(!check_double(arg, str_len(arg)))
231  {
232  printf(_("argument %s for option --%s is not a number\n"), (char *)arg, o.longopt);
233  SETFAILED(var);
234  }
235  else
236  {
237  SETDOUBLE(var, char_to_double(arg, str_len(arg)));
238  }
239  }
240  return var;
241 }
242 
243 int getparam(option_t **o, int argc, char **argv)
244 {
245  int i, j, prefix;
246  for(i = 1; i < argc; i++)
247  {
248  if(argv[i][0] == '-' && argv[i][1] == '-' && str_len(argv[i]) == 2)
249  return i + 1;
250  else if(argv[i][0] == '-' && argv[i][1] == '-')
251  {
252  for(j = 0; (*o)[j].type != 0; j++)
253  {
254  prefix = 2;
255 
256  if(TYPEBOOL((*o)[j]) && strncmp(argv[i] + prefix, "no-", 3) == 0)
257  prefix += 3;
258  int optlen = MIN(_len(argv[i] + prefix, '='), str_len(argv[i] + prefix));
259  if(strncmp(argv[i] + prefix, (*o)[j].longopt, MAX(optlen, str_len((*o)[j].longopt))) == 0)
260  {
261  TYPLESSVAR var;
262  if(argv[i][prefix + optlen] == '=')
263  {
264  if(NOARG((*o)[j]))
265  {
266  printf(_("option --%s does not accept any arguments\n"), (*o)[j].longopt);
267  return -1;
268  }
269  if(ISFUNC((*o)[j]))
270  {
271  if(((option_func_t)(*o)[j].ptr)((*o)[j], argv[i] + prefix + optlen + 1, o) != 0)
272  return -1;
273  }
274  else if(ISVAR((*o)[j]))
275  {
276  var = check_arg((*o)[j], argv[i] + prefix + optlen + 1);
277  if(ISFAILED(var)) return -1;
278  applyopt(o, (*o)[j], var);
279  }
280  }
281  else if(REQUIREARG((*o)[j]))
282  {
283  printf(_("option --%s requires an argument\n"), (*o)[j].longopt);
284  return -1;
285  }
286  else
287  {
288  if(TYPEBOOL((*o)[j]))
289  {
290  if(ISFUNC((*o)[j]))
291  {
292  if(((option_func_t)(*o)[j].ptr)((*o)[j], (prefix > 2 ? (void *)0 : (void *)1), o) != 0)
293  return -1;
294  }
295  else if(ISVAR((*o)[j]))
296  {
297  SETBOOL(var, (prefix>2?0:1));
298  }
299  }
300  else
301  {
302  if(ISFUNC((*o)[j]))
303  {
304  if(((option_func_t)(*o)[j].ptr)((*o)[j], (*o)[j].default_value, o) != 0)
305  return -1;
306  }
307  else if(ISVAR((*o)[j]))
308  {
309  SETVOID(var, (int64_t)(*o)[j].default_value);
310  }
311  }
312  if(ISVAR((*o)[j]))
313  applyopt(o, (*o)[j], var);
314  }
315  break;
316  }
317  }
318  if((*o)[j].type == 0)
319  {
320  printf(_("no such option %s\n"), argv[i]);
321  return -1;
322  }
323  }
324  else if(argv[i][0] == '-' && str_len(argv[i]) == 2)
325  {
326  for(j = 0; (*o)[j].type != 0; j++)
327  {
328  if(argv[i][1] == (*o)[j].shortopt)
329  {
330  TYPLESSVAR var;
331  if(CANARG((*o)[j]) && (i + 1) < argc && argv[i + 1][0] != '-')
332  {
333  if(ISFUNC((*o)[j]))
334  {
335  if(((option_func_t)(*o)[j].ptr)((*o)[j], (void *)argv[++i], o) != 0)
336  return -1;
337  }
338  else if(ISVAR((*o)[j]))
339  {
340  var = check_arg((*o)[j], argv[++i]);
341  if(ISFAILED(var)) return -1;
342  }
343  }
344  else if(REQUIREARG((*o)[j]))
345  {
346  printf(_("option -%c requires an argument\n"), (*o)[j].shortopt);
347  return -1;
348  }
349  else if(TYPEBOOL((*o)[j]))
350  {
351  if(ISFUNC((*o)[j]))
352  {
353  if(((option_func_t)(*o)[j].ptr)((*o)[j], (void *)1, o) != 0)
354  return -1;
355  }
356  else if(ISVAR((*o)[j]))
357  {
358  SETBOOL(var, 1);
359  }
360  }
361  else
362  {
363  if(ISFUNC((*o)[j]))
364  {
365  if(((option_func_t)(*o)[j].ptr)((*o)[j], (*o)[j].default_value, o) != 0)
366  return -1;
367  }
368  else if(ISVAR((*o)[j]))
369  {
370  SETVOID(var, (int64_t)(*o)[j].default_value);
371  }
372  }
373  if(ISVAR((*o)[j]))
374  applyopt(o, (*o)[j], var);
375  break;
376  }
377  }
378  if((*o)[j].type == 0)
379  {
380  printf(_("no such option %s\n"), argv[i]);
381  return -1;
382  }
383  }
384  else if(argv[i][0] == '-')
385  {
386  printf(_("%s is not a valid option\n"), argv[i]);
387  return -1;
388  }
389  else
390  break;
391  }
392  return i;
393 }
394 
395 int readconfig(option_t **o, const char *file, int options)
396 {
397  if(file == NULL || *o == NULL)
398  return -1;
399 
400  FILE *fp = fopen(file, "r");
401  if(fp == NULL)
402  return -1;
403 
404  char *line, *key, *val, *ptr;
405  line = key = val = NULL;
406  ssize_t readsize = 0;
407  size_t s = 0;
408  size_t vallen = 0;
409  int n = 0;
410 
411  while((readsize = getline(&line, &s, fp)) != -1)
412  {
413  if(line[readsize - 1] == '\n')
414  line[--readsize] = '\0';
415 
416  key = malloc(readsize + 1);
417  ptr = val = malloc(readsize + 1);
418 
419  if(sscanf(line, " %[^%#= ] = %[^#] ", key, val) >= 2)
420  {
421  vallen = str_len(val);
422  while(val[vallen - 1] == ' ' || val[vallen - 1] == '\t')
423  {
424  val[vallen - 1] = '\0';
425  vallen--;
426  }
427 
428  for(n = 0; (*o)[n].type != 0; n++)
429  {
430  if((*o)[n].configname != NULL && strcmp(key, (*o)[n].configname) == 0)
431  {
432  if(val[0] == '"' && val[vallen - 1] == '"')
433  {
434  val++;
435  vallen -= 2;
436  val[vallen] = '\0';
437  }
438  char *val2 = strdup(val);
439  if(ISFUNC((*o)[n]))
440  {
441  if(((option_func_t)(*o)[n].ptr)((*o)[n], (void *)val2, o) != 0)
442  {
443  free(key);
444  free(ptr);
445  free(line);
446  return -1;
447  }
448  }
449  else if(ISVAR((*o)[n]))
450  {
451  TYPLESSVAR var = check_arg((*o)[n], val2);
452  if(ISFAILED(var))
453  {
454  free(key);
455  free(ptr);
456  free(line);
457  return -1;
458  }
459  applyopt(o, (*o)[n], var);
460  }
461  else
462  return -1;
463  break;
464  }
465  }
466  if(IS_FAIL_ON_UNKNOWN(options) && (*o)[n].type == 0)
467  {
468  printf(_("no such option %s\n"), key);
469  return -1;
470  }
471  }
472  free(key);
473  free(ptr);
474  free(line);
475  line = key = val = ptr = NULL;
476  }
477  fclose(fp);
478  return 0;
479 }
long double char_to_double(const char *s, int len)
char * longopt
Definition: getparam.h:23
#define GETINT(var)
Definition: getparam.c:62
int _len(const char *s, char m)
Definition: len.c:8
#define GETBOOL(var)
Definition: getparam.c:61
#define TYPEINT(o)
Definition: getparam.c:24
long int i
Definition: getparam.c:39
short int check_bool(const char *s, size_t len)
Definition: getparam.c:142
char shortopt
Definition: getparam.h:24
#define GETSTR(var)
Definition: getparam.c:64
#define SETDOUBLE(var, v)
Definition: getparam.c:47
#define str_len(s)
Shorthand for counting &#39;\0&#39; terminating strings. See _len for more info.
Definition: len.h:17
#define ISBOOL(var)
Definition: getparam.c:53
int getparam(option_t **o, int argc, char **argv)
Definition: getparam.c:243
#define _(string)
Definition: output.h:43
#define GETNULL(var)
Definition: getparam.c:60
#define SETVOID(var, v)
Definition: getparam.c:49
#define SETBOOL(var, v)
Definition: getparam.c:45
short int type
Definition: getparam.c:37
int applyopt(option_t **o_all, option_t o, TYPLESSVAR arg)
Definition: getparam.c:161
void * ptr
Definition: getparam.h:27
void print_options_help(option_t *o)
Definition: getparam.c:76
char * s
Definition: getparam.c:41
int readconfig(option_t **o, const char *file, int options)
Definition: getparam.c:395
#define CANARG(o)
Definition: getparam.c:19
#define NOARG(o)
Definition: getparam.c:22
long double d
Definition: getparam.c:40
#define MIN(a, b)
Definition: getparam.c:29
#define TYPEDOUBLE(o)
Definition: getparam.c:26
TYPLESSVAR check_arg(option_t o, void *arg)
Definition: getparam.c:195
#define GETVOID(var)
Definition: getparam.c:65
size_t add_config_options(option_t **o_in, option_t add[])
Definition: getparam.c:126
#define MAX(a, b)
Definition: getparam.c:32
#define SETINT(var, v)
Definition: getparam.c:46
#define ARG(o)
Definition: getparam.c:69
#define ISVAR(o)
Definition: getparam.c:17
short int b
Definition: getparam.c:38
short int check_double(const char *s, int len)
short int type
Definition: getparam.h:26
#define ISVOID(var)
Definition: getparam.c:57
int(* option_func_t)(option_t, void *, option_t **)
Definition: getparam.h:32
#define SETFAILED(var)
Definition: getparam.c:50
#define ISFUNC(o)
Definition: getparam.c:18
#define REQUIREARG(o)
Definition: getparam.c:21
unsigned long long char_to_int(const char *s, int i, uint8_t base)
Definition: char_to_int.c:24
#define IS_FAIL_ON_UNKNOWN(o)
Definition: getparam.c:68
#define MAYARG(o)
Definition: getparam.c:20
#define ISNULL(var)
Definition: getparam.c:52
short int char_to_bool(const char *s, size_t len)
Definition: getparam.c:151
#define TYPEBOOL(o)
Definition: getparam.c:23
#define ISSTR(var)
Definition: getparam.c:56
#define ISFAILED(var)
Definition: getparam.c:58
#define TYPLESSVAR
Definition: getparam.c:44
#define ISDOUBLE(var)
Definition: getparam.c:55
#define UNUSED(x)
Used to indicate that a function does not use a certain parameter.
Definition: getparam.c:15
short int check_int(const char *s, int len, uint8_t base)
Definition: char_to_int.c:8
#define GETDOUBLE(var)
Definition: getparam.c:63
#define ISINT(var)
Definition: getparam.c:54
#define SETSTR(var, v)
Definition: getparam.c:48
#define TYPESTR(o)
Definition: getparam.c:25
void print_options_config(option_t *o)
Definition: getparam.c:104