# HG changeset patch # User Matti Hamalainen # Date 1578849952 -7200 # Node ID 01c6a526196258ccf290a1b3710a83be1a8b9a72 # Parent 5d391c31ebc9026e1195279c92870fa9eef5ff9c Sync commandline argument help printing/handling changes from th-libs. diff -r 5d391c31ebc9 -r 01c6a5261962 src/dmargs.c --- a/src/dmargs.c Sun Jan 12 03:41:02 2020 +0200 +++ b/src/dmargs.c Sun Jan 12 19:25:52 2020 +0200 @@ -175,14 +175,24 @@ } -static void dmPad(FILE *outFile, int count) +void dmPrintPad(FILE *fh, int count, const char och) { while (count--) - fputc(' ', outFile); + fputc(och, fh); } -static void dmPrintWrap(FILE *fh, const char *str, int spad, int rpad, int width) +/** + * Print given string indented in such a way that it is automatically + * line-wrapped as necessary, taking hard linefeeds into account as well. + * @param fh stdio file handle to output to + * @param str string to output + * @param spad starting pad/indent of the first line + * @param rpad how much to pad the other lines + * @param width total line width to wrap at + */ +void dmPrintWrap(FILE *fh, const char *str, + const int spad, int const rpad, const int width) { size_t pos = 0; BOOL first = TRUE; @@ -191,42 +201,125 @@ { // Pre-pad line int linelen = first ? spad : rpad; - dmPad(fh, first ? 0 : rpad); + dmPrintPad(fh, first ? 0 : rpad, ' '); first = FALSE; // Skip whitespace at line start - while (isspace(str[pos]) || str[pos] == '\n') pos++; + 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); + + // Find word length and next break + for (wlen = 0, next = pos; + str[next] && !isspace(str[next]) && + str[next] != '\n'; + next++, wlen++); - if (str[next] == '\n' || str[next] == 0) - { - fprintf(fh, "\n"); - break; - } - else - { - fputc(str[pos], fh); - pos++; - linelen++; - } - } + // Check if we have too much of text? + if (linelen + wlen >= width) + break; + + // Print what we have + for (;pos < next; pos++, linelen++) + fputc(str[pos], fh); + + // Check if we are at end of input or hard linefeed + if (str[next] == '\n' || str[next] == 0) + break; else { - fprintf(fh, "\n"); - break; + fputc(str[pos], fh); + pos++; + linelen++; } } + fprintf(fh, "\n"); + } +} + + +static inline const char *dmArgsGetOptArg(const DMOptArg *opt) +{ +#ifdef DM_USE_OPT_ARG + return opt->o_arg != NULL ? opt->o_arg : "ARG"; +#else + (void) opt; + return "ARG"; +#endif +} + + +static void dmArgsPrintHelpPrintItem(FILE *fh, const DMOptArg *opt, int *lineWidth, const int maxLineWidth, const BOOL doPrint) +{ + const char *arg = dmArgsGetOptArg(opt); + char fmtBuf[32]; + int padWidth; + BOOL hasLongOpt = opt->o_long != NULL; + + if (opt->o_short != 0) + { + if (!hasLongOpt && (opt->flags & OPT_ARGREQ)) + { + snprintf(fmtBuf, sizeof(fmtBuf), " -%c <%s>", + opt->o_short, arg); + } + else + { + snprintf(fmtBuf, sizeof(fmtBuf), " -%c,", + opt->o_short); + } + + *lineWidth = strlen(fmtBuf); + if (doPrint) + padWidth = hasLongOpt ? 2 : maxLineWidth - *lineWidth; + else + padWidth = 2; + } + else + { + fmtBuf[0] = 0; + *lineWidth = 0; + padWidth = 4 + 2; + } + + if (doPrint) + { + fputs(fmtBuf, fh); + dmPrintPad(fh, padWidth, ' '); + } + *lineWidth += padWidth; + + if (hasLongOpt) + { + if (opt->flags & OPT_ARGREQ) + { + snprintf(fmtBuf, sizeof(fmtBuf), "--%s=<%s>", + opt->o_long, arg); + } + else + { + snprintf(fmtBuf, sizeof(fmtBuf), "--%s", + opt->o_long); + } + + *lineWidth += strlen(fmtBuf); + } + else + fmtBuf[0] = 0; + + if (doPrint) + { + padWidth = hasLongOpt ? maxLineWidth - *lineWidth : 0; + *lineWidth += padWidth; + + fputs(fmtBuf, fh); + dmPrintPad(fh, padWidth, ' '); + dmPrintWrap(fh, opt->desc, *lineWidth, *lineWidth, 79); } } @@ -238,42 +331,29 @@ * @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) +void dmArgsPrintHelp(FILE *fh, const DMOptArg *opts, + const int nopts, const int flags) { - int index; + int index, maxLineWidth; + (void) flags; - // Print out option list + // Determine width of the options and arguments + maxLineWidth = 0; 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); + int lineWidth = 0; + dmArgsPrintHelpPrintItem(NULL, &opts[index], &lineWidth, 0, FALSE); + if (lineWidth > maxLineWidth) + maxLineWidth = lineWidth; + } - // 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; + maxLineWidth += 2; - fprintf(fh, "%-18s", tmpStr); - - dmPrintWrap(fh, opt->desc, 24, 24, 79); + // Print out the formatted option list + for (index = 0; index < nopts; index++) + { + int lineWidth; + dmArgsPrintHelpPrintItem(fh, &opts[index], &lineWidth, maxLineWidth, TRUE); } } diff -r 5d391c31ebc9 -r 01c6a5261962 src/dmargs.h --- a/src/dmargs.h Sun Jan 12 03:41:02 2020 +0200 +++ b/src/dmargs.h Sun Jan 12 19:25:52 2020 +0200 @@ -35,20 +35,26 @@ typedef struct { 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 o_short; ///< Short option name (one character, can be 0 for none) + char *o_long; ///< Long option name (can be NULL for none) +#ifdef DM_USE_OPT_ARG + char *o_arg; ///< Option argument name (can be NULL for none/default) +#endif char *desc; ///< Option description int flags; ///< Flags (see OPT_*) } DMOptArg; -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); +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); -void dmArgsPrintHelp(FILE *, const DMOptArg *opts, - const int nopts, const int flags); +void dmArgsPrintHelp(FILE *fh, const DMOptArg *opts, + const int nopts, const int flags); + +void dmPrintWrap(FILE *fh, const char *str, + const int spad, const int rpad, const int width); #ifdef __cplusplus }