#include <stdlib.h>
#include <stdio.h>
#ifndef ARGS_FORMAT_HEADER
#define ARGS_FORMAT_HEADER "Recognized values for <%s>:\n"
#endif
#ifndef ARGS_FORMAT_NAME
#define ARGS_FORMAT_NAME " %s\n"
#endif
#ifndef ARGS_FORMAT_POSITIONAL
#define ARGS_FORMAT_POSITIONAL "No %s specified"
#endif
#ifndef ARGS_FORMAT_COLON
#define ARGS_FORMAT_COLON "Option -%c requires an argument"
#endif
#ifndef ARGS_FORMAT_QUESTIONMARK
#define ARGS_FORMAT_QUESTIONMARK "Unrecognized option: '-%c'"
#endif
#ifndef ARGS_FORMAT_DEFAULT
#define ARGS_FORMAT_DEFAULT "Failed to parse option: '-%c'"
#endif
#ifndef ARGS_FORMAT_FIND
#define ARGS_FORMAT_FIND "Unrecognized %s: '%s'"
#endif
#ifndef ARGS_FORMAT_CATCH
#define ARGS_FORMAT_CATCH "Unrecognized argument: '%s'"
#endif
#define ARGS_PRINT(STREAM, ARG, ARGS) \
fprintf(STREAM, ARGS_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, ARGS_FORMAT_NAME, *(char const **)arg); \
}
#define ARGS_SPECIALS() \
if (argc > 1) { \
if ( \
0 == strcmp(argv[1], "-h") || \
0 == strcmp(argv[1], "--help") \
) { \
help(stdout); \
exit(EXIT_SUCCESS); \
} \
if ( \
0 == strcmp(argv[1], "--version") \
) { \
version(stdout); \
exit(EXIT_SUCCESS); \
} \
}
#define ARGS_DECLARE(ARG, DEFAULT) \
char const * arg_##ARG = DEFAULT;
#define ARGS_POSITIONAL(ARG) \
if (optind >= argc) { \
fprintf(stderr, ARGS_FORMAT_POSITIONAL "\n\n", #ARG); \
usage(stderr); \
exit(EXIT_FAILURE); \
} \
arg_##ARG = argv[optind++];
#define ARGS_OPTIONS_BEGIN(OPTSTRING) \
{ \
int opt; \
int opterr = 0; \
while (-1 != (opt = getopt(argc, argv, ":" OPTSTRING))) { \
switch(opt) {
#define ARGS_OPTION(OPT, ARG) \
case OPT: arg_##ARG = argv[optind]; break;
#define ARGS_OPTION_WITH_ARGUMENT(OPT, ARG) \
case OPT: arg_##ARG = optarg; break;
#define ARGS_OPTIONS_END() \
case ':': \
fprintf(stderr, ARGS_FORMAT_COLON "\n\n", optopt); \
opterr = 1; \
break; \
case '?': \
fprintf(stderr, ARGS_FORMAT_QUESTIONMARK "\n\n", optopt); \
opterr = 1; \
break; \
default: \
fprintf(stderr, ARGS_FORMAT_DEFAULT "\n\n", opt); \
opterr = 1; \
break; \
} \
} \
if (opterr) { \
usage(stderr); \
exit(EXIT_FAILURE); \
} \
}
#define ARGS_CONVERT_BOOL(ARG) \
int ARG = !!arg_##ARG;
#define ARGS_CONVERT_NULL(ARG) \
char const * ARG = *(arg_##ARG) ? (arg_##ARG) : NULL;
#define ARGS_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, ARGS_FORMAT_FIND "\n\n", #ARG, arg_##ARG); \
usage(stderr); \
exit(EXIT_FAILURE); \
} \
#define ARGS_CATCH() \
if (optind < argc) { \
fprintf(stderr, ARGS_FORMAT_CATCH "\n\n", argv[optind]); \
usage(stderr); \
exit(EXIT_FAILURE); \
}