Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various updates of the modular argument handling #10

Open
wants to merge 10 commits into
base: modular-arg-handling
Choose a base branch
from
11 changes: 0 additions & 11 deletions arch/platform/native/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,17 +230,6 @@ set_global_address(void)
}
#endif
/*---------------------------------------------------------------------------*/
int contiki_argc = 0;
char **contiki_argv;
/*---------------------------------------------------------------------------*/
void
platform_process_args(int argc, char **argv)
{
/* crappy way of remembering and accessing argc/v */
contiki_argc = argc;
contiki_argv = argv;
}
/*---------------------------------------------------------------------------*/
void
platform_init_stage_one()
{
Expand Down
167 changes: 164 additions & 3 deletions os/contiki-main.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,177 @@
#include "sys/log.h"
#define LOG_MODULE "Main"
#define LOG_LEVEL LOG_LEVEL_MAIN

#if PLATFORM_MAIN_ACCEPTS_ARGS
/*---------------------------------------------------------------------------*/
int contiki_argc;
char **contiki_argv;
/*---------------------------------------------------------------------------*/
#include "lib/list.h"

LIST(contiki_options);
int flag_verbose;
static const char *prog;
static const char *help_usage;
static const char *help_suffix;
/*---------------------------------------------------------------------------*/
void
contiki_set_usage(const char *msg)
{
help_usage = msg;
}
/*---------------------------------------------------------------------------*/
void
contiki_set_extra_help(const char *msg)
{
help_suffix = msg;
}
/*---------------------------------------------------------------------------*/
void
contiki_add_option(struct contiki_option *option)
{
static bool initialized = false;
if(!initialized) {
list_init(contiki_options);
initialized = true;
}
list_add(contiki_options, option);
}
/*---------------------------------------------------------------------------*/
static void
print_help(void)
{
printf("usage: %s [options]", prog);
if(help_usage) {
printf(" %s", help_usage);
}
printf("\n\nOptions are:\n");
for(struct contiki_option *r = list_head(contiki_options);
r != NULL; r = r->next) {
if(!r->help) {
continue;
}
printf(" ");
if(r->opt_struct.flag == NULL && r->opt_struct.val) {
printf("-%c, ", (char)r->opt_struct.val);
}
const char *short_or_long = strlen(r->opt_struct.name) == 1 ? "" : "-";
printf("-%s%s", short_or_long, r->opt_struct.name);

int has_arg = r->opt_struct.has_arg;
if(has_arg != no_argument) {
printf(has_arg == optional_argument ? " [%s]" : " <%s>",
r->arg_name ? r->arg_name : "value");
}
printf("\n" CONTIKI_HELP_PREFIX "%s\n", r->help);
}
if(help_suffix) {
printf("%s\n", help_suffix);
}
}
/*---------------------------------------------------------------------------*/
static int
verbose_callback(const char *optarg)
{
flag_verbose = optarg ? atoi(optarg) : 3;
if(flag_verbose < 0 || flag_verbose > 5 ||
(flag_verbose == 0 && optarg && optarg[0] != '0')) {
fprintf(stderr, "Verbose level '%s' not between 0 and 5\n", optarg);
return 1;
}
return 0;
}
CONTIKI_OPTION(CONTIKI_VERBOSE_PRIO, {"v", optional_argument, NULL, 0},
verbose_callback, "verbosity level (0-5)", "verbosity");
/*---------------------------------------------------------------------------*/
CC_NORETURN static int
help_callback(const char *optarg)
{
print_help();
exit(0);
}
CONTIKI_OPTION(CONTIKI_MAX_INIT_PRIO + 1, {"help", no_argument, NULL, 'h'},
help_callback, "display this help and exit");
/*---------------------------------------------------------------------------*/
static int
parse_argv(int *argc, char ***argv)
{
prog = *argv[0];
const int num_options = list_length(contiki_options);
struct contiki_option options[num_options];
struct option long_options[num_options + 1];
char opt_string[num_options * 2 + 1];

int opt_i = 0;
int i = 0;
for(struct contiki_option *r = list_head(contiki_options);
r != NULL; ++i, r = r->next) {
memcpy(&long_options[i], &r->opt_struct, sizeof(struct option));
memcpy(&options[i], r, sizeof(struct contiki_option));
if(r->opt_struct.flag == NULL && r->opt_struct.val != 0) {
opt_string[opt_i++] = r->opt_struct.val;
if(r->opt_struct.has_arg == required_argument) {
opt_string[opt_i++] = ':';
}
}
}

/* Null terminate options. */
memset(&long_options[i], 0, sizeof(struct option));
opt_string[opt_i] = '\0';

while(1) {
int ix = 0;
int c = getopt_long_only(*argc, *argv, opt_string, long_options, &ix);
if(c == -1) { /* Processed all options. */
break;
}
if(c == '?') { /* Unknown option, print help and return error. */
print_help();
return 1;
}
if(c != 0) {
bool found = false;
for(i = 0; i < num_options; i++) {
if(long_options[i].flag == NULL && long_options[i].val == c) {
ix = i;
found = true;
break;
}
}
if(!found) {
printf("Unknown option: -%c\n", c);
print_help();
return 1;
}
}
if(options[ix].callback) { /* Option has a callback, call with optarg. */
int rv;
if((rv = options[ix].callback(optarg)) != 0) {
return rv;
}
}
}
*argc -= optind - 1;
*argv += optind - 1;
return 0;
}
/*---------------------------------------------------------------------------*/
int
#if PLATFORM_MAIN_ACCEPTS_ARGS
main(int argc, char **argv)
{
platform_process_args(argc, argv);
int rv;
if((rv = parse_argv(&argc, &argv)) != 0) {
return rv;
}
/* Remember argc/argv after command line options. */
contiki_argc = argc;
contiki_argv = argv;
#else
int
main(void)
{
#endif
#endif /* PLATFORM_MAIN_ACCEPTS_ARGS */
platform_init_stage_one();

clock_init();
Expand Down
Loading