#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include "options.h" typedef enum opt_type { OT_INVALID = 0, OT_NOARG, OT_L, OT_LL, OT_STR, OT_PATH } opt_type; struct opt_list; typedef union opt_ptr { long int l; long long int ll; const char *str; char *str_dup; struct opt_list *list; } opt_ptr; typedef struct opt_list { opt_ptr value; struct opt_list *next; } opt_list; struct opt { opt_type type; opt_ptr value; opt_ptr def_value; int used; int is_list; const char *arg_name; const char *short_help; const char *help; }; #define OPT(type, def_value, arg, short_help, help) \ { type, {0}, {def_value}, 0, 0, arg, short_help, help } #define OPT_LIST(type, def_values, arg, short_help, help) \ { type, {0}, {def_values}, 0, 1, arg, short_help, help } #define OPT_NOARG(arg, short_help, help) \ OPT(OT_NOARG, .ll = 0, arg, short_help, help) static struct opt options[OPT_MAX+1] = { OPT_NOARG("log-to-file", "short_help", "help"), OPT(OT_PATH, .str = POTD_LOGFILE, "log-file", "short help", "help"), OPT(OT_STR, .ll = 0, "log-level", "short help", "help"), OPT_NOARG("daemon", "short help", "help"), OPT_LIST(OT_STR, .ll = 0, "test", "short_help", "help"), OPT(OT_INVALID, .ll = 0, NULL, NULL, NULL) }; static int opt_convert(opt_type t, opt_ptr *d); static int setopt_list(struct opt *o, const char *optarg); static int setopt(struct opt *o, const char *optarg); static int opt_convert(opt_type t, opt_ptr *d) { char *endptr = NULL; switch (t) { case OT_L: d->l = strtol(optarg, &endptr, 10); break; case OT_LL: d->ll = strtoll(optarg, &endptr, 10); break; case OT_STR: d->str_dup = strdup(optarg); break; case OT_PATH: d->str_dup = realpath(optarg, NULL); break; case OT_NOARG: case OT_INVALID: return 1; } if (endptr && *endptr != 0) return 1; return 0; } static int setopt_list(struct opt *o, const char *optarg) { opt_list **l; assert(o && o->type != OT_INVALID); if (o->type == OT_NOARG || !o->is_list) return 1; l = &o->value.list; while (*l) l = &(*l)->next; o->used = 1; return 0; } static int setopt(struct opt *o, const char *optarg) { assert(o && o->type != OT_INVALID); if (o->used && !o->is_list) return 1; if (!optarg || o->type == OT_NOARG) goto noarg; if (opt_convert(o->type, &o->value)) return 1; noarg: o->used = 1; return 0; } int options_cmdline(int argc, char **argv) { int rc, i, option, option_index; struct option *o = (struct option *) calloc(OPT_MAX+1, sizeof *o); assert(o); for (i = 0; i < OPT_MAX; ++i) { o[i].name = options[i].arg_name; if (options[i].def_value.ll) o[i].has_arg = required_argument; else o[i].has_arg = (options[i].type == OT_NOARG ? no_argument : required_argument); } rc = 0; while (1) { option_index = -1; option = getopt_long_only(argc, argv, "", o, &option_index); if (option_index == -1 && option != -1) { rc = 1; continue; } if (option == -1) break; if (!option) { if (!setopt_list(&options[option_index], optarg)) { } else if (setopt(&options[option_index], optarg)) { rc = 1; goto error; } } else { fprintf(stderr, "%s: unknown option '%c' [0x%X]\n", argv[0], option, option); } } error: free(o); return rc; } int getopt_used(opt_name on) { return options[on].used; } char * getopt_str(opt_name on) { char *str; assert(options[on].type == OT_STR || options[on].type == OT_PATH); assert(getopt_used(on) || options[on].def_value.str); str = options[on].value.str_dup; if (!str) str = options[on].def_value.str_dup; assert(str); return str; }