Mercurial > hg > dmlib
changeset 1742:ddec147d1f90
Bring in changes from the th-libs version of commandline argument handling.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 09 Jun 2018 17:56:07 +0300 |
parents | 6f1313c761aa |
children | bcdea45a14cb |
files | Makefile.gen src/dmargs.c src/dmargs.h src/dmargs_int.c tools/packed.c |
diffstat | 5 files changed, 303 insertions(+), 295 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile.gen Sat Jun 09 17:04:33 2018 +0300 +++ b/Makefile.gen Sat Jun 09 17:56:07 2018 +0300 @@ -395,10 +395,6 @@ @echo " CC $+" @$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS) -$(OBJPATH)dmargs.o: $(DMLIBSRC)dmargs.c $(DMLIBSRC)dmargs.h $(DMLIBSRC)dmargs_int.c $(DMLIBSRC)dmlib.h - @echo " CC $+" - @$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS) - $(OBJPATH)libgfx.o: $(DMLIB)tools/libgfx.c $(DMLIB)tools/libgfx.h @echo " CC $+" @$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS) $(LIBPNG_CFLAGS)
--- a/src/dmargs.c Sat Jun 09 17:04:33 2018 +0300 +++ b/src/dmargs.c Sat Jun 09 17:56:07 2018 +0300 @@ -1,12 +1,279 @@ +/* + * Simple commandline argument processing + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2018 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +/// @file +/// @brief Simple commandline argument processing functions #include "dmargs.h" -#define TH_EXTERNAL 1 -#define th_optarg_t DMOptArg -#define th_args_process dmArgsProcess -#define th_args_help dmArgsPrintHelp + + +/** + * Parse and optionally handle the given long or short option argument. + * @param currArg current argument string + * @param argIndex pointer to index of current argument in argv[] + * @param argc number of arguments + * @param argv argument string array + * @param opts options list array + * @param nopts number of elements in options list array + * @param handle_option function pointer to callback that handles option arguments + * @param doProcess if TRUE, actually handle the argument, aka call the handle_option() function. if FALSE, only validity of options are checked. + * @param isLong TRUE if the option is a --long-format one + */ +static BOOL dmArgsProcessOpt( + char *currArg, int *argIndex, + int argc, char *argv[], + const DMOptArg opts[], int nopts, + BOOL (*handle_option)(int id, char *, char *), + BOOL doProcess, BOOL isLong) +{ + const DMOptArg *opt = NULL; + char *optArg = NULL; + int optIndex; + + for (optIndex = 0; optIndex < nopts; optIndex++) + { + const DMOptArg *node = &opts[optIndex]; + if (isLong && node->o_long != NULL) + { + if (strcmp(currArg, node->o_long) == 0) + { + opt = node; + optArg = NULL; + break; + } + + size_t len = strlen(node->o_long); + if (strncmp(currArg, node->o_long, len) == 0 && + currArg[len] == '=') + { + opt = node; + optArg = (&currArg[len+1] != 0) ? &currArg[len+1] : NULL; + break; + } + } + else + if (!isLong && node->o_short != 0) + { + if (*currArg == node->o_short) + { + opt = node; + optArg = (currArg[1] != 0) ? &currArg[1] : NULL; + } + } + } + + if (opt != NULL) + { + // Check for the possible option argument + if ((opt->flags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL) + { + if (*argIndex < argc) + { + (*argIndex)++; + optArg = argv[*argIndex]; + } + + if (optArg == NULL) + { + dmErrorMsg("Option '%s%s' requires an argument.\n", + isLong ? "--" : "-", + currArg); + return FALSE; + } + } + + // Option was given succesfully, try to process it + if (doProcess && !handle_option(opt->id, optArg, currArg)) + return FALSE; + } + else + { + dmErrorMsg("Unknown %s option '%s%s'\n", + isLong ? "long" : "short", + isLong ? "--" : "-", + currArg); + + return FALSE; + } + + return TRUE; +} + + +/** + * Process given array of commandline arguments, handling short + * and long options by calling the respective callback functions. + * + * @param argc number of arguments + * @param argv argument list + * @param opts supported option list array + * @param nopts number of elements in the option list array + * @param handle_option callback function + * @param handle_other callback function + * @param flags processing flags + * @return return TRUE if all is well + */ +BOOL dmArgsProcess(int argc, char *argv[], + const DMOptArg *opts, const int nopts, + BOOL(*handle_option)(int id, char *, char *), + BOOL(*handle_other)(char *), const int flags) +{ + int argIndex, handleFlags = flags & OPTH_ONLY_MASK; + BOOL optionsOK = TRUE, endOfOptions = FALSE; + + for (argIndex = 1; argIndex < argc; argIndex++) + { + char *str = argv[argIndex]; + if (*str == '-' && !endOfOptions) + { + // Should we process options? + BOOL doProcess = (handleFlags & OPTH_ONLY_OPTS) || handleFlags == 0; + BOOL isLong; -#define THERR dmErrorMsg -#define th_calloc dmCalloc -#define th_malloc dmMalloc -#define th_free dmFree + str++; + if (*str == '-') + { + // Check for "--", which ends the options-list + str++; + if (*str == 0) + { + endOfOptions = TRUE; + continue; + } + + // We have a long option + isLong = TRUE; + } + else + isLong = FALSE; + + if (!dmArgsProcessOpt(str, &argIndex, argc, argv, + opts, nopts, handle_option, doProcess, isLong)) + optionsOK = FALSE; + } + else + if (handleFlags == OPTH_ONLY_OTHER || handleFlags == 0) + { + // Was not option argument + if (handle_other == NULL || + (handle_other != NULL && !handle_other(str))) + { + dmErrorMsg("Invalid argument '%s'\n", str); + optionsOK = FALSE; + } + } + + // Check if we bail out on invalid argument + if (!optionsOK && (flags & OPTH_BAILOUT)) + return FALSE; + } + + return optionsOK; +} + + +static void dmPad(FILE *outFile, int count) +{ + while (count--) + fputc(' ', outFile); +} + + +static void dmPrintWrap(FILE *fh, const char *str, int spad, int rpad, int width) +{ + size_t pos = 0; + BOOL first = TRUE; + + while (str[pos]) + { + // Pre-pad line + int linelen = first ? spad : rpad; + dmPad(fh, first ? 0 : rpad); + first = FALSE; + + // Skip whitespace at line start + while (isspace(str[pos]) || str[pos] == '\n') pos++; -#include "dmargs_int.c" + // Handle each word + while (str[pos] && str[pos] != '\n') + { + size_t next; + int wlen; + for (wlen = 0, next = pos; str[next] && !isspace(str[next]) && str[next] != '\n'; next++, wlen++); +// fprintf(stdout, "X '%c', %d .. linelen=%d/%d, wlen=%d\n", str[pos], pos, linelen, width, wlen); + if (linelen + wlen < width) + { + for (;pos < next; pos++, linelen++) + fputc(str[pos], fh); + + if (str[next] == '\n' || str[next] == 0) + { + fprintf(fh, "\n"); + break; + } + else + { + fputc(str[pos], fh); + pos++; + linelen++; + } + } + else + { + fprintf(fh, "\n"); + break; + } + } + } +} + + +/** + * Print help for commandline arguments/options + * @param fh stdio file handle to output to + * @param opts options list array + * @param nopts number of elements in options list array + * @param flags flags (currently unused) + */ +void dmArgsPrintHelp(FILE *fh, + const DMOptArg *opts, const int nopts, + const int flags) +{ + int index; + (void) flags; + + // Print out option list + for (index = 0; index < nopts; index++) + { + const DMOptArg *opt = &opts[index]; + char tmpStr[128]; + + // Print short option + if (opt->o_short != 0) + { + snprintf(tmpStr, sizeof(tmpStr), + "-%c,", opt->o_short); + } + else + tmpStr[0] = 0; + + fprintf(fh, " %-5s", tmpStr); + + // Print long option + if (opt->o_long != NULL) + { + snprintf(tmpStr, sizeof(tmpStr), "--%s%s", + opt->o_long, + (opt->flags & OPT_ARGREQ) ? "=ARG" : ""); + } + else + tmpStr[0] = 0; + + fprintf(fh, "%-20s", tmpStr); + + dmPrintWrap(fh, opt->desc, 26, 26, 79); + } +}
--- a/src/dmargs.h Sat Jun 09 17:04:33 2018 +0300 +++ b/src/dmargs.h Sat Jun 09 17:56:07 2018 +0300 @@ -1,10 +1,12 @@ /* * Simple commandline argument processing functions * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2002-2015 Tecnic Software productions (TNSP) + * (C) Copyright 2002-2018 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ +/// @file +/// @brief Simple commandline argument processing functions #ifndef DMARGS_H #define DMARGS_H @@ -14,40 +16,39 @@ extern "C" { #endif -/* Option flags +/** @def Option argument flags */ -#define OPT_NONE (0) // Simple option with no arguments -#define OPT_ARGREQ (1) // Option requires an argument -#define OPT_ARGMASK (1) // Mask for option argument flags +#define OPT_NONE (0) ///< Simple option with no arguments +#define OPT_ARGREQ (1) ///< Option requires an argument +#define OPT_ARGMASK (1) ///< Mask for option argument flags -#define OPTH_BAILOUT 0x0001 // Bail out on errors -#define OPTH_ONLY_OPTS 0x0010 // Handle only options -#define OPTH_ONLY_OTHER 0x0020 // Handle only "non-options" -#define OPTH_ONLY_MASK 0x00f0 // Mask +/** @def Option processing flags + */ +#define OPTH_BAILOUT 0x0001 ///< Bail out on errors +#define OPTH_ONLY_OPTS 0x0010 ///< Handle only options +#define OPTH_ONLY_OTHER 0x0020 ///< Handle only "non-options" +#define OPTH_ONLY_MASK 0x00f0 ///< Mask -/* Option argument structure +/** Option argument structure */ typedef struct { - int id; - char optShort; - char *optLong; - char *desc; - int flags; + int id; ///< Option ID (should be unique for each option) + char o_short; ///< Short option name (one character) + char *o_long; ///< Long option name + char *desc; ///< Option description + int flags; ///< Flags (see OPT_*) } DMOptArg; BOOL dmArgsProcess(int argc, char *argv[], - const DMOptArg optList[], int noptList, - BOOL (*handleOptionCB)(int, char *, char *), - BOOL (*handleFileCB)(char *), BOOL); + const DMOptArg *opts, const int nopts, + BOOL (*handle_option)(int id, char *, char *), + BOOL (*handle_other)(char *), const int flags); -void dmArgsPrintHelp(FILE *, - const DMOptArg optList[], - const int noptList, - const int flags); - +void dmArgsPrintHelp(FILE *, const DMOptArg *opts, + const int nopts, const int flags); #ifdef __cplusplus }
--- a/src/dmargs_int.c Sat Jun 09 17:04:33 2018 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,256 +0,0 @@ -/* - * Simple commandline argument processing - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2002-2015 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#ifndef TH_EXTERNAL -#include "th_util.h" -#include "th_args.h" -#include "th_string.h" -#endif - - -/* Parse long and short options - */ -static BOOL th_args_process_opt( - char *currArg, int *argIndex, - int argc, char *argv[], - const th_optarg_t opts[], int numOpts, - BOOL (*handleOptionCB)(int, char *, char *), - BOOL doProcess, BOOL isLong) -{ - const th_optarg_t *opt = NULL; - char *optArg = NULL; - int optIndex; - - for (optIndex = 0; optIndex < numOpts; optIndex++) - { - const th_optarg_t *node = &opts[optIndex]; - if (isLong && node->optLong != NULL) - { - if (strcmp(currArg, node->optLong) == 0) - { - opt = node; - optArg = NULL; - break; - } - - size_t len = strlen(node->optLong); - if (strncmp(currArg, node->optLong, len) == 0 && - currArg[len] == '=') - { - opt = node; - optArg = (&currArg[len+1] != 0) ? &currArg[len+1] : NULL; - break; - } - } - else - if (!isLong && node->optShort != 0) - { - if (*currArg == node->optShort) - { - opt = node; - optArg = (currArg[1] != 0) ? &currArg[1] : NULL; - } - } - } - - if (opt != NULL) - { - // Check for the possible option argument - if ((opt->flags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL) - { - if (*argIndex < argc) - { - (*argIndex)++; - optArg = argv[*argIndex]; - } - - if (optArg == NULL) - { - THERR("Option '%s%s' requires an argument.\n", - isLong ? "--" : "-", - currArg); - return FALSE; - } - } - - // Option was given succesfully, try to process it - if (doProcess && !handleOptionCB(opt->id, optArg, currArg)) - return FALSE; - } - else - { - THERR("Unknown %s option '%s%s'\n", - isLong ? "long" : "short", - isLong ? "--" : "-", - 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[], - const th_optarg_t *opts, const int numOpts, - BOOL(*handleOptionCB) (int, char *, char *), - BOOL(*handleOther) (char *), int flags) -{ - int argIndex, handleFlags = flags & OPTH_ONLY_MASK; - BOOL optionsOK = TRUE, endOfOptions = FALSE; - - for (argIndex = 1; argIndex < argc; argIndex++) - { - char *str = argv[argIndex]; - if (*str == '-' && !endOfOptions) - { - // Should we process options? - BOOL doProcess = (handleFlags & OPTH_ONLY_OPTS) || handleFlags == 0; - BOOL isLong; - - str++; - if (*str == '-') - { - // Check for "--", which ends the options-list - str++; - if (*str == 0) - { - endOfOptions = TRUE; - continue; - } - - // We have a long option - isLong = TRUE; - } - else - isLong = FALSE; - - if (!th_args_process_opt(str, &argIndex, argc, argv, - opts, numOpts, handleOptionCB, doProcess, isLong)) - optionsOK = FALSE; - } - else - if (handleFlags == OPTH_ONLY_OTHER || handleFlags == 0) - { - // Was not option argument - if (handleOther == NULL || - (handleOther != NULL && !handleOther(str))) - { - THERR("Invalid argument '%s'\n", str); - optionsOK = FALSE; - } - } - - // Check if we bail out on invalid argument - if (!optionsOK && (flags & OPTH_BAILOUT)) - return FALSE; - } - - return optionsOK; -} - - -/* Print help for commandline arguments/options - */ -static void th_pad(FILE *outFile, int count) -{ - while (count--) - fputc(' ', outFile); -} - - -static void th_print_wrap(FILE *fh, const char *str, int spad, int rpad, int width) -{ - size_t pos = 0; - BOOL first = TRUE; - - while (str[pos]) - { - // Pre-pad line - int linelen = first ? spad : rpad; - th_pad(fh, first ? 0 : rpad); - first = FALSE; - - // Skip whitespace at line start - while (isspace(str[pos]) || str[pos] == '\n') pos++; - - // Handle each word - while (str[pos] && str[pos] != '\n') - { - size_t next; - int wlen; - for (wlen = 0, next = pos; str[next] && !isspace(str[next]) && str[next] != '\n'; next++, wlen++); -// fprintf(stdout, "X '%c', %d .. linelen=%d/%d, wlen=%d\n", str[pos], pos, linelen, width, wlen); - if (linelen + wlen < width) - { - for (;pos < next; pos++, linelen++) - fputc(str[pos], fh); - - if (str[next] == '\n' || str[next] == 0) - { - fprintf(fh, "\n"); - break; - } - else - { - fputc(str[pos], fh); - pos++; - linelen++; - } - } - else - { - fprintf(fh, "\n"); - break; - } - } - } -} - - -void th_args_help(FILE *fh, - const th_optarg_t *opts, const int numOpts, - const int flags) -{ - int index; - (void) flags; - - // Print out option list - for (index = 0; index < numOpts; index++) - { - const th_optarg_t *opt = &opts[index]; - char tmpStr[128]; - - // Print short option - if (opt->optShort != 0) - { - snprintf(tmpStr, sizeof(tmpStr), - "-%c,", opt->optShort); - } - else - tmpStr[0] = 0; - - fprintf(fh, " %-5s", tmpStr); - - // Print long option - if (opt->optLong != NULL) - { - snprintf(tmpStr, sizeof(tmpStr), "--%s%s", - opt->optLong, - (opt->flags & OPT_ARGREQ) ? "=ARG" : ""); - } - else - tmpStr[0] = 0; - - fprintf(fh, "%-20s", tmpStr); - - th_print_wrap(fh, opt->desc, 26, 26, 73); - } -}
--- a/tools/packed.c Sat Jun 09 17:04:33 2018 +0300 +++ b/tools/packed.c Sat Jun 09 17:56:07 2018 +0300 @@ -73,7 +73,7 @@ const DMOptArg *cmd = &cmdList[i]; char tmpStr[128]; snprintf(tmpStr, sizeof(tmpStr), "%c / %s", - cmd->optShort, cmd->optLong); + cmd->o_short, cmd->o_long); fprintf(stdout, " %-15s %s\n", tmpStr, cmd->desc); } @@ -159,8 +159,8 @@ for (int n = 0; n < cmdListN; n++) { const DMOptArg *cmd = &cmdList[n]; - if ((currArg[0] == cmd->optShort && currArg[1] == 0) || - strcmp(currArg, cmd->optLong) == 0) + if ((currArg[0] == cmd->o_short && currArg[1] == 0) || + strcmp(currArg, cmd->o_long) == 0) { optCommand = cmd->id; break;