Mercurial > hg > nnchat
view th_args.c @ 264:4c1c18a388d9
Add configuration setting and functionality for random "keepalive" messages to avoid idle timeout kicks from chat.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 03 Jun 2011 11:18:19 +0300 |
parents | 69aed051f84d |
children | 9ad157feb99a |
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)); */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "th_util.h" #include "th_args.h" #include "th_string.h" /* Check if option requires an argument */ static BOOL th_args_check_arg(optarg_t *o, char *optArg) { if ((o->optFlags & 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].optFlags & 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].optID, 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].optFlags & 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].optID, 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].optFlags & 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, char * progName, char * progUsage) { int i, nrequired; fprintf(outFile, "\n%s v%s (%s)\n" "%s\n" "%s\n" "Usage: %s %s\n", th_prog_name, th_prog_version, th_prog_fullname, th_prog_author, th_prog_license, progName, progUsage); 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->optFlags & OPT_ARGMASK) == OPT_ARGOPT) { snprintf(tmpStr, sizeof(tmpStr), "%s[=ARG]", optList[i].optLong); p = tmpStr; } else if ((o->optFlags & 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].optDesc); if (o->optFlags & OPT_REQUIRED) { fprintf(outFile, " [*]\n"); nrequired++; } else fprintf(outFile, "\n"); } if (nrequired > 0) fprintf(outFile, "(Options marked with [*] are required)\n"); }