271 lines
7.2 KiB
C
271 lines
7.2 KiB
C
/*
|
|
Argument parser 0.3.2 (Sen)
|
|
#define ARGPARSE_DE -> Deutsche Ausgabe
|
|
#define ARGPARSE_OUT -> Ausgabe-Funktion
|
|
*/
|
|
|
|
#ifndef ARGPARSE_H
|
|
#define ARGPARSE_H
|
|
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#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 <stdio.h>
|
|
#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
|