ROSS
tw-opts.c
Go to the documentation of this file.
1#include <ctype.h>
2#include <ross.h>
3#include <string.h>
4
5#ifndef ARRAY_SIZE
6#define ARRAY_SIZE(a) ( sizeof((a)) / sizeof((a)[0]) )
7#endif
8
9static const char *program;
10static const tw_optdef *all_groups[10];
11
12static void need_argument(const tw_optdef *def) NORETURN;
13static int is_empty(const tw_optdef *def);
14static void parse_args_file(const char* file_name, int* argc_p, char ***argv_p);
15
16static const tw_optdef *opt_groups[10];
17static unsigned int opt_index = 0;
18
19// We don't allow recursive invocations of the `args-file` option
20static uint args_file_depth = 0;
21
22void
23tw_opt_add(const tw_optdef *options)
24{
25 if(!options || !options->type || is_empty(options))
26 return;
27
28 opt_groups[opt_index++] = options;
29 opt_groups[opt_index] = NULL;
30}
31
32static void
34{
35 const tw_optdef **group = all_groups;
36 unsigned cnt = 0;
37
38 fprintf(stderr, "usage: %s [options] [-- [args]]\n", program);
39 fputc('\n', stderr);
40
41 for (; *group; group++)
42 {
43 const tw_optdef *def = *group;
44 for (; def->type; def++)
45 {
46 int pos = 0;
47
48 if (def->type == TWOPTTYPE_GROUP)
49 {
50 if (cnt)
51 fputc('\n', stderr);
52 fprintf(stderr, "%s:\n", def->help);
53 cnt++;
54 continue;
55 }
56
57 pos += fprintf(stderr, " --%s", def->name);
58 switch (def->type)
59 {
60 case TWOPTTYPE_ULONG:
62 case TWOPTTYPE_UINT:
63 pos += fprintf(stderr, "=n");
64 break;
65
67 pos += fprintf(stderr, "=dbl");
68 break;
69
70 case TWOPTTYPE_STIME:
71 pos += fprintf(stderr, "=ts");
72 break;
73
74 case TWOPTTYPE_CHAR:
75 pos += fprintf(stderr, "=str");
76 break;
77
78 default:
79 break;
80 }
81
82 if (def->help)
83 {
84 int col = 22;
85 int pad = col - pos;
86 if (pad > 0)
87 fprintf(stderr, "%*s", col - pos, "");
88 else {
89 fputc('\n', stderr);
90 fprintf(stderr, "%*s", col, "");
91 }
92 fputs(" ", stderr);
93 fputs(def->help, stderr);
94 }
95
96 if (def->value)
97 {
98 switch (def->type)
99 {
100 case TWOPTTYPE_ULONG:
101 fprintf(stderr, " (default %lu)", *((unsigned long*)def->value));
102 break;
103
105 fprintf(stderr, " (default %llu)", *((unsigned long long*)def->value));
106 break;
107
108 case TWOPTTYPE_UINT:
109 fprintf(stderr, " (default %u)", *((unsigned int*)def->value));
110 break;
111
112 case TWOPTTYPE_DOUBLE:
113 fprintf(stderr, " (default %.2f)", *((double*)def->value));
114 break;
115
116 case TWOPTTYPE_STIME:
117 fprintf(stderr, " (default %.2f)", *((tw_stime*)def->value));
118 break;
119
120 case TWOPTTYPE_CHAR:
121 fprintf(stderr, " (default %s)", (char *) def->value);
122 break;
123
124 case TWOPTTYPE_FLAG:
125 if((*(unsigned int*)def->value) == 0) {
126 fprintf(stderr, " (default off)");
127 } else {
128 fprintf(stderr, " (default on)");
129 }
130 break;
131
132 default:
133 break;
134 }
135 }
136
137 fputc('\n', stderr);
138 cnt++;
139 }
140 }
141
142 // CMake used to pass options by command line flags
143 fprintf(stderr, "ROSS CMake Configuration Options:\n");
144 fprintf(stderr, " (See build-dir/core/config.h)\n");
145}
146
147void tw_opt_settings(FILE *outfile) {
148 const tw_optdef **group = all_groups;
149 unsigned cnt = 0;
150
151 for (; *group; group++){
152 const tw_optdef *def = *group;
153 for (; def->type; def++){
154 int pos = 0;
155
156 if (def->type == TWOPTTYPE_GROUP){
157 if (cnt)
158 fputc('\n', outfile);
159 fprintf(outfile, "%s:\n", def->help);
160 cnt++;
161 continue;
162 }
163
164 pos += fprintf(outfile, " --%s", def->name);
165
166 if (def->value) {
167 int col = 20;
168 int pad = col - pos;
169 if (pad > 0) {
170 fprintf(outfile, "%*s", col - pos, "");
171 } else {
172 fputc('\n', outfile);
173 fprintf(outfile, "%*s", col, "");
174 }
175 fputs(" ", outfile);
176 }
177
178 if (def->value){
179 switch (def->type){
180 case TWOPTTYPE_ULONG:
181 fprintf(outfile, "%lu", *((unsigned long*)def->value));
182 break;
183
185 fprintf(outfile, "%llu", *((unsigned long long*)def->value));
186 break;
187
188 case TWOPTTYPE_UINT:
189 fprintf(outfile, "%u", *((unsigned int*)def->value));
190 break;
191
192 case TWOPTTYPE_DOUBLE:
193 fprintf(outfile, "%.2f", *((double*)def->value));
194 break;
195
196 case TWOPTTYPE_STIME:
197 fprintf(outfile, "%.2f", *((tw_stime*)def->value));
198 break;
199
200 case TWOPTTYPE_CHAR:
201 fprintf(outfile, "%s", (char *) def->value);
202 break;
203
204 case TWOPTTYPE_FLAG:
205 if((*(unsigned int*)def->value) == 0) {
206 fprintf(outfile, "off");
207 } else {
208 fprintf(outfile, "on");
209 }
210 break;
211
212 default:
213 break;
214 }
215 }
216
217 fputc('\n', outfile);
218 cnt++;
219 }
220 }
221}
222
223void
225{
226 FILE *f = g_tw_csv;
227 const tw_optdef **group = all_groups;
228
229 if(!tw_ismaster() || NULL == f)
230 return;
231
232 for (; *group; group++)
233 {
234 const tw_optdef *def = *group;
235 for (; def->type; def++)
236 {
237 if (def->type == TWOPTTYPE_GROUP ||
238 (def->name && 0 == strcmp(def->name, "help")))
239 continue;
240
241 if (def->value)
242 {
243 switch (def->type)
244 {
245 case TWOPTTYPE_ULONG:
246 fprintf(f, "%lu,", *((unsigned long*)def->value));
247 break;
248
250 fprintf(f, "%llu,", *((unsigned long long*)def->value));
251 break;
252
253 case TWOPTTYPE_UINT:
254 fprintf(f, "%u,", *((unsigned int*)def->value));
255 break;
256
257 case TWOPTTYPE_DOUBLE:
258 fprintf(f, "%.2f,", *((double*)def->value));
259 break;
260
261 case TWOPTTYPE_STIME:
262 fprintf(f, "%.2f,", *((tw_stime*)def->value));
263 break;
264
265 case TWOPTTYPE_CHAR:
266 fprintf(f, "%s,", (char *)def->value);
267 break;
268
269 case TWOPTTYPE_FLAG:
270 fprintf(f, "%s,", (char *)def->name);
271 break;
272
273 default:
274 break;
275 }
276 } else
277 fprintf(f, "undefined,");
278 }
279 }
280
281 //print_options(f);
282}
283
284static void
286{
287 if (tw_ismaster())
288 fprintf(stderr,
289 "%s: option --%s requires a valid argument\n",
290 program, def->name);
291 tw_net_stop();
292 exit(1);
293}
294
295// Trims left spaces and returns NULL if the string is empty or has a comment (starts with #)
296char *ltrim(char *s)
297{
298 while(isspace(*s)) s++;
299 if (*s == '\0' || *s == '#') { return NULL; }
300 return s;
301}
302
303// Returns the next argument and leaves `line` pointer at the end of the argument, so that it can be consumed further
304char *next_argument(char **line) {
305 char * to_ret = *line;
306 // consuming characters until we have traversed a full argument
307 // An argument doesn't have any spaces on it
308 while(!(isspace(**line) || **line == '\0' || **line == '#')) {
309 (*line)++;
310 }
311
312 switch (**line) {
313 case '\0':
314 break;
315 case '#': // we don't care about the rest of the line
316 **line = '\0';
317 break;
318 default: // the next character is a space, so there might be more arguments in the same line
319 **line = '\0';
320 (*line)++;
321 }
322
323 return to_ret;
324}
325
326static void
327apply_opt(const tw_optdef *def, const char *value)
328{
329 switch (def->type)
330 {
331 case TWOPTTYPE_ULONG:
333 case TWOPTTYPE_UINT:
334 {
335 unsigned long v;
336 char *end;
337
338 if (!value)
339 need_argument(def);
340 v = strtoul(value, &end, 10);
341
342 if (*end)
343 need_argument(def);
344 switch (def->type)
345 {
346 case TWOPTTYPE_ULONG:
347 *((unsigned long*)def->value) = v;
348 break;
350 *((unsigned long long*)def->value) = v;
351 break;
352
353 case TWOPTTYPE_UINT:
354 *((unsigned int*)def->value) = (unsigned int)v;
355 break;
356 default:
357 tw_error(TW_LOC, "Option type not supported here.");
358 }
359 break;
360 }
361
362 case TWOPTTYPE_DOUBLE:
363 {
364 double v;
365 char *end;
366
367 if (!value)
368 need_argument(def);
369 v = strtod(value, &end);
370 if (*end)
371 need_argument(def);
372 *((double*)def->value) = v;
373 break;
374 }
375
376 case TWOPTTYPE_STIME:
377 {
378 tw_stime v;
379 char *end;
380
381 tw_warning(TW_LOC, "Option type stime (TWOPT_STIME) is deprecated. Please use double (TWOPT_DOUBLE).");
382
383 if (!value)
384 need_argument(def);
385 v = strtod(value, &end);
386 if (*end)
387 need_argument(def);
388 *((tw_stime*)def->value) = v;
389 break;
390 }
391
392 case TWOPTTYPE_CHAR:
393 {
394 if (!value)
395 need_argument(def);
396
397 // *((char **)def->value) = tw_calloc(TW_LOC, "string arg", strlen(value) + 1, 1);
398 strcpy((char *) def->value, value);
399 break;
400 }
401
402 case TWOPTTYPE_FLAG:
403 *((unsigned int*)def->value) = 1;
404 break;
405
407 if (tw_ismaster())
408 show_help();
409 tw_net_stop();
410 exit(0);
411 break;
412
414 {
415 if (args_file_depth) {
416 tw_error(TW_LOC, "--args-file cannot be invoked inside an args-file.");
417 }
419
420 int argc_parsed = 1;
421 char** argv_parsed = (char**)malloc(sizeof(char*));
422
423 // Copying program name into first slot of argv
424 size_t prog_name_len = strlen(program);
425 argv_parsed[0] = malloc(prog_name_len + 3); // 1 for `\0`, and 2 for "./"
426 strcpy(argv_parsed[0], "./");
427 strcat(argv_parsed[0], program);
428 argv_parsed[0][prog_name_len+2] = '\0';
429
430 parse_args_file(value, &argc_parsed, &argv_parsed);
431
432 // Print out the arguments passed through the args-file
433 if (tw_ismaster()) {
434 printf("Arguments passed through --args-file:\n");
435 for (int i = 1; i < argc_parsed; i++) {
436 printf("%s\n", argv_parsed[i]);
437 }
438 printf("\n");
439 }
440
441 // Recursive call of args-file (it is not allowed to go recursively more than once, thanks to `args_file_depth`)
442 tw_opt_parse(&argc_parsed, &argv_parsed);
443 for (size_t i = 0; i < argc_parsed; i++) {
444 free(argv_parsed[0]);
445 }
446 free(argv_parsed);
447
449 break;
450 }
451
452 default:
453 tw_error(TW_LOC, "Option type not supported here.");
454 }
455}
456
457static void
458match_opt(const char *arg)
459{
460 const char *eq = strchr(arg + 2, '=');
461 const tw_optdef **group = all_groups;
462
463 for (; *group; group++)
464 {
465 const tw_optdef *def = *group;
466 for (; def->type; def++)
467 {
468 if (!def->name || def->type == TWOPTTYPE_GROUP)
469 continue;
470 if (!eq && !strcmp(def->name, arg + 2))
471 {
472 apply_opt(def, NULL);
473 return;
474 }
475 else if (eq && !strncmp(def->name, arg + 2, eq - arg - 2))
476 {
477 apply_opt(def, eq + 1);
478 return;
479 }
480 }
481 }
482
483 if (tw_ismaster())
484 fprintf(stderr,
485 "%s: option '%s' not recognized; see --help for details\n",
486 program, arg);
487 tw_net_stop();
488 exit(1);
489}
490
491static const tw_optdef basic[] = {
492 { TWOPTTYPE_SHOWHELP, "help", "show this message", NULL },
493 TWOPT_END()
494};
495
496static int is_empty(const tw_optdef *def)
497{
498 for (; def->type; def++) {
499 if (def->type == TWOPTTYPE_GROUP)
500 continue;
501 return 0;
502 }
503 return 1;
504}
505
506static void
507parse_args_file(const char* file_name, int* argc_p, char ***argv_p)
508{
509 FILE* file;
510 char* line = NULL;
511 char* argument = NULL;
512 size_t len = 0;
513 ssize_t read;
514 int argc = *argc_p;
515 char** argv = *argv_p;
516
517 file = fopen(file_name, "r");
518
519 if (file == NULL) {
520 tw_error(TW_LOC, "Invalid file path!");
521 }
522
523 while ((read = getline(&line, &len, file)) != -1) {
524 char * start_line = line;
525 line = ltrim(line);
526 // Retrieve all arguments from the line
527 while (line && (argument = next_argument(&line))) {
528 argc++;
529 argv = (char**)realloc(argv, sizeof(char*)*argc);
530
531 // Saving argument in memory
532 size_t argument_len = strlen(argument);
533 argv[argc-1] = (char*)malloc(sizeof(char)*(argument_len+1));
534 strcpy(argv[argc-1], argument);
535
536 line = ltrim(line);
537
538 // checking for disallowed `--` argument
539 if(strcmp(argument, "--")==0) {
540 tw_error(TW_LOC, "Argument `--' is invalid inside of args-file.");
541 }
542 }
543 free(start_line);
544 }
545 if (line) { free(line); }
546
547 *argc_p = argc;
548 *argv_p = argv;
549}
550
551void
552tw_opt_parse(int *argc_p, char ***argv_p)
553{
554 int argc = *argc_p;
555 char **argv = *argv_p;
556 unsigned i;
557
558 program = strrchr(argv[0], '/');
559 if (program)
560 program++;
561 else
562 program = argv[0];
563
564 for (i = 0; opt_groups[i]; i++)
565 {
566 if (!(opt_groups[i])->type || is_empty(opt_groups[i]))
567 continue;
568 if (i >= ARRAY_SIZE(all_groups))
569 {
570 tw_error(TW_LOC, "Too many tw_optdef arrays.");
571 }
572 all_groups[i] = opt_groups[i];
573 }
574 all_groups[i++] = basic;
575 all_groups[i] = NULL;
576
577 while (argc > 1)
578 {
579 const char *s = argv[1];
580 if (strncmp(s, "--", 2))
581 {
582 printf("Warning: found ill-formated argument: %s, stopping arg parsing here!! \n", s );
583 break;
584 }
585 if (strcmp(s, "--"))
586 match_opt(s);
587
588 argc--;
589 memmove(argv + 1, argv + 2, (argc - 1) * sizeof(*argv));
590
591 if (!strcmp(s, "--"))
592 break;
593 }
594
595 *argc_p = argc;
596 *argv_p = argv;
597}
void tw_net_stop(void)
Stops the network library after simulation end.
double tw_stime
Definition ross-base.h:39
#define NORETURN
Definition ross-base.h:15
void tw_error(const char *file, int line, const char *fmt,...)
Definition tw-util.c:77
FILE * g_tw_csv
Definition ross-global.c:95
void tw_warning(const char *file, int line, const char *fmt,...)
Definition tw-util.c:93
#define TW_LOC
static int tw_ismaster(void)
#define TWOPT_END()
Definition tw-opts.h:39
@ TWOPTTYPE_CHAR
Definition tw-opts.h:14
@ TWOPTTYPE_SHOWHELP
Definition tw-opts.h:17
@ TWOPTTYPE_ARGSFILE
Definition tw-opts.h:16
@ TWOPTTYPE_DOUBLE
Definition tw-opts.h:13
@ TWOPTTYPE_ULONGLONG
Definition tw-opts.h:10
@ TWOPTTYPE_FLAG
Definition tw-opts.h:15
@ TWOPTTYPE_STIME
Definition tw-opts.h:12
@ TWOPTTYPE_UINT
Definition tw-opts.h:11
@ TWOPTTYPE_GROUP
Definition tw-opts.h:8
@ TWOPTTYPE_ULONG
Definition tw-opts.h:9
const char * name
Definition tw-opts.h:25
const char * help
Definition tw-opts.h:26
tw_opttype type
Definition tw-opts.h:24
void * value
Definition tw-opts.h:27
char * next_argument(char **line)
Definition tw-opts.c:304
void tw_opt_parse(int *argc_p, char ***argv_p)
Definition tw-opts.c:552
static void need_argument(const tw_optdef *def)
Definition tw-opts.c:285
static void apply_opt(const tw_optdef *def, const char *value)
Definition tw-opts.c:327
#define ARRAY_SIZE(a)
Definition tw-opts.c:6
static void match_opt(const char *arg)
Definition tw-opts.c:458
void tw_opt_settings(FILE *outfile)
Definition tw-opts.c:147
static int is_empty(const tw_optdef *def)
Definition tw-opts.c:496
void tw_opt_print(void)
Definition tw-opts.c:224
static const tw_optdef * opt_groups[10]
Definition tw-opts.c:16
static const tw_optdef * all_groups[10]
Definition tw-opts.c:10
static const tw_optdef basic[]
Definition tw-opts.c:491
char * ltrim(char *s)
Definition tw-opts.c:296
static void parse_args_file(const char *file_name, int *argc_p, char ***argv_p)
Definition tw-opts.c:507
static unsigned int opt_index
Definition tw-opts.c:17
static uint args_file_depth
Definition tw-opts.c:20
void tw_opt_add(const tw_optdef *options)
Definition tw-opts.c:23
static const char * program
Definition tw-opts.c:9
static void show_help(void)
Definition tw-opts.c:33