#include <stdlib.h> #include <stdio.h> struct arg_const { char const * name; int const value; }; #ifndef ARG_HELP #define ARG_HELP help #endif #ifndef ARG_VERSION #define ARG_VERSION version #endif #ifndef ARG_USAGE #define ARG_USAGE usage #endif #ifndef ARG_FORMAT_HEADER #define ARG_FORMAT_HEADER "Recognized values for <%s>:\n" #endif #ifndef ARG_FORMAT_NAME #define ARG_FORMAT_NAME " %s\n" #endif #ifndef ARG_FORMAT_POSITIONAL #define ARG_FORMAT_POSITIONAL "No %s specified" #endif #ifndef ARG_FORMAT_COLON #define ARG_FORMAT_COLON "Option -%c requires an argument" #endif #ifndef ARG_FORMAT_QUESTIONMARK #define ARG_FORMAT_QUESTIONMARK "Unrecognized option: '-%c'" #endif #ifndef ARG_FORMAT_DEFAULT #define ARG_FORMAT_DEFAULT "Failed to parse option: '-%c'" #endif #ifndef ARG_FORMAT_FIND #define ARG_FORMAT_FIND "Unrecognized %s: '%s'" #endif #ifndef ARG_FORMAT_CATCH #define ARG_FORMAT_CATCH "Unrecognized argument: '%s'" #endif #define ARG_PRINT(STREAM, ARG, ARGS) \ fprintf(STREAM, ARG_FORMAT_HEADER, #ARG); \ for (size_t argi = 0; argi < sizeof(ARGS) / sizeof(*ARGS); ++argi) { \ void const * arg = &((char const *)ARGS)[argi * sizeof(*ARGS)]; \ fprintf(STREAM, ARG_FORMAT_NAME, *(char const **)arg); \ } #define ARG_SPECIALS() \ if (argc > 1) { \ if ( \ 0 == strcmp(argv[1], "-h") || \ 0 == strcmp(argv[1], "--help") \ ) { \ ARG_HELP(stdout); \ exit(EXIT_SUCCESS); \ } \ if ( \ 0 == strcmp(argv[1], "--version") \ ) { \ ARG_VERSION(stdout); \ exit(EXIT_SUCCESS); \ } \ } #define ARG_DECLARE(ARG, DEFAULT) \ char const * arg_##ARG = DEFAULT; #define ARG_POSITIONAL(ARG) \ if (optind >= argc) { \ fprintf(stderr, ARG_FORMAT_POSITIONAL "\n\n", #ARG); \ ARG_USAGE(stderr); \ exit(EXIT_FAILURE); \ } \ arg_##ARG = argv[optind++]; #define ARG_GETOPT_BEGIN(OPTSTRING) \ { \ int opt; \ int opterr = 0; \ while (-1 != (opt = getopt(argc, argv, ":" OPTSTRING))) { \ switch(opt) { #define ARG_GETOPT(OPT, ARG) \ case OPT: arg_##ARG = argv[optind]; break; #define ARG_GETOPT_WITH_ARGUMENT(OPT, ARG) \ case OPT: arg_##ARG = optarg; break; #define ARG_GETOPT_END() \ case ':': \ fprintf(stderr, ARG_FORMAT_COLON "\n\n", optopt); \ opterr = 1; \ break; \ case '?': \ fprintf(stderr, ARG_FORMAT_QUESTIONMARK "\n\n", optopt); \ opterr = 1; \ break; \ default: \ fprintf(stderr, ARG_FORMAT_DEFAULT "\n\n", opt); \ opterr = 1; \ break; \ } \ } \ if (opterr) { \ ARG_USAGE(stderr); \ exit(EXIT_FAILURE); \ } \ } #define ARG_CONVERT_BOOL(ARG) \ int ARG = !!arg_##ARG; #define ARG_CONVERT_NULL(ARG) \ char const * ARG = *(arg_##ARG) ? (arg_##ARG) : NULL; #define ARG_CONVERT_FIND(TYPE, ARG, ARGS) \ struct TYPE const * ARG = NULL; \ for (size_t argi = 0; argi < sizeof(ARGS) / sizeof(*ARGS); ++argi) { \ void const * arg = &((char const *)ARGS)[argi * sizeof(*ARGS)]; \ if (0 == strcmp(arg_##ARG, *(char const **)arg)) \ ARG = arg; \ } \ if (!ARG) { \ fprintf(stderr, ARG_FORMAT_FIND "\n\n", #ARG, arg_##ARG); \ ARG_USAGE(stderr); \ exit(EXIT_FAILURE); \ } \ #define ARG_CONVERT_FIND_CONST(ARG, ARGS) \ struct arg_const const * arg_const_##ARG = NULL; \ for (size_t argi = 0; argi < sizeof(ARGS) / sizeof(*ARGS); ++argi) { \ void const * arg = &((char const *)ARGS)[argi * sizeof(*ARGS)]; \ if (0 == strcmp(arg_##ARG, *(char const **)arg)) \ arg_const_##ARG = arg; \ } \ if (!arg_const_##ARG) { \ fprintf(stderr, ARG_FORMAT_FIND "\n\n", #ARG, arg_##ARG); \ ARG_USAGE(stderr); \ exit(EXIT_FAILURE); \ } \ int ARG = arg_const_##ARG->value; \ #define ARG_CATCH() \ if (optind < argc) { \ fprintf(stderr, ARG_FORMAT_CATCH "\n\n", argv[optind]); \ ARG_USAGE(stderr); \ exit(EXIT_FAILURE); \ }