Flowgrind
Advanced TCP traffic generator
fg_argparser.c
Go to the documentation of this file.
1 
6 /*
7  * Copyright (C) 2014 Felix Rietig <felix.rietig@rwth-aachen.de>
8  * Copyright (C) 2006-2013 Antonio Diaz Diaz <antonio@gnu.org>
9  *
10  * This file is part of Flowgrind. It is based on the POSIX/GNU
11  * command line argument parser 'arg_parser' origninally written by
12  * Antonio Diaz Diaz.
13  *
14  * Flowgrind is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * Flowgrind is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with Flowgrind. If not, see <http://www.gnu.org/licenses/>.
26  *
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif /* HAVE_CONFIG_H */
32 
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdbool.h>
37 
38 #include "fg_definitions.h"
39 #include "fg_argparser.h"
40 
48 static void *ap_resize_buffer(void *buf, const int min_size)
49 {
50  if (buf)
51  buf = realloc(buf, min_size);
52  else
53  buf = malloc(min_size);
54  return buf;
55 }
56 
66 static bool push_back_record(struct arg_parser *const ap, const int option_index,
67  bool long_opt, const char *const argument)
68 {
69  const int len = strlen(argument);
70  struct ap_Record *p;
71  void *tmp = ap_resize_buffer(ap->data,
72  (ap->data_size + 1) * sizeof(struct ap_Record));
73  if (!tmp)
74  return false;
75  ap->data = (struct ap_Record *)tmp;
76  p = &(ap->data[ap->data_size]);
78  p->argument = 0;
79  tmp = ap_resize_buffer(p->argument, len + 1);
80  if (!tmp)
81  return false;
82  p->argument = (char *)tmp;
83  strncpy(p->argument, argument, len + 1);
84 
85  if (long_opt) {
86  if (!asprintf(&p->opt_string, "--%s", ap->options[option_index].name))
87  return false;
88  } else {
89  if (!asprintf(&p->opt_string, "-%c", ap->options[option_index].code))
90  return false;
91  }
92 
93  ++ap->data_size;
94  return true;
95 }
96 
104 static bool add_error(struct arg_parser *const ap, const char *const msg)
105 {
106  const int len = strlen(msg);
107  void *tmp = ap_resize_buffer(ap->error, ap->error_size + len + 1);
108  if (!tmp)
109  return false;
110  ap->error = (char *)tmp;
111  strncpy(ap->error + ap->error_size, msg, len + 1);
112  ap->error_size += len;
113 
114  return true;
115 }
116 
122 static void free_data(struct arg_parser *const ap)
123 {
124  for (int i = 0; i < ap->data_size; ++i) {
125  free(ap->data[i].argument);
126  free(ap->data[i].opt_string);
127  }
128  if (ap->data) {
129  free(ap->data);
130  ap->data = 0;
131  }
132  ap->data_size = 0;
133 
134  for (int i = 0; i < ap->num_options; ++i) {
135  free(ap->options[i].name);
136  free(ap->options[i].mutex);
137  }
138  free(ap->options);
139  ap->num_options = 0;
140 }
141 
153 static bool parse_long_option(struct arg_parser *const ap,
154  const char *const opt, const char *const arg,
155  const struct ap_Option options[],
156  int *const argindp)
157 {
158  unsigned len;
159  int index = -1;
160  char exact = 0, ambig = 0;
161 
162  for (len = 0; opt[len + 2] && opt[len + 2] != '='; ++len) ;
163 
164  /* Test all long options for either exact match or abbreviated matches */
165  for (int i = 0; options[i].code != 0; ++i)
166  if (options[i].name
167  && strncmp(options[i].name, &opt[2], len) == 0) {
168  /* Exact match found */
169  if (strlen(options[i].name) == len) {
170  index = i;
171  exact = 1;
172  break;
173  /* First nonexact match found */
174  } else if (index < 0) {
175  index = i;
176  /* Second or later nonexact match found */
177  } else if (options[index].code != options[i].code ||
178  options[index].has_arg != options[i].has_arg) {
179  ambig = 1;
180  }
181  }
182 
183  if (ambig && !exact) {
184  add_error(ap, "option '");
185  add_error(ap, opt);
186  add_error(ap, "' is ambiguous");
187  return true;
188  }
189 
190  /* nothing found */
191  if (index < 0) {
192  add_error(ap, "unrecognized option '");
193  add_error(ap, opt);
194  add_error(ap, "'");
195  return true;
196  }
197 
198  ++*argindp;
199 
200  /* '--<long_option>=<argument>' syntax */
201  if (opt[len + 2]) {
202  if (options[index].has_arg == ap_no) {
203  add_error(ap, "option '--");
204  add_error(ap, options[index].name);
205  add_error(ap, "' doesn't allow an argument");
206  return true;
207  }
208  if (options[index].has_arg == ap_yes && !opt[len + 3]) {
209  add_error(ap, "option '--");
210  add_error(ap, options[index].name);
211  add_error(ap, "' requires an argument");
212  return true;
213  }
214  return push_back_record(ap, index, true, &opt[len + 3]);
215  }
216 
217  if (options[index].has_arg == ap_yes) {
218  if (!arg || !arg[0]) {
219  add_error(ap, "option '--");
220  add_error(ap, options[index].name);
221  add_error(ap, "' requires an argument");
222  return true;
223  }
224  ++*argindp;
225  return push_back_record(ap, index, true, arg);
226  }
227 
228  return push_back_record(ap, index, true, "");
229 }
230 
242 static bool parse_short_option(struct arg_parser *const ap,
243  const char *const opt, const char *const arg,
244  const struct ap_Option options[],
245  int *const argindp)
246 {
247  int cind = 1; /* character index in opt */
248 
249  while (cind > 0) {
250  int index = -1;
251  const unsigned char code = opt[cind];
252  char code_str[2];
253  code_str[0] = code;
254  code_str[1] = 0;
255 
256  if (code != 0)
257  for (int i = 0; options[i].code; ++i)
258  if (code == options[i].code) {
259  index = i;
260  break;
261  }
262 
263  if (index < 0) {
264  add_error(ap, "invalid option -- ");
265  add_error(ap, code_str);
266  return true;
267  }
268 
269  /* opt finished */
270  if (opt[++cind] == 0) {
271  ++*argindp;
272  cind = 0;
273  }
274 
275  if (options[index].has_arg != ap_no && cind > 0 && opt[cind]) {
276  if (!push_back_record(ap, index, false, &opt[cind]))
277  return false;
278  ++*argindp;
279  cind = 0;
280  } else if (options[index].has_arg == ap_yes) {
281  if (!arg || !arg[0]) {
282  add_error(ap, "option requires an argument -- ");
283  add_error(ap, code_str);
284  return true;
285  }
286  ++*argindp;
287  cind = 0;
288  if (!push_back_record(ap, index, false, arg))
289  return false;
290  } else if (!push_back_record(ap, index, false, "")) {
291  return false;
292  }
293  }
294 
295  return true;
296 }
297 
306 static int get_num_options(const struct ap_Option options[])
307 {
308  int i;
309  for (i=0; options[i].code; i++){}
310  return i;
311 }
312 
321 static int get_mutex_count(const struct ap_Option options[])
322 {
323  int num = 0;
324 
325  for (int i=0; options[i].code; i++)
326  for (int *mutex = options[i].mutex; mutex && *mutex; mutex++)
327  ASSIGN_MAX(num, *mutex);
328 
329  return num;
330 }
331 
341 static bool copy_options(struct arg_parser *const ap,
342  const struct ap_Option options[])
343 {
344 
345  ap->num_options = get_num_options(options);
346  if (!ap->num_options)
347  return false;
348  ap->options = malloc(sizeof(struct ap_Option)*ap->num_options);
349  if (!ap->options)
350  return false;
351 
352  for (int i=0; i < ap->num_options; i++) {
353  ap->options[i] = options[i];
354  if (options[i].name)
355  ap->options[i].name = strdup(options[i].name);
356 
357  if (options[i].mutex) {
358  /* get number of mutex items */
359  int num;
360  for (num = 0; options[i].mutex[num]; num++);
361 
362  /* now copy into new array */
363  ap->options[i].mutex = malloc(sizeof(int)*
364  (num+1));
365  if (!ap->options[i].mutex)
366  return false;
367  for (int e=0; e<=num; e++)
368  ap->options[i].mutex[e] = options[i].mutex[e];
369  }
370  }
371  return true;
372 }
373 
374 bool ap_init(struct arg_parser *const ap,
375  const int argc, const char *const argv[],
376  const struct ap_Option options[], const char in_order)
377 {
378  const char **non_options = 0; /* skipped non-options */
379  int non_options_size = 0; /* number of skipped non-options */
380  int argind = 1; /* index in argv */
381 
382  if (!copy_options(ap,options))
383  return false;
384 
385  ap->num_mutex = get_mutex_count(options);
386 
387  ap->data = 0;
388  ap->error = 0;
389  ap->data_size = 0;
390  ap->error_size = 0;
391  if (argc < 2 || !argv || !options)
392  return true;
393 
394  while (argind < argc) {
395  const unsigned char ch1 = argv[argind][0];
396  const unsigned char ch2 = (ch1 ? argv[argind][1] : 0);
397 
398  if (ch1 == '-' && ch2) { /* we found an option */
399  const char *const opt = argv[argind];
400  const char *const arg =
401  (argind + 1 < argc) ? argv[argind + 1] : 0;
402  if (ch2 == '-') {
403  if (!argv[argind][2]) {
404  ++argind; /* we found "--" */
405  break;
406  } else {
407  if (!parse_long_option
408  (ap, opt, arg, options, &argind))
409  return false;
410  }
411  } else {
412  if (!parse_short_option
413  (ap, opt, arg, options, &argind))
414  return false;
415  }
416  if (ap->error)
417  break;
418  } else {
419  if (!in_order) {
420  void *tmp = ap_resize_buffer(non_options, (non_options_size + 1) *
421  sizeof *non_options);
422  if (!tmp)
423  return false;
424  non_options = (const char **)tmp;
425  non_options[non_options_size++] = argv[argind++];
426  } else if (!push_back_record(ap, ap->num_options, false, argv[argind++])) {
427  return false;
428  }
429  }
430  }
431 
432  if (ap->error) {
433  free_data(ap);
434  } else {
435  for (int i = 0; i < non_options_size; ++i)
436  if (!push_back_record(ap, ap->num_options, false, non_options[i]))
437  return false;
438  while (argind < argc)
439  if (!push_back_record(ap, ap->num_options, false, argv[argind++]))
440  return false;
441  }
442 
443  if (non_options)
444  free(non_options);
445  return true;
446 }
447 
448 void ap_free(struct arg_parser *const ap)
449 {
450  free_data(ap);
451  if (ap->error) {
452  free(ap->error);
453  ap->error = 0;
454  }
455  ap->error_size = 0;
456 }
457 
458 const char *ap_error(const struct arg_parser *const ap)
459 {
460  return ap->error;
461 }
462 
463 int ap_arguments(const struct arg_parser *const ap)
464 {
465  return ap->data_size;
466 }
467 
468 int ap_code(const struct arg_parser *const ap, const int i)
469 {
470  if (i >= 0 && i < ap_arguments(ap)) {
471  int index = ap->data[i].option_index;
472  return ap->options[index].code;
473  } else {
474  return false;
475  }
476 }
477 
478 const char *ap_argument(const struct arg_parser *const ap, const int i)
479 {
480  if (i >= 0 && i < ap_arguments(ap))
481  return ap->data[i].argument;
482  else
483  return "";
484 }
485 
486 const char *ap_opt_string(const struct arg_parser *const ap, const int i)
487 {
488  if (i >= 0 && i < ap_arguments(ap))
489  return ap->data[i].opt_string;
490  else
491  return "";
492 }
493 
494 const struct ap_Option *ap_option(const struct arg_parser *const ap,
495  const int i)
496 {
497  if (i >= 0 && i < ap_arguments(ap))
498  return &ap->options[ap->data[i].option_index];
499  else
500  return false;
501 }
502 
503 bool ap_is_used(const struct arg_parser *const ap, int code)
504 {
505  bool ret = false;
506 
507  for (int i=0; i < ap->data_size; i++)
508  if (ap_code(ap, i) == code) {
509  ret = true;
510  break;
511  }
512 
513  return ret;
514 }
515 
516 bool ap_init_mutex_state(const struct arg_parser *const ap,
517  struct ap_Mutex_state *const ms)
518 {
519  ms->seen_records = malloc(sizeof(int)*ap->num_mutex);
520  if(!ap->num_mutex || !ms->seen_records)
521  return false;
522  memset(ms->seen_records,0,sizeof(int)*ap->num_mutex);
523  ms->num_mutex = ap->num_mutex;
524  return true;
525 }
526 
527 bool ap_check_mutex(const struct arg_parser *const ap,
528  const struct ap_Mutex_state *const ms,
529  const int i, int *conflict)
530 {
531  if(ap->num_mutex != ms->num_mutex)
532  return false;
533 
534  *conflict = 0;
535 
536  if (i < 0 || i >= ap_arguments(ap) || !ap->num_mutex)
537  return false;
538 
539  int index = ap->data[i].option_index;
540  for (int *mutex = ap->options[index].mutex; mutex && *mutex; mutex++) {
541  if (ms->seen_records[*mutex-1]) {
542  *conflict = ms->seen_records[*mutex-1]-1;
543  if (ap->data[*conflict].option_index != index)
544  return true;
545  else
546  *conflict = 0;
547  }
548  }
549 
550  return false;
551 }
552 
553 bool ap_set_mutex(const struct arg_parser *const ap,
554  struct ap_Mutex_state *const ms, const int i)
555 {
556  if(ap->num_mutex != ms->num_mutex)
557  return false;
558 
559  if (i < 0 || i >= ap_arguments(ap) || !ap->num_mutex)
560  return false;
561 
562  int index = ap->data[i].option_index;
563  for (int *mutex = ap->options[index].mutex; mutex && *mutex; mutex++)
564  ms->seen_records[*mutex-1] = i+1;
565 
566  return true;
567 }
568 
569 bool ap_set_check_mutex(const struct arg_parser *const ap,
570  struct ap_Mutex_state *const ms, const int i,
571  int *conflict)
572 {
573  bool ret = ap_check_mutex(ap, ms, i, conflict);
574  ap_set_mutex(ap, ms, i);
575  return ret;
576 }
577 
578 void ap_reset_mutex(struct ap_Mutex_state *const ms)
579 {
580  memset(ms->seen_records,0,sizeof(int)*ms->num_mutex);
581 }
582 
583 void ap_free_mutex_state(struct ap_Mutex_state *const ms)
584 {
585  if (ms->seen_records) {
586  free(ms->seen_records);
587  ms->seen_records = 0;
588  ms->num_mutex = 0;
589  }
590 }
591 
get_num_options
static int get_num_options(const struct ap_Option options[])
Determines number of options in options.
Definition: fg_argparser.c:306
ASSIGN_MAX
#define ASSIGN_MAX(s, c)
Assign value if it's greater than current one.
Definition: fg_definitions.h:68
get_mutex_count
static int get_mutex_count(const struct ap_Option options[])
Get the number of mutex in the option definitions.
Definition: fg_argparser.c:321
arg_parser::error_size
int error_size
Real size of the error string.
Definition: fg_argparser.h:85
ap_option
const struct ap_Option * ap_option(const struct arg_parser *const ap, const int i)
Get the user-defined option for a given record position.
Definition: fg_argparser.c:494
ap_code
int ap_code(const struct arg_parser *const ap, const int i)
Returns the code of a parsed option with given index.
Definition: fg_argparser.c:468
ap_argument
const char * ap_argument(const struct arg_parser *const ap, const int i)
Returns the argument of a parsed option.
Definition: fg_argparser.c:478
ap_error
const char * ap_error(const struct arg_parser *const ap)
Get the string containing errors encountered during parsing.
Definition: fg_argparser.c:458
ap_Mutex_state::seen_records
int * seen_records
A table containing for each mutex the last seen option record.
Definition: fg_argparser.h:93
arg_parser
Internal state of the argument parser.
Definition: fg_argparser.h:73
ap_no
@ ap_no
Option without argument (flag).
Definition: fg_argparser.h:37
ap_Option::mutex
int * mutex
Null-terminated array of mutex IDs (greater zero) this option belongs to.
Definition: fg_argparser.h:59
ap_reset_mutex
void ap_reset_mutex(struct ap_Mutex_state *const ms)
Reset a mutex context.
Definition: fg_argparser.c:578
arg_parser::num_mutex
int num_mutex
The number of defined mutex.
Definition: fg_argparser.h:87
parse_long_option
static bool parse_long_option(struct arg_parser *const ap, const char *const opt, const char *const arg, const struct ap_Option options[], int *const argindp)
Parses a long option and adds it to the record of arg-parser ap.
Definition: fg_argparser.c:153
arg_parser::data
struct ap_Record * data
Container for parsed cmdline options.
Definition: fg_argparser.h:77
ap_yes
@ ap_yes
Argument required.
Definition: fg_argparser.h:39
ap_check_mutex
bool ap_check_mutex(const struct arg_parser *const ap, const struct ap_Mutex_state *const ms, const int i, int *conflict)
Check a new option record for mutex.
Definition: fg_argparser.c:527
ap_Mutex_state
Contains the state of all mutex.
Definition: fg_argparser.h:91
copy_options
static bool copy_options(struct arg_parser *const ap, const struct ap_Option options[])
Copy options into the arg-parser ap.
Definition: fg_argparser.c:341
ap_Option::code
int code
Short option letter or code (code != 0).
Definition: fg_argparser.h:47
ap_is_used
bool ap_is_used(const struct arg_parser *const ap, int code)
Returns true if the option specified by code was given at least once.
Definition: fg_argparser.c:503
mutex
pthread_mutex_t mutex
Definition: daemon.c:93
arg_parser::data_size
int data_size
Number of parsed records.
Definition: fg_argparser.h:83
free_data
static void free_data(struct arg_parser *const ap)
Free all space required by the arg-parser ap.
Definition: fg_argparser.c:122
ap_set_check_mutex
bool ap_set_check_mutex(const struct arg_parser *const ap, struct ap_Mutex_state *const ms, const int i, int *conflict)
Check a new option record for mutex and register it at the same time.
Definition: fg_argparser.c:569
add_error
static bool add_error(struct arg_parser *const ap, const char *const msg)
Add an error message to the arg-parser ap.
Definition: fg_argparser.c:104
push_back_record
static bool push_back_record(struct arg_parser *const ap, const int option_index, bool long_opt, const char *const argument)
Store a parsed option in the state of the arg-parser given by ap.
Definition: fg_argparser.c:66
ap_free
void ap_free(struct arg_parser *const ap)
Free internal state of arg-parser.
Definition: fg_argparser.c:448
arg_parser::num_options
int num_options
Number of known options.
Definition: fg_argparser.h:81
ap_resize_buffer
static void * ap_resize_buffer(void *buf, const int min_size)
Assure at least a minimum size for buffer buf.
Definition: fg_argparser.c:48
ap_arguments
int ap_arguments(const struct arg_parser *const ap)
Number of arguments parsed (may be different from argc).
Definition: fg_argparser.c:463
ap_Record::argument
char * argument
Argument string (may be empty).
Definition: fg_argparser.h:67
fg_argparser.h
Command line argument parser.
ap_free_mutex_state
void ap_free_mutex_state(struct ap_Mutex_state *const ms)
Free a mutex context.
Definition: fg_argparser.c:583
ap_Option
Defines a valid command line option.
Definition: fg_argparser.h:45
fg_definitions.h
Common definitions used by the Flowgrind daemon, controller, and libs.
arg_parser::error
char * error
Contains errors encountered during parsing.
Definition: fg_argparser.h:79
ap_Option::name
char * name
Long option name (maybe null).
Definition: fg_argparser.h:49
parse_short_option
static bool parse_short_option(struct arg_parser *const ap, const char *const opt, const char *const arg, const struct ap_Option options[], int *const argindp)
Parses a short option and adds it to the record of arg-parser ap.
Definition: fg_argparser.c:242
ap_opt_string
const char * ap_opt_string(const struct arg_parser *const ap, const int i)
Get the real command line option string (may be the short or long version).
Definition: fg_argparser.c:486
config.h
ap_init_mutex_state
bool ap_init_mutex_state(const struct arg_parser *const ap, struct ap_Mutex_state *const ms)
Initialize a new mutex state table.
Definition: fg_argparser.c:516
ap_Record::option_index
int option_index
Index of the option for internal use (e.g.
Definition: fg_argparser.h:69
ap_Mutex_state::num_mutex
int num_mutex
The number of defined mutex.
Definition: fg_argparser.h:95
ap_init
bool ap_init(struct arg_parser *const ap, const int argc, const char *const argv[], const struct ap_Option options[], const char in_order)
Initialize the arg-parser given command line and user-defined options.
Definition: fg_argparser.c:374
arg_parser::options
struct ap_Option * options
Array containing user-defined options.
Definition: fg_argparser.h:75
ap_set_mutex
bool ap_set_mutex(const struct arg_parser *const ap, struct ap_Mutex_state *const ms, const int i)
Register an option record in a mutex context.
Definition: fg_argparser.c:553
ap_Record::opt_string
char * opt_string
Observed opt string (maybe the long or the short version).
Definition: fg_argparser.h:65
ap_Record
Holds a parsed command line option and its argument.
Definition: fg_argparser.h:63