#include #include #include #include #include #include #include "options.h" typedef enum opt_type { OT_INVALID = 0, OT_NOARG, OT_L, OT_LL, OT_STR } opt_type; typedef union opt_ptr { long int l; long long int ll; const char *str; char *str_dup; } opt_ptr; 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, is_list, arg, short_help, help) \ { type, {0}, {def_value}, 0, is_list, arg, short_help, help } #define OPT_STR(def_value, is_list, arg, short_help, help) \ OPT(OT_STR, .str = def_value, is_list, arg, short_help, help) #define OPT_NOARG(arg, short_help, help) \ OPT(OT_NOARG, .ll = 0, 0, arg, short_help, help) static struct opt options[OPT_MAX+1] = { OPT_STR("./potd.log", 0, "log", "short help", "help"), OPT_STR(NULL, 0, "log-level", "short help", "help"), OPT_NOARG("daemon", "short help", "help"), OPT(OT_INVALID, .ll = 0, 0, NULL, NULL, NULL) }; static int setopt(struct opt *o, const char *optarg); static int setopt(struct opt *o, const char *optarg) { char *endptr = NULL; assert(o && o->type != OT_INVALID); if (o->used && !o->is_list) return 1; if (!optarg || o->type == OT_NOARG) goto noarg; switch (o->type) { case OT_L: o->value.l = strtol(optarg, &endptr, 10); break; case OT_LL: o->value.ll = strtoll(optarg, &endptr, 10); break; case OT_STR: o->value.str_dup = strdup(optarg); break; case OT_NOARG: case OT_INVALID: return 1; } if (endptr && *endptr != 0) 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 = optional_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(&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); 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; }