/* See LICENSE file for copyright and license details. */ #ifndef LIBSIMPLE_ARG_H #define LIBSIMPLE_ARG_H #include #include #include extern char *argv0; struct longopt { const char *long_flag; char short_flag; int with_arg; }; #define ARGBEGIN ARGBEGIN3(1, argc, argv) #define SUBARGBEGIN ARGBEGIN3(0, argc, argv) #define ARGBEGIN3(WITH_ARGV0, argc, argv)\ do {\ char flag_, *lflag_, *arg_;\ int brk_ = 0, again_;\ size_t i_, n_;\ if (WITH_ARGV0) {\ argv0 = *argv;\ argv += !!argv0;\ argc -= !!argv0;\ }\ for (; argv[0] && argv[0][0] && argv[0][1]; argc--, argv++) {\ lflag_ = argv[0];\ if (argv[0][0] == '-') {\ if (argv[0][1] == '-' && !argv[0][2]) {\ argv++, argc--;\ break;\ }\ for (argv[0]++; argv[0][0]; argv[0]++) {\ flag_ = argv[0][0];\ if (flag_ == '-' && &argv[0][-1] != lflag_)\ usage();\ arg_ = argv[0][1] ? &argv[0][1] : argv[1];\ do {\ again_ = 0;\ switch (flag_) { #define ARGMAPLONG(LONGOPTS)\ for (i_ = 0; (LONGOPTS)[i_].long_flag; i_++) {\ if (TESTLONG((LONGOPTS)[i_].long_flag, (LONGOPTS)[i_].with_arg)) {\ flag_ = (LONGOPTS)[i_].short_flag;\ again_ = 1;\ break;\ }\ }\ if (again_)\ break #define ARGALT(SYMBOL)\ }\ } while (again_);\ if (brk_) {\ argc -= arg_ == argv[1];\ argv += arg_ == argv[1];\ brk_ = 0;\ break;\ }\ }\ } else if (argv[0][0] == SYMBOL) {\ if (argv[0][1] == SYMBOL && !argv[0][2])\ break;\ for (argv[0]++; argv[0][0]; argv[0]++) {\ flag_ = argv[0][0];\ if (flag_ == SYMBOL && &argv[0][-1] != lflag_)\ usage();\ arg_ = argv[0][1] ? &argv[0][1] : argv[1];\ do {\ again_ = 0;\ switch (flag_) { #define ARGEND\ }\ } while (again_);\ if (brk_) {\ argc -= arg_ == argv[1];\ argv += arg_ == argv[1];\ brk_ = 0;\ break;\ }\ }\ } else {\ break;\ }\ }\ } while (0) #define ARGNUM '0': case '1': case '2': case '3': case '4':\ case '5': case '6': case '7': case '8': case '9' #define FLAG() (flag_) #define LFLAG() (lflag_) #define ARG() (arg_ ? (brk_ = 1, arg_) : (usage(), (char *)0)) #define ARGHERE() (brk_ = 1, argv[0]) #define NOFLAGS(...)\ do {\ if (*argv)\ argv0 = *argv++, argc--;\ if (argv[0] && argv[0][0] == '-' && argv[0][1] == '-' && !argv[0][2])\ argv++, argc--;\ else if (argv[0] && argv[0][0] == '-')\ usage();\ if (__VA_ARGS__)\ usage();\ } while (0) #define TESTLONG(FLG, WARG)\ ((WARG)\ ? ((!strncmp(lflag_, (FLG), n_ = strlen(FLG)) && lflag_[n_] == '=')\ ? (lflag_[n_] = '\0',\ (arg_ = &lflag_[n_ + 1]),\ (brk_ = 1))\ : (!strcmp(lflag_, (FLG))\ ? (argv[1]\ ? ((arg_ = argv[1]),\ (brk_ = 1))\ : (usage(), 0))\ : 0))\ : (!strcmp(lflag_, (FLG))\ ? (brk_ = 1)\ : 0)) #define USAGE(SYNOPSIS)\ NUSAGE(1, SYNOPSIS) #if defined(__GNUC__) || defined(__clang__) # define NUSAGE(STATUS, SYNOPSIS)\ __attribute__((noreturn))\ static void usage(void)\ {\ const char *syn = SYNOPSIS ? SYNOPSIS : "";\ fprintf(stderr, "usage: %s%s%s\n", argv0, *syn ? " " : "", syn);\ exit(STATUS);\ }\ char *argv0 #else # define NUSAGE(STATUS, SYNOPSIS)\ static void usage(void)\ {\ const char *syn = SYNOPSIS ? SYNOPSIS : "";\ fprintf(stderr, "usage: %s%s%s\n", argv0, *syn ? " " : "", syn);\ exit(STATUS);\ }\ char *argv0 #endif #endif