Mercurial > hg > dmlib
view dmargs_int.c @ 8:fc097f7717df
Fix JSSMod loading in viewmod and testpl.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 28 Sep 2012 04:47:10 +0300 |
parents | 32250b436bca |
children | 4d6769bd8cfb |
line wrap: on
line source
/* * Simple commandline argument processing * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2002-2008 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ /* Description =========== Structures and functions for simple commandline argument processing, option argument handling (short and long forms supported). Output function for printing out short on-line help for said options and program commandline usage. Format for typical commandline: $ program -a -b -c --long-d -e argument-for-e --long-f="argument for f" where -a, -b and -c are short options without required arguments; --long-d is a long option without argument; -e is short option with argument and finally --long-f is long option with argument. Introduction ============ Handling of commandline options in th_args_process() has various options, which effect how an option is handled. Also the error situations (unknown option/no required argument) can be handled in different ways. Typically th_args_process() is called as follows: BOOL optionHandlerCallback(int optionNumber, char *optionArgument, char *optionName) { if (option is OK) return TRUE; else return FALSE; } BOOL nonoptionHandlerCallback(char *argumentString) { // return value same as in optionHandlerCallback } int main(int argc, char *argv[]) { if (th_args_process(argc, argv, optList, optListN, optionHandlerCallback, nonoptionHandlerCallback)) { ... arguments OK ... } else { ... arguments invalid or required arguments missing ... } } NOTICE! ------- The return value from handler callbacks affects the return value of th_args_process(). Additionally, a failure in callback (returns FALSE) effects the argument processing if bailOut argument of th_args_process() is TRUE! If bailOut is TRUE, any error/failure in argument processing (including callbacks) immediately stops the argument processing and FALSE is returned from th_args_process(). If bailOut is FALSE, most errors are "ignored", but FALSE is still returned if any errors occured. NOTICE #2! ---------- A small temporary buffer of N*sizeof(BOOL) (where N is number of options in optList[]) is allocated for processing required options. If this allocation fails, the program is immediately exited with code 128. Examples ======== Example of different options, in a fictional optionlist struct: optarg_t optList[] = { // Option without arguments { 0, '?', "help", "Show this help", OPT_NONE }, // Option with a required argument { 1, 'o', "output", "Output file name", OPT_ARGREQ }, // Option with optional argument { 2, 'f', "foobar", "Use foobar, with optional string", OPT_ARGOPT }, // This option is required to be given, though without other flags // it may not make much sense. { 4, 'S', "stupid", "You must give this option", OPT_REQUIRED }, // The flags can be combined with OR operator: this option is both // required to be specified, and also requires argument (the filename) { 5, 'i', "input", "Input file name", OPT_REQUIRED | OPT_ARGREQ }, // Option with only long form { 0, 0, "only-long", "Long option", OPT_NONE }, // Option with only short form { 0, 's', NULL, "Short option", OPT_NONE }, }; const int optListN = (sizeof(optList) / sizeof(optarg_t)); */ #ifndef TH_EXTERNAL #include "th_util.h" #include "th_args.h" #include "th_string.h" #endif /* Check if option requires an argument */ static BOOL th_args_check_arg(const optarg_t *o, const char *optArg) { if ((o->flags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL) { if (o->optShort != 0 && o->optLong != NULL) { THERR("Option '-%c ARG' (--%s=ARG) requires an argument!\n", o->optShort, o->optLong); } else if (o->optShort != 0) { THERR("Option '-%c ARG' requires an argument!\n", o->optShort); } else if (o->optLong != NULL) { THERR("Option --%s=ARG requires an argument!\n", o->optLong); } return FALSE; } else return TRUE; } /* Handle short options */ static BOOL th_args_process_short(char *currArg, int *newArgIndex, BOOL *wasGiven, int argc, char *argv[], optarg_t optList[], int optListN, BOOL (*handleOpt)(int, char *, char *)) { char *tmpArg = currArg, *optArg; int optN; BOOL isFound; // Short options can be combined: -a -b -c == -abc while (*tmpArg) { for (optN = 0, isFound = FALSE; (optN < optListN) && !isFound; optN++) if (*tmpArg == optList[optN].optShort) { // Get possible option argument, if needed if ((optList[optN].flags & OPT_ARGMASK) != 0 && (++(*newArgIndex) < argc)) optArg = argv[*newArgIndex]; else optArg = NULL; // Check if option argument is required if (!th_args_check_arg(&optList[optN], optArg)) return FALSE; else { char tmpStr[2] = { 0, 0 }; // Option was given succesfully, try to handle it wasGiven[optN] = TRUE; tmpStr[0] = *tmpArg; if (!handleOpt(optList[optN].id, optArg, tmpStr)) return FALSE; } isFound = TRUE; } if (!isFound) { THERR("Unknown short option '%c' in argument '-%s'\n", *tmpArg, currArg); return FALSE; } tmpArg++; } return TRUE; } /* Handle long options */ static BOOL th_args_process_long(char *currArg, int *newArgIndex, BOOL *wasGiven, int argc, char *argv[], optarg_t optList[], int optListN, BOOL (*handleOpt)(int, char *, char *)) { int optN, optLen, i; char *optArg; (void) argc; (void) argv; (void) newArgIndex; // Long option for (optN = -1, optLen = i = 0; (i < optListN) && (optN < 0); i++) if (optList[i].optLong) { optLen = strlen(optList[i].optLong); if (strncmp(currArg, optList[i].optLong, optLen) == 0) optN = i; } // Get possible option argument, if needed if (optN >= 0) { if ((optList[optN].flags & OPT_ARGMASK) != 0) { if (currArg[optLen] == '=') optArg = &currArg[optLen + 1]; else optArg = NULL; } else optArg = NULL; // Check if option argument is required if (!th_args_check_arg(&optList[optN], optArg)) return FALSE; else { // Option was given succesfully, try to handle it wasGiven[optN] = TRUE; if (!handleOpt(optList[optN].id, optArg, currArg)) return FALSE; } } else { THERR("Unknown long option '--%s'\n", currArg); return FALSE; } return TRUE; } /* Process arguments, handling short and long options by * calling the given callback functions. */ BOOL th_args_process(int argc, char *argv[], optarg_t optList[], int optListN, BOOL(*handleOpt) (int, char *, char *), BOOL(*handleNonOption) (char *), BOOL bailOut) { BOOL endOptions, optionsOK; int argIndex, newArgIndex, i; char *currArg; BOOL *wasGiven; // Allocate wasGiven wasGiven = (BOOL *) th_calloc(optListN, sizeof(BOOL)); if (!wasGiven) { THERR("FATAL ERROR! Could not allocate wasGiven in th_args_process()!\n"); exit(128); } // Parse arguments argIndex = 1; optionsOK = TRUE; endOptions = FALSE; while (argIndex < argc) { currArg = argv[argIndex]; if ((currArg[0] == '-') && !endOptions) { newArgIndex = argIndex; currArg++; if (*currArg == '-') { // Check for "--", which ends the options-list currArg++; if (*currArg == 0) { endOptions = TRUE; continue; } // Long options if (!th_args_process_long(currArg, &newArgIndex, wasGiven, argc, argv, optList, optListN, handleOpt)) optionsOK = FALSE; } else { // Short options if (!th_args_process_short(currArg, &newArgIndex, wasGiven, argc, argv, optList, optListN, handleOpt)) optionsOK = FALSE; } argIndex = newArgIndex; } else { // Was not option argument if (handleNonOption == NULL || (handleNonOption != NULL && !handleNonOption(currArg))) { THERR("Invalid argument '%s'\n", currArg); optionsOK = FALSE; } } // Check if we bail out on invalid argument if (!optionsOK && bailOut) { th_free(wasGiven); return FALSE; } argIndex++; } // Check wasGiven by isRequired for (i = 0; i < optListN; i++) if ((optList[i].flags & OPT_REQUIRED) != 0 && !wasGiven[i]) { THERR("Option -%s (--%s) is required.\n", optList[i].optShort, optList[i].optLong); optionsOK = FALSE; if (bailOut) break; } th_free(wasGiven); return optionsOK; } /* Print help for commandline arguments/options */ void th_args_help(FILE *outFile, optarg_t optList[], int optListN) { int i, nrequired; for (i = nrequired = 0; i < optListN; i++) { optarg_t *o = &optList[i]; // Print short option if (o->optShort != 0) fprintf(outFile, " -%c, ", o->optShort); else fprintf(outFile, " "); // Print long option if (o->optLong) { char tmpStr[64], *p; if ((o->flags & OPT_ARGMASK) == OPT_ARGOPT) { snprintf(tmpStr, sizeof(tmpStr), "%s[=ARG]", optList[i].optLong); p = tmpStr; } else if ((o->flags & OPT_ARGMASK) == OPT_ARGREQ) { snprintf(tmpStr, sizeof(tmpStr), "%s=ARG", optList[i].optLong); p = tmpStr; } else p = o->optLong; fprintf(outFile, "--%-15s", p); } else fprintf(outFile, " "); fprintf(outFile, " %s.", optList[i].desc); if (o->flags & OPT_REQUIRED) { fprintf(outFile, " [*]\n"); nrequired++; } else fprintf(outFile, "\n"); } if (nrequired > 0) fprintf(outFile, "(Options marked with [*] are required)\n"); }