/* Argument parser 0.3.2 (Sen) #define ARGPARSE_DE -> Deutsche Ausgabe #define ARGPARSE_OUT -> Ausgabe-Funktion */ #ifndef ARGPARSE_H #define ARGPARSE_H #include #include #ifndef ARGPARSE_DE #define STR_ARG_USAGE "Usage" #define STR_ARG_HELP "output this help" #define STR_ARG_OPVEC "Option %s (-%c)" #define STR_ARG_OPPOS "Option %s (#%d)" #define STR_ARG_EINT "must be a full number" #define STR_ARG_ERANGE "has to be in range %d .. %d" #define STR_ARG_UNKNOWN "Unknown option -%c" #define STR_ARG_EMORE "Too many arguments, maximum %d" #define STR_ARG_ELESS "Not enough arguments, minimum %d" #define STR_ARG_EREQARG STR_ARG_OPVEC " needs an argument" #else #define STR_ARG_USAGE "Verwendung" #define STR_ARG_HELP "Diese Hilfe anzeigen" #define STR_ARG_OPVEC "Option %s (-%c)" #define STR_ARG_OPPOS "Option %s (#%d)" #define STR_ARG_EINT "muss ein ganzzahliger Wert sein" #define STR_ARG_ERANGE "muss sich im Bereich %d .. %d befinden" #define STR_ARG_UNKNOWN "Unbekannte Option -%c" #define STR_ARG_EMORE "Zu viele Argumente, Maximum %d" #define STR_ARG_ELESS "Nicht genug Argumente, Minimum %d" #define STR_ARG_EREQARG STR_ARG_OPVEC " benoetigt ein Argument" #endif #define STR_ARG_EINT_V STR_ARG_OPVEC " " STR_ARG_EINT #define STR_ARG_EINT_P STR_ARG_OPPOS " " STR_ARG_EINT #define STR_ARG_ERANGE_V STR_ARG_OPVEC " " STR_ARG_ERANGE #define STR_ARG_ERANGE_P STR_ARG_OPPOS " " STR_ARG_ERANGE #ifndef ARGPARSE_OUT #include #define ARGPARSE_OUT(s ...) fprintf(stderr, s) #endif typedef struct { char spec; char arg; int min; int max; int *value; char **str; const char *name; } arg_t; typedef struct { unsigned int arg_min; unsigned int arg_max; unsigned int arg_count; arg_t *arg_vec; } argp_t; void arg_help(argp_t *argspec, char *prog) { arg_t *arg_vec = argspec->arg_vec; ARGPARSE_OUT(STR_ARG_USAGE": %s\n [-h ("STR_ARG_HELP")]\n", prog); for(int h = 0; h < argspec->arg_count; h++) { arg_t *arg = &arg_vec[h]; if(arg->spec) { if(arg->arg) { if((arg->min == 0) && (arg->max == 0)) { ARGPARSE_OUT(" [-%c <%s>]\n", arg->spec, arg->name); } else { ARGPARSE_OUT(" [-%c <%s (%d-%d)>]\n", arg->spec, arg->name, arg->min, arg->max); } } else { ARGPARSE_OUT(" [-%c (%s)]\n", arg->spec, arg->name); } } } for(int h = 0; h < argspec->arg_max; h++) { arg_t *arg = &arg_vec[h]; char nb = (h < argspec->arg_min) ? '<' : '['; char eb = (h < argspec->arg_min) ? '>' : ']'; if((arg->min == 0) && (arg->max == 0)) { ARGPARSE_OUT(" %c%s%s%c\n", nb, arg->name, (arg->value == NULL) ? "" : ", ...", eb); } else { ARGPARSE_OUT(" %c%s (%d-%d)%c\n", nb, arg->name, arg->min, arg->max, eb); } } } char arg_process(arg_t *arg_vec, char *arg, int off) { if((arg_vec[off].min == 0) && (arg_vec[off].max == 0)) { if(arg_vec[off].value != NULL) { arg_vec[off].str[*(arg_vec[off].value)] = arg; *(arg_vec[off].value) += 1; } else { *(arg_vec[off].str) = arg; } } else { errno = 0; char *endptr; *(arg_vec[off].value) = strtol(arg, &endptr, 10); if((errno != 0) || (endptr[0] != 0)) { if(arg_vec[off].spec) { ARGPARSE_OUT(STR_ARG_EINT_V"\n", arg_vec[off].name, arg_vec[off].spec); } else { ARGPARSE_OUT(STR_ARG_EINT_P"\n", arg_vec[off].name, off + 1); } return 0; } if((*(arg_vec[off].value) < arg_vec[off].min) || (*(arg_vec[off].value) > arg_vec[off].max)) { if(arg_vec[off].spec) { ARGPARSE_OUT(STR_ARG_ERANGE_V"\n", arg_vec[off].name, arg_vec[off].spec, arg_vec[off].min, arg_vec[off].max); } else { ARGPARSE_OUT(STR_ARG_ERANGE_P"\n", arg_vec[off].name, off + 1, arg_vec[off].min, arg_vec[off].max); } return 0; } } return 1; } char arg_parse(argp_t *argspec, int argc, char **argv) { unsigned int arg_min = argspec->arg_min; unsigned int arg_max = argspec->arg_max; unsigned int arg_count = argspec->arg_count; arg_t *arg_vec = argspec->arg_vec; unsigned int idx = 0; unsigned int sp = 0; char sa = 0; for(int h = 1; h < argc; h++) { char *arg = argv[h]; if((sa == 0) && (arg[0] == '-') && (arg[1] != 0)) { arg += 1; if(arg[0] == 'h') { arg_help(argspec, argv[0]); free(argspec); return 0; } while((arg[0] != 0) && (sa == 0)) { int f = 0; for(int h = 0; h < arg_count; h++) { if((arg_vec[h].arg ^ 1) && (arg[0] == arg_vec[h].spec)) { *(arg_vec[h].value) = 1; arg += 1; f++; break; } else if(arg[0] == arg_vec[h].spec) { sa = arg[0]; sp = h; arg += 1; f++; break; } } if(f == 0) { ARGPARSE_OUT(STR_ARG_UNKNOWN"\n", arg[0]); free(argspec); return 0; } } if(arg[0] == 0) { continue; } } else if(sa == 0) { if((arg[0] == '\\') && (arg[1] == '-')) { arg += 1; } if((idx < arg_max) || ((arg_max > 0) && (arg_vec[arg_max-1].min == 0) && (arg_vec[arg_max-1].max == 0) && (arg_vec[arg_max-1].value != NULL))) { if(!arg_process(arg_vec, arg, (idx >= arg_max) ? (arg_max-1) : idx)) { free(argspec); return 0; } idx += 1; continue; } else { ARGPARSE_OUT(STR_ARG_EMORE"\n", arg_max); free(argspec); return 0; } } if(!arg_process(arg_vec, arg, sp)) { free(argspec); return 0; } sa = 0; } if(sa != 0) { ARGPARSE_OUT(STR_ARG_EREQARG"\n", arg_vec[sp].name, sa); free(argspec); return 0; } if(idx < arg_min) { ARGPARSE_OUT(STR_ARG_ELESS"\n", arg_min); free(argspec); return 0; } free(argspec); return 1; } void arg_add_gen(argp_t *argspec, char spec, const char *name, int min, int max, char argreq, int *value, char **str) { arg_t *arg = &argspec->arg_vec[(argspec->arg_count)++]; arg->spec = spec; arg->arg = argreq; arg->min = min; arg->max = max; arg->value = value; arg->str = str; arg->name = name; } void arg_add_int(argp_t *argspec, char spec, const char *name, int min, int max, int *value) { arg_add_gen(argspec, spec, name, min, max, 1, value, NULL); } void arg_add_str(argp_t *argspec, char spec, const char *name, char **value) { arg_add_gen(argspec, spec, name, 0, 0, 1, NULL, value); } void arg_add_bool(argp_t *argspec, char spec, const char *name, int *value) { arg_add_gen(argspec, spec, name, 0, 0, 0, value, NULL); } void arg_add_nint(argp_t *argspec, const char *name, char req, int min, int max, int *value) { arg_add_gen(argspec, 0, name, min, max, 0, value, NULL); argspec->arg_max += 1; argspec->arg_min += req ? 1 : 0; } void arg_add_nstr(argp_t *argspec, const char *name, char req, char **value) { arg_add_gen(argspec, 0, name, 0, 0, 0, NULL, value); argspec->arg_max += 1; argspec->arg_min += req ? 1 : 0; } void arg_add_nbool(argp_t *argspec, const char *name, char req, int *value) { arg_add_gen(argspec, 0, name, 0, 1, 0, value, NULL); argspec->arg_max += 1; argspec->arg_min += req ? 1 : 0; } void arg_add_vstr(argp_t *argspec, const char *name, char req, char **svalue, int *ivalue) { arg_add_gen(argspec, 0, name, 0, 0, 0, ivalue, svalue); argspec->arg_max = 1; argspec->arg_min += req ? 1 : 0; } argp_t *arg_alloc(unsigned int count) { char *data = malloc(sizeof(argp_t) + (count * sizeof(arg_t))); argp_t *argspec = (argp_t*)data; data += sizeof(argp_t); argspec->arg_vec = (arg_t*)data; argspec->arg_count = 0; argspec->arg_min = 0; argspec->arg_max = 0; } #endif