--- popt-1.7/poptconfig.c 2002-08-22 15:17:50.000000000 +0100 +++ popt-1.7.1/poptconfig.c 2004-07-26 17:43:49.000000000 +0100 @@ -50,6 +50,8 @@ item->option.longName = opt + 2; else if (opt[0] == '-' && opt[2] == '\0') item->option.shortName = opt[1]; + else + return ; /* Anonymous items are pretty useless. */ /*@=temptrans@*/ if (poptParseArgvString(line, &item->argc, &item->argv)) return; --- popt-1.7/popthelp.c 2002-09-16 14:16:54.000000000 +0100 +++ popt-1.7.1/popthelp.c 2004-07-26 11:55:41.000000000 +0100 @@ -12,6 +12,28 @@ #include "system.h" #include "poptint.h" +#include + +/** + * Query the width of the output device + * @param fp output file handle + */ +static int QueryOutputWidth ( FILE * fp ) +{ + int fd ; + + fd = fileno(fp) ; + if (0 <= fd && isatty(fd)) { +#if defined(TIOCGWINSZ) + struct winsize ws ; + if (0 <= ioctl(fd, TIOCGWINSZ, &ws)) + return ws.ws_col ; +#endif + } + + return 80 ; +} + /** * Display arguments. * @param con context @@ -191,17 +213,19 @@ * Display help text for an option. * @param fp output file handle * @param maxLeftCol + * @param columns * @param opt option(s) * @param translation_domain translation domain */ static void singleOptionHelp(FILE * fp, int maxLeftCol, + int columns, const struct poptOption * opt, /*@null@*/ const char * translation_domain) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ { int indentLength = maxLeftCol + 5; - int lineLength = 79 - indentLength; + int lineLength = columns - indentLength - 1; const char * help = D_(translation_domain, opt->descrip); const char * argDescrip = getArgDescrip(opt, translation_domain); int helpLength; @@ -286,7 +310,7 @@ default: /*@innerbreak@*/ break; } - *le++ = '='; + *le++ = opt->shortName ? ' ' : '='; if (negate) *le++ = '~'; /*@-formatconst@*/ le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong); @@ -300,14 +324,14 @@ case POPT_ARG_FLOAT: case POPT_ARG_DOUBLE: case POPT_ARG_STRING: - *le++ = '='; + *le++ = opt->shortName ? ' ' : '='; strcpy(le, argDescrip); le += strlen(le); break; default: break; } } else { - *le++ = '='; + *le++ = opt->shortName ? ' ' : '='; strcpy(le, argDescrip); le += strlen(le); } if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) @@ -406,10 +430,12 @@ * @param items alias/exec array * @param nitems no. of alias/exec entries * @param left + * @param columns * @param translation_domain translation domain */ static void itemHelp(FILE * fp, /*@null@*/ poptItem items, int nitems, int left, + int columns, /*@null@*/ const char * translation_domain) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ @@ -423,7 +449,7 @@ opt = &item->option; if ((opt->longName || opt->shortName) && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) - singleOptionHelp(fp, left, opt, translation_domain); + singleOptionHelp(fp, left, columns, opt, translation_domain); } } @@ -433,10 +459,12 @@ * @param fp output file handle * @param table option(s) * @param left + * @param columns * @param translation_domain translation domain */ static void singleTableHelp(poptContext con, FILE * fp, /*@null@*/ const struct poptOption * table, int left, + int columns, /*@null@*/ const char * translation_domain) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ @@ -445,8 +473,8 @@ const char *sub_transdom; if (table == poptAliasOptions) { - itemHelp(fp, con->aliases, con->numAliases, left, NULL); - itemHelp(fp, con->execs, con->numExecs, left, NULL); + itemHelp(fp, con->aliases, con->numAliases, left, columns, NULL); + itemHelp(fp, con->execs, con->numExecs, left, columns, NULL); return; } @@ -454,7 +482,7 @@ for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) { if ((opt->longName || opt->shortName) && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) - singleOptionHelp(fp, left, opt, translation_domain); + singleOptionHelp(fp, left, columns, opt, translation_domain); } if (table != NULL) @@ -468,7 +496,7 @@ if (opt->descrip) fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip)); - singleTableHelp(con, fp, opt->arg, left, sub_transdom); + singleTableHelp(con, fp, opt->arg, left, columns, sub_transdom); } } @@ -480,10 +508,10 @@ /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ { - int len = 6; + int len ; const char * fn; - fprintf(fp, POPT_("Usage:")); + len = fprintf(fp, POPT_("Usage:")); if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) { /*@-boundsread@*/ /*@-nullderef@*/ /* LCL: wazzup? */ @@ -492,8 +520,7 @@ /*@=boundsread@*/ if (fn == NULL) return len; if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1; - fprintf(fp, " %s", fn); - len += strlen(fn) + 1; + len += fprintf(fp, " %s", fn); } return len; @@ -502,6 +529,9 @@ void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ int flags) { int leftColWidth; + int columns ; + + columns = QueryOutputWidth(fp) ; (void) showHelpIntro(con, fp); if (con->otherHelp) @@ -510,16 +540,18 @@ fprintf(fp, " %s\n", POPT_("[OPTION...]")); leftColWidth = maxArgWidth(con->options, NULL); - singleTableHelp(con, fp, con->options, leftColWidth, NULL); + singleTableHelp(con, fp, con->options, leftColWidth, columns, NULL); } /** * @param fp output file handle * @param cursor + * @param columns * @param opt option(s) * @param translation_domain translation domain */ static int singleOptionUsage(FILE * fp, int cursor, + int columns, const struct poptOption * opt, /*@null@*/ const char *translation_domain) /*@globals fileSystem @*/ @@ -549,10 +581,8 @@ if (argDescrip) len += strlen(argDescrip) + 1; - if ((cursor + len) > 79) { - fprintf(fp, "\n "); - cursor = 7; - } + if ((cursor + len) > columns - 1) + cursor = fprintf(fp, "\n ") - 1; if (opt->longName && opt->shortName) { fprintf(fp, " [-%c|-%s%s%s%s]", @@ -575,11 +605,12 @@ * Display popt alias and exec usage. * @param fp output file handle * @param cursor + * @param columns * @param item alias/exec array * @param nitems no. of ara/exec entries * @param translation_domain translation domain */ -static int itemUsage(FILE * fp, int cursor, poptItem item, int nitems, +static int itemUsage(FILE * fp, int cursor, int columns, poptItem item, int nitems, /*@null@*/ const char * translation_domain) /*@globals fileSystem @*/ /*@modifies *fp, fileSystem @*/ @@ -595,7 +626,7 @@ translation_domain = (const char *)opt->arg; } else if ((opt->longName || opt->shortName) && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { - cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + cursor = singleOptionUsage(fp, cursor, columns, opt, translation_domain); } } /*@=branchstate@*/ @@ -617,12 +648,14 @@ * @param con context * @param fp output file handle * @param cursor + * @param columns * @param opt option(s) * @param translation_domain translation domain * @param done tables already processed * @return */ static int singleTableUsage(poptContext con, FILE * fp, int cursor, + int columns, /*@null@*/ const struct poptOption * opt, /*@null@*/ const char * translation_domain, /*@null@*/ poptDone done) @@ -653,11 +686,13 @@ done->opts[done->nopts++] = (const void *) opt->arg; /*@=boundswrite@*/ } - cursor = singleTableUsage(con, fp, cursor, opt->arg, + cursor = singleTableUsage(con, fp, cursor, columns, opt->arg, translation_domain, done); } else if ((opt->longName || opt->shortName) && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) { - cursor = singleOptionUsage(fp, cursor, opt, translation_domain); + /* Don't print combining short options that have no long option. */ + if (opt->longName || (opt->argInfo & POPT_ARG_MASK) != POPT_ARG_NONE) + cursor = singleOptionUsage(fp, cursor, columns, opt, translation_domain); } } /*@=branchstate@*/ @@ -666,50 +701,35 @@ } /** - * Return concatenated short options for display. + * Return concatenated (combining) short options for display. * @todo Sub-tables should be recursed. * @param opt option(s) - * @param fp output file handle * @retval str concatenation of short options - * @return length of display string */ -static int showShortOptions(const struct poptOption * opt, FILE * fp, +static void CollectShortOptions(const struct poptOption * opt, /*@null@*/ char * str) - /*@globals fileSystem @*/ - /*@modifies *str, *fp, fileSystem @*/ + /*@modifies *str @*/ { - char * s = alloca(300); /* larger then the ascii set */ - - s[0] = '\0'; - /*@-branchstate@*/ /* FIX: W2DO? */ - if (str == NULL) { - memset(s, 0, sizeof(s)); - str = s; - } - /*@=branchstate@*/ - /*@-boundswrite@*/ if (opt != NULL) for (; (opt->longName || opt->shortName || opt->arg); opt++) { - if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK)) - str[strlen(str)] = opt->shortName; - else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) - if (opt->arg) /* XXX program error */ - (void) showShortOptions(opt->arg, fp, str); + /* Only collect combining short options that have no long option. */ + if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK)) { + if (!opt->longName && !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) + *str++ = opt->shortName; + } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) { + CollectShortOptions(opt->arg, str); + str = strchr(str, '\0') ; + } } /*@=boundswrite@*/ - - if (s != str || *s != '\0') - return 0; - - fprintf(fp, " [-%s]", s); - return strlen(s) + 4; } void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ int flags) { poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done)); - int cursor; + int cursor, columns; + char s[300] ; /* XXX Should be long enough for all reasonable possibilities. */ done->nopts = 0; done->maxopts = 64; @@ -719,16 +739,25 @@ done->opts[done->nopts++] = (const void *) con->options; /*@=boundswrite@*/ + columns = QueryOutputWidth(fp) ; + + memset(s, '\0', sizeof(s)); + cursor = showHelpIntro(con, fp); - cursor += showShortOptions(con->options, fp, NULL); - cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done); - cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL); - cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL); + CollectShortOptions(con->options, s); + if (*s) { + if ((cursor + strlen(s) + 4) > (columns - 1)) + cursor = fprintf(fp, "\n ") - 1; + cursor += fprintf(fp, " [-%s]", s); + } + cursor = singleTableUsage(con, fp, cursor, columns, con->options, NULL, done); + cursor = itemUsage(fp, cursor, columns, con->aliases, con->numAliases, NULL); + cursor = itemUsage(fp, cursor, columns, con->execs, con->numExecs, NULL); if (con->otherHelp) { - cursor += strlen(con->otherHelp) + 1; - if (cursor > 79) fprintf(fp, "\n "); - fprintf(fp, " %s", con->otherHelp); + if ((cursor + strlen(con->otherHelp) + 1) > (columns - 1)) + cursor = fprintf(fp, "\n ") - 1; + cursor += fprintf(fp, " %s", con->otherHelp); } fprintf(fp, "\n"); --- popt-1.7/popt.3 2001-09-15 14:49:37.000000000 +0100 +++ popt-1.7.1/popt.3 2004-07-26 11:40:22.000000000 +0100 @@ -194,10 +194,10 @@ .RB "This macro includes another option table (via " POPT_ARG_INCLUDE_TABLE; see below) in the main one which provides the table entries for these .RB "arguments. When " --usage " or " --help " are passed to programs which -use popt's automatical help, popt displays the appropriate message on -stderr as soon as it finds the option, and exits the program with a +use popt's automatic help, popt displays the appropriate message on +stdout as soon as it finds the option, and exits the program with a return code of 0. If you want to use popt's automatic help generation in -a different way, you need to explicitly add the option entries to your programs +a different way, you need to explicitly add the option entries to your program's .RB "option table instead of using " POPT_AUTOHELP ". .sp If the \fIargInfo\fR value is bitwise or'd with \fBPOPT_ARGFLAG_DOC_HIDDEN\fR, @@ -400,8 +400,8 @@ .SS "5. AUTOMATIC HELP MESSAGES" The \fBpopt\fR library can automatically generate help messages which describe the options a program accepts. There are two types of help -messages which can be generated. Usage messages are a short messages -which lists valid options, but does not describe them. Help messages +messages which can be generated. Usage messages are short messages +which list valid options, but do not describe them. Help messages describe each option on one (or more) lines, resulting in a longer, but more useful, message. Whenever automatic help messages are used, the \fBdescrip\fR and \fBargDescrip\fR fields \fBstruct poptOption\fR members @@ -420,8 +420,15 @@ .sp \fBpoptPrintHelp()\fR displays the standard help message to the stdio file descriptor f, while \fBpoptPrintUsage()\fR displays the shorter usage -message. Both functions currently ignore the \fBflags\fR argument; it is -there to allow future changes. +message. If and only if the file is a terminal device whose number of columns +can be obtained from the kernel, the outputs of both functions will be +word-wrapped to fit in that number of columns. Otherwise the outputs of +both functions will be word-wrapped to fit into 80 columns. +The string passed to \fBpoptSetOtherOptionHelp()\fR will be displayed by +both functions (after the list of options in the case of usage messages). +.sp +Both functions currently ignore the \fBflags\fR argument; it is +there to allow future changes and should be set to zero. .sp .SH "ERROR HANDLING" All of the popt functions that can return errors return integers. --- popt-1.7/Makefile.in 2002-08-31 14:22:18.000000000 +0100 +++ popt-1.7.1/Makefile.in 2004-07-26 11:37:20.000000000 +0100 @@ -292,7 +292,7 @@ rm -f "$${dir}/so_locations"; \ done libpopt.la: $(libpopt_la_OBJECTS) $(libpopt_la_DEPENDENCIES) - $(LINK) -rpath $(libdir) $(libpopt_la_LDFLAGS) $(libpopt_la_OBJECTS) $(libpopt_la_LIBADD) $(LIBS) + $(LINK) -version-info 0:1 -rpath $(libdir) $(libpopt_la_LDFLAGS) $(libpopt_la_OBJECTS) $(libpopt_la_LIBADD) $(LIBS) clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; for p in $$list; do \