#pragma once #include enum option_spec_kind { OPTSPECKIND_SETBOOL, OPTSPECKIND_CALL, OPTSPECKIND_CALLP, OPTSPECKIND_HELPUSAGE, OPTSPECKIND_VERSION, OPTSPECKIND_END, // end of spec list (rest of spec entry ignored) }; // For usage info, see option_parse() below. struct option_spec { char optc; // short option character // TODO: long options? // From here, the fields should be filled in using the OPTION_* macros. enum option_spec_kind kind; union { struct { bool *ptr; } setbool; struct { void (*fun)(void); } call; struct { void (*fun)(void*); void *data; } callp; struct { const char *usagestr; } helpusage; struct {} version; } spec_sub; }; // Takes a bool* and stores 'true' there if the flag is found. #define OPTION_SETBOOL(boolptr) \ OPTSPECKIND_SETBOOL, {.setbool={.ptr=(boolptr)}} // Takes a void(*)(void) and calls it every time the flag is found. #define OPTION_CALL(funptr) \ OPTSPECKIND_CALL, {.call={.fun=(funptr)}} // Takes a void(*)(void*) and a 'void *data', and calls the function with 'data' // every time the flag is found. #define OPTION_CALLP(funptr, dataptr) \ OPTSPECKIND_CALLP, {.callp={.fun=(funptr), .data=(dataptr)}} // Takes a printf format string with a single %s, which is substituted (by // printf) for argv[0]. Prints the formatted string and exits with code 0. #define OPTION_HELPUSAGE(usagestring) \ OPTSPECKIND_HELPUSAGE, {.helpusage={.usagestr=(usagestring)}} // Prints version of the tool and exits with code 0. #define OPTION_VERSION() \ OPTSPECKIND_VERSION, {.version={}} // This must be the final entry in the list of option specs; contrary to the // other OPTION_* macros, it is an _entire_ 'struct option_spec'. #define OPTION_SPEC_END {'\0', OPTSPECKIND_END, {}} // The spec must not contain duplicate entries for the same short option // character. // Reshuffles positional arguments to the end of the argument list; returns a // pointer to the first positional argument after reshuffling. // // The specs array is most conveniently declared as a C array: // // const struct option_spec[] = { // {'h', OPTION_HELPUSAGE("Gebruik: %s \n")}, // {'V', OPTION_VERSION()}, // OPTION_SPEC_END // } // // The individual option specs should be initialised with a brace-initialiser // containing the short option character followed by one of the OPTION_* macros, // as shown in the example above. See the comments above the macros for their // meaning. End the list with OPTION_SPEC_END. char** option_parse(int argc, char **argv, const struct option_spec *specs);