IOR
option.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <limits.h>
7 
8 #include <option.h>
9 
10 
11 /* merge two option lists and return the total size */
13  int count_a = 0;
14  for(option_help * i = a; i->type != 0; i++){
15  count_a++;
16  }
17  int count = count_a + 1; // LAST_OPTION is one
18  for(option_help * i = b; i->type != 0; i++){
19  count++;
20  }
21  option_help * h = malloc(sizeof(option_help) * count);
22  memcpy(h, a, sizeof(option_help) * count_a);
23  memcpy(h + count_a, b, sizeof(option_help) * (count - count_a));
24  return h;
25 }
26 
27 /*
28 * Takes a string of the form 64, 8m, 128k, 4g, etc. and converts to bytes.
29 */
30 int64_t string_to_bytes(char *size_str)
31 {
32  int64_t size = 0;
33  char range;
34  int rc;
35 
36  rc = sscanf(size_str, " %lld %c ", (long long*) & size, &range);
37  if (rc == 2) {
38  switch ((int)range) {
39  case 'k':
40  case 'K':
41  size <<= 10;
42  break;
43  case 'm':
44  case 'M':
45  size <<= 20;
46  break;
47  case 'g':
48  case 'G':
49  size <<= 30;
50  break;
51  case 't':
52  case 'T':
53  size <<= 40;
54  break;
55  case 'p':
56  case 'P':
57  size <<= 50;
58  break;
59  }
60  } else if (rc == 0) {
61  size = -1;
62  }
63  return (size);
64 }
65 
66 /*
67  * Initial revision by JK
68  */
69 
70 static int print_value(option_help * o){
71  int pos = 0;
73  assert(o->variable != NULL);
74 
75  switch(o->type){
76  case('p'):{
77  pos += printf("=STRING");
78  break;
79  }
80  case('F'):{
81  pos += printf("=%.14f ", *(double*) o->variable);
82  break;
83  }
84  case('f'):{
85  pos += printf("=%.6f ", (double) *(float*) o->variable);
86  break;
87  }
88  case('d'):{
89  pos += printf("=%d ", *(int*) o->variable);
90  break;
91  }
92  case('H'):
93  case('s'):{
94  if ( *(char**) o->variable != NULL && ((char**) o->variable)[0][0] != 0 ){
95  pos += printf("=%s", *(char**) o->variable);
96  }else{
97  pos += printf("=STRING");
98  }
99  break;
100  }
101  case('c'):{
102  pos += printf("=%c", *(char*) o->variable);
103  break;
104  }
105  case('l'):{
106  pos += printf("=%lld", *(long long*) o->variable);
107  break;
108  }
109  case('u'):{
110  pos += printf("=%lu", *(uint64_t*) o->variable);
111  break;
112  }
113  }
114  }
115  if (o->arg == OPTION_FLAG && (*(int*)o->variable) != 0){
116  pos += printf(" (%d)", (*(int*)o->variable));
117  }
118 
119  return pos;
120 }
121 
122 static void print_help_section(option_help * args, option_value_type type, char * name){
123  int first;
124  first = 1;
125  option_help * o;
126  for(o = args; o->shortVar != 0 || o->longVar != 0 || o->help != NULL ; o++){
127 
128  if (o->arg == type){
129  if( o->shortVar == 0 && o->longVar == 0 && o->help != NULL){
130  printf("%s\n", o->help);
131  continue;
132  }
133  if (first){
134  printf("\n%s\n", name);
135  first = 0;
136  }
137  printf(" ");
138  int pos = 0;
139  if(o->shortVar != 0 && o->longVar != 0){
140  pos += printf("-%c, --%s", o->shortVar, o->longVar);
141  }else if(o->shortVar != 0){
142  pos += printf("-%c", o->shortVar);
143  }else if(o->longVar != 0){
144  pos += printf("--%s", o->longVar);
145  }
146 
147  pos += print_value(o);
148  if(o->help != NULL){
149  for(int i = 0 ; i < (30 - pos); i++){
150  printf(" ");
151  }
152  printf("%s", o->help);
153  }
154  printf("\n");
155  }
156  }
157 }
158 
160  print_help_section(args, OPTION_REQUIRED_ARGUMENT, "Required arguments");
161  print_help_section(args, OPTION_FLAG, "Flags");
162  print_help_section(args, OPTION_OPTIONAL_ARGUMENT, "Optional arguments");
163 }
164 
165 
167  int pos = 0;
169  assert(o->variable != NULL);
170 
171  switch(o->type){
172  case('F'):{
173  pos += printf("=%.14f ", *(double*) o->variable);
174  break;
175  }
176  case('f'):{
177  pos += printf("=%.6f ", (double) *(float*) o->variable);
178  break;
179  }
180  case('d'):{
181  pos += printf("=%d ", *(int*) o->variable);
182  break;
183  }
184  case('H'):{
185  pos += printf("=HIDDEN");
186  break;
187  }
188  case('s'):{
189  if ( *(char**) o->variable != NULL && ((char**) o->variable)[0][0] != 0 ){
190  pos += printf("=%s", *(char**) o->variable);
191  }else{
192  pos += printf("=");
193  }
194  break;
195  }
196  case('c'):{
197  pos += printf("=%c", *(char*) o->variable);
198  break;
199  }
200  case('l'):{
201  pos += printf("=%lld", *(long long*) o->variable);
202  break;
203  }
204  case('u'):{
205  pos += printf("=%lu", *(uint64_t*) o->variable);
206  break;
207  }
208  }
209  }else{
210  //printf(" ");
211  }
212 
213  return pos;
214 }
215 
216 
218  option_help * o;
219  for(o = args; o->shortVar != 0 || o->longVar != 0 ; o++){
220  if (o->arg == type){
221  int pos = 0;
222  if (o->arg == OPTION_FLAG && (*(int*)o->variable) == 0){
223  continue;
224  }
225  printf("\t");
226 
227  if(o->shortVar != 0 && o->longVar != 0){
228  pos += printf("%s", o->longVar);
229  }else if(o->shortVar != 0){
230  pos += printf("%c", o->shortVar);
231  }else if(o->longVar != 0){
232  pos += printf("%s", o->longVar);
233  }
234 
235  pos += print_option_value(o);
236  printf("\n");
237  }
238  }
239 }
240 
241 
246 }
247 
248 static void option_parse_token(char ** argv, int * flag_parsed_next, int * requiredArgsSeen, options_all_t * opt_all, int * error, int * print_help){
249  char * txt = argv[0];
250  char * arg = strstr(txt, "=");
251 
252  int replaced_equal = 0;
253  int i = 0;
254  if(arg != NULL){
255  arg[0] = 0;
256  replaced_equal = 1;
257 
258  // Check empty value
259  arg = (arg[1] == 0) ? NULL : arg + 1;
260  }
261  *flag_parsed_next = 0;
262 
263  // just skip over the first dash so we don't have to handle it everywhere below
264  if(txt[0] != '-'){
265  *error = 1;
266  return;
267  }
268  txt++;
269  int parsed = 0;
270 
271  // printf("Parsing: %s : %s\n", txt, arg);
272  // support groups of multiple flags like -vvv or -vq
273  for(int flag_index = 0; flag_index < strlen(txt); ++flag_index){
274  // don't loop looking for multiple flags if we already processed a long option
275  if(txt[flag_index] == '=' || (txt[0] == '-' && flag_index > 0))
276  break;
277 
278  for(int m = 0; m < opt_all->module_count; m++ ){
279  option_help * args = opt_all->modules[m].options;
280  if(args == NULL) continue;
281  // try to find matching option help
282  for(option_help * o = args; o->shortVar != 0 || o->longVar != 0 || o->help != NULL ; o++ ){
283  if( o->shortVar == 0 && o->longVar == 0 ){
284  // section
285  continue;
286  }
287  if ( (o->shortVar == txt[flag_index]) || (strlen(txt) > 2 && txt[0] == '-' && o->longVar != NULL && strcmp(txt + 1, o->longVar) == 0)){
288  // printf("Found %s %c=%c? %d %d\n", o->help, o->shortVar, txt[flag_index], (o->shortVar == txt[flag_index]), (strlen(txt) > 2 && txt[0] == '-' && o->longVar != NULL && strcmp(txt + 1, o->longVar) == 0));
289  // now process the option.
290  switch(o->arg){
291  case (OPTION_FLAG):{
292  assert(o->type == 'd');
293  if(arg != NULL){
294  int val = atoi(arg);
295  (*(int*) o->variable) = (val < 0) ? 0 : val;
296  }else{
297  (*(int*) o->variable)++;
298  }
299  break;
300  }
302  case (OPTION_REQUIRED_ARGUMENT):{
303  // check if next is an argument
304  if(arg == NULL && replaced_equal != 1){
305  if(o->shortVar == txt[0] && txt[1] != 0){
306  arg = & txt[1];
307  }else{
308  // simply take the next value as argument
309  i++;
310  arg = argv[1];
311  *flag_parsed_next = 1;
312  }
313  }
314 
315  if(arg == NULL){
316  const char str[] = {o->shortVar, 0};
317  printf("Error, argument missing for option %s\n", (o->longVar != NULL) ? o->longVar : str);
318  exit(1);
319  }
320 
321  switch(o->type){
322  case('p'):{
323  // call the function in the variable
324  void(*fp)() = o->variable;
325  fp(arg);
326  break;
327  }
328  case('F'):{
329  *(double*) o->variable = atof(arg);
330  break;
331  }
332  case('f'):{
333  *(float*) o->variable = atof(arg);
334  break;
335  }
336  case('d'):{
337  int64_t val = string_to_bytes(arg);
338  if (val > INT_MAX || val < INT_MIN){
339  printf("WARNING: parsing the number %s to integer, this produced an overflow!\n", arg);
340  }
341  *(int*) o->variable = val;
342  break;
343  }
344  case('H'):
345  case('s'):{
346  (*(char **) o->variable) = strdup(arg);
347  break;
348  }
349  case('c'):{
350  (*(char *)o->variable) = arg[0];
351  if(strlen(arg) > 1){
352  printf("Error, ignoring remainder of string for option %c (%s).\n", o->shortVar, o->longVar);
353  }
354  break;
355  }
356  case('l'):{
357  *(long long*) o->variable = string_to_bytes(arg);
358  break;
359  }
360  case('u'):{
361  *(uint64_t*) o->variable = string_to_bytes(arg);
362  break;
363  }
364  default:
365  printf("ERROR: Unknown option type %c\n", o->type);
366  break;
367  }
368  }
369  }
370  if(replaced_equal){
371  arg[-1] = '=';
372  }
373 
374  if(o->arg == OPTION_REQUIRED_ARGUMENT){
375  (*requiredArgsSeen)++;
376  }
377 
378  parsed = 1;
379  }
380  }
381  }
382  }
383  if(parsed) return;
384 
385  if(strcmp(txt, "h") == 0 || strcmp(txt, "-help") == 0){
386  *print_help = 1;
387  }else{
388  *error = 1;
389  }
390 }
391 
392 int option_parse_str(char*val, options_all_t * opt_all){
393  int flag_parsed_next;
394  int error = 0;
395  int requiredArgsSeen = 0;
396  int print_help = 0;
397  char * argv[2] = {val, NULL};
398  option_parse_token(argv, & flag_parsed_next, & requiredArgsSeen, opt_all, & error, & print_help);
399  return error;
400 }
401 
402 int option_parse_key_value(char * key, char *val, options_all_t * opt_all){
403  int flag_parsed_next;
404  int error = 0;
405  int requiredArgsSeen = 0;
406  int print_help = 0;
407  char value[1024];
408  sprintf(value, "%s=%s", key, val);
409  char * argv[2] = {value, NULL};
410  option_parse_token(argv, & flag_parsed_next, & requiredArgsSeen, opt_all, & error, & print_help);
411  return error;
412 }
413 
414 int option_parse(int argc, char ** argv, options_all_t * opt_all){
415  int error = 0;
416  int requiredArgsSeen = 0;
417  int requiredArgsNeeded = 0;
418  int i;
419  int printhelp = 0;
420 
421  for(int m = 0; m < opt_all->module_count; m++ ){
422  option_help * args = opt_all->modules[m].options;
423  if(args == NULL) continue;
424  for(option_help * o = args; o->shortVar != 0 || o->longVar != 0 ; o++ ){
425  if(o->arg == OPTION_REQUIRED_ARGUMENT){
426  requiredArgsNeeded++;
427  }
428  }
429  }
430 
431  for(i=1; i < argc; i++){
432  int flag_parsed_next;
433  option_parse_token(& argv[i], & flag_parsed_next, & requiredArgsSeen, opt_all, & error, & printhelp);
434  if (flag_parsed_next){
435  i++;
436  }
437  if(error){
438  printf("Error invalid argument: %s\n", argv[i]);
439  }
440  }
441 
442  if( requiredArgsSeen != requiredArgsNeeded ){
443  printf("Error: Missing some required arguments\n\n");
444  printhelp = 1;
445  }
446 
447  if(error != 0){
448  printf("Invalid options\n");
449  printhelp = 1;
450  }
451 
452  if(printhelp == 1){
453  printf("Synopsis %s\n", argv[0]);
454  for(int m = 0; m < opt_all->module_count; m++ ){
455  option_help * args = opt_all->modules[m].options;
456  if(args == NULL) continue;
457  char * prefix = opt_all->modules[m].prefix;
458  if(prefix != NULL){
459  printf("\n\nModule %s\n", prefix);
460  }
461  option_print_help(args);
462  }
463  exit(0);
464  }
465 
466  return i;
467 }
option_module * modules
Definition: option.h:36
CURLcode rc
Definition: aiori-S3-4c.c:111
int option_parse(int argc, char **argv, options_all_t *opt_all)
Definition: option.c:414
struct benchmark_options o
Definition: md-workbench.c:128
option_value_type
Definition: option.h:10
void * variable
Definition: option.h:23
void option_print_help(option_help *args)
Definition: option.c:159
char * longVar
Definition: option.h:18
static void print_current_option_section(option_help *args, option_value_type type)
Definition: option.c:217
static void option_parse_token(char **argv, int *flag_parsed_next, int *requiredArgsSeen, options_all_t *opt_all, int *error, int *print_help)
Definition: option.c:248
char shortVar
Definition: option.h:17
void option_print_current(option_help *args)
Definition: option.c:242
static int print_option_value(option_help *o)
Definition: option.c:166
int option_parse_key_value(char *key, char *val, options_all_t *opt_all)
Definition: option.c:402
option_value_type arg
Definition: option.h:21
int option_parse_str(char *val, options_all_t *opt_all)
Definition: option.c:392
static int print_value(option_help *o)
Definition: option.c:70
int64_t string_to_bytes(char *size_str)
Definition: option.c:30
char * help
Definition: option.h:19
option_help * options
Definition: option.h:30
static void print_help_section(option_help *args, option_value_type type, char *name)
Definition: option.c:122
char * prefix
Definition: option.h:29
int module_count
Definition: option.h:35
char type
Definition: option.h:22
option_help * option_merge(option_help *a, option_help *b)
Definition: option.c:12
#define NULL
Definition: iordef.h:70