00001
00002
00007
00008
00009
00010
00011 #include "system.h"
00012
00013 #define POPT_WCHAR_HACK
00014 #ifdef POPT_WCHAR_HACK
00015 #include <wchar.h>
00016 #endif
00017 #include "poptint.h"
00018
00019
00020
00029 static void displayArgs(poptContext con,
00030 enum poptCallbackReason foo,
00031 struct poptOption * key,
00032 const char * arg, void * data)
00033
00034
00035 {
00036 if (key->shortName == '?')
00037 poptPrintHelp(con, stdout, 0);
00038 else
00039 poptPrintUsage(con, stdout, 0);
00040 exit(0);
00041 }
00042
00043 #ifdef NOTYET
00044
00045 static int show_option_defaults = 0;
00046 #endif
00047
00051
00052 struct poptOption poptAliasOptions[] = {
00053 POPT_TABLEEND
00054 };
00055
00059
00060
00061 struct poptOption poptHelpOptions[] = {
00062 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
00063 { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
00064 { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
00065 POPT_TABLEEND
00066 } ;
00067
00068
00069 static struct poptOption poptHelpOptions2[] = {
00070
00071 { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
00072
00073 { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
00074 { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
00075 { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
00076 #ifdef NOTYET
00077 { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
00078 N_("Display option defaults in message"), NULL },
00079 #endif
00080 POPT_TABLEEND
00081 } ;
00082
00083
00084 struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
00085
00086
00090 static const char *const
00091 getTableTranslationDomain( const struct poptOption *table)
00092
00093 {
00094 const struct poptOption *opt;
00095
00096 if (table != NULL)
00097 for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
00098 if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
00099 return opt->arg;
00100 }
00101 return NULL;
00102 }
00103
00108 static const char *const
00109 getArgDescrip(const struct poptOption * opt,
00110
00111 const char * translation_domain)
00112
00113
00114 {
00115 if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
00116
00117 if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
00118 if (opt->argDescrip) return POPT_(opt->argDescrip);
00119
00120 if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
00121
00122 switch (opt->argInfo & POPT_ARG_MASK) {
00123 case POPT_ARG_NONE: return POPT_("NONE");
00124 #ifdef DYING
00125 case POPT_ARG_VAL: return POPT_("VAL");
00126 #else
00127 case POPT_ARG_VAL: return NULL;
00128 #endif
00129 case POPT_ARG_INT: return POPT_("INT");
00130 case POPT_ARG_LONG: return POPT_("LONG");
00131 case POPT_ARG_STRING: return POPT_("STRING");
00132 case POPT_ARG_FLOAT: return POPT_("FLOAT");
00133 case POPT_ARG_DOUBLE: return POPT_("DOUBLE");
00134 default: return POPT_("ARG");
00135 }
00136 }
00137
00145 static char *
00146 singleOptionDefaultValue(size_t lineLength,
00147 const struct poptOption * opt,
00148
00149 const char * translation_domain)
00150
00151
00152 {
00153 const char * defstr = D_(translation_domain, "default");
00154 char * le = malloc(4*lineLength + 1);
00155 char * l = le;
00156
00157 if (le == NULL) return NULL;
00158
00159 *le = '\0';
00160 *le++ = '(';
00161 strcpy(le, defstr); le += strlen(le);
00162 *le++ = ':';
00163 *le++ = ' ';
00164 if (opt->arg)
00165 switch (opt->argInfo & POPT_ARG_MASK) {
00166 case POPT_ARG_VAL:
00167 case POPT_ARG_INT:
00168 { long aLong = *((int *)opt->arg);
00169 le += sprintf(le, "%ld", aLong);
00170 } break;
00171 case POPT_ARG_LONG:
00172 { long aLong = *((long *)opt->arg);
00173 le += sprintf(le, "%ld", aLong);
00174 } break;
00175 case POPT_ARG_FLOAT:
00176 { double aDouble = *((float *)opt->arg);
00177 le += sprintf(le, "%g", aDouble);
00178 } break;
00179 case POPT_ARG_DOUBLE:
00180 { double aDouble = *((double *)opt->arg);
00181 le += sprintf(le, "%g", aDouble);
00182 } break;
00183 case POPT_ARG_STRING:
00184 { const char * s = *(const char **)opt->arg;
00185 if (s == NULL) {
00186 strcpy(le, "null"); le += strlen(le);
00187 } else {
00188 size_t slen = 4*lineLength - (le - l) - sizeof("\"...\")");
00189 *le++ = '"';
00190 strncpy(le, s, slen); le[slen] = '\0'; le += strlen(le);
00191 if (slen < strlen(s)) {
00192 strcpy(le, "..."); le += strlen(le);
00193 }
00194 *le++ = '"';
00195 }
00196 } break;
00197 case POPT_ARG_NONE:
00198 default:
00199 l = _free(l);
00200 return NULL;
00201 break;
00202 }
00203 *le++ = ')';
00204 *le = '\0';
00205
00206
00207 return l;
00208 }
00209
00217 static void singleOptionHelp(FILE * fp, size_t maxLeftCol,
00218 const struct poptOption * opt,
00219 const char * translation_domain)
00220
00221
00222 {
00223 size_t indentLength = maxLeftCol + 5;
00224 size_t lineLength = 79 - indentLength;
00225 const char * help = D_(translation_domain, opt->descrip);
00226 const char * argDescrip = getArgDescrip(opt, translation_domain);
00227 size_t helpLength;
00228 char * defs = NULL;
00229 char * left;
00230 size_t nb = maxLeftCol + 1;
00231 int displaypad = 0;
00232
00233
00234 if (opt->longName) nb += strlen(opt->longName);
00235 if (argDescrip) nb += strlen(argDescrip);
00236
00237
00238 left = malloc(nb);
00239 if (left == NULL) return;
00240 left[0] = '\0';
00241 left[maxLeftCol] = '\0';
00242
00243 if (opt->longName && opt->shortName)
00244 sprintf(left, "-%c, %s%s", opt->shortName,
00245 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
00246 opt->longName);
00247 else if (opt->shortName != '\0')
00248 sprintf(left, "-%c", opt->shortName);
00249 else if (opt->longName)
00250 sprintf(left, "%s%s",
00251 ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
00252 opt->longName);
00253 if (!*left) goto out;
00254
00255 if (argDescrip) {
00256 char * le = left + strlen(left);
00257
00258 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
00259 *le++ = '[';
00260
00261
00262
00263 if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
00264 defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
00265 if (defs) {
00266 char * t = malloc((help ? strlen(help) : 0) +
00267 strlen(defs) + sizeof(" "));
00268 if (t) {
00269 char * te = t;
00270 *te = '\0';
00271 if (help) {
00272 strcpy(te, help); te += strlen(te);
00273 }
00274 *te++ = ' ';
00275 strcpy(te, defs);
00276 defs = _free(defs);
00277 }
00278 defs = t;
00279 }
00280 }
00281
00282
00283 if (opt->argDescrip == NULL) {
00284 switch (opt->argInfo & POPT_ARG_MASK) {
00285 case POPT_ARG_NONE:
00286 break;
00287 case POPT_ARG_VAL:
00288 #ifdef NOTNOW
00289 { long aLong = opt->val;
00290 int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
00291 int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
00292
00293
00294 if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
00295 break;
00296 *le++ = '[';
00297 switch (ops) {
00298 case POPT_ARGFLAG_OR:
00299 *le++ = '|';
00300 break;
00301 case POPT_ARGFLAG_AND:
00302 *le++ = '&';
00303 break;
00304 case POPT_ARGFLAG_XOR:
00305 *le++ = '^';
00306 break;
00307 default:
00308 break;
00309 }
00310 *le++ = (opt->longName != NULL ? '=' : ' ');
00311 if (negate) *le++ = '~';
00312
00313 le += sprintf(le, (ops ? "0x%lx" : "%ld"), aLong);
00314
00315 *le++ = ']';
00316 }
00317 #endif
00318 break;
00319 case POPT_ARG_INT:
00320 case POPT_ARG_LONG:
00321 case POPT_ARG_FLOAT:
00322 case POPT_ARG_DOUBLE:
00323 case POPT_ARG_STRING:
00324 *le++ = (opt->longName != NULL ? '=' : ' ');
00325 strcpy(le, argDescrip); le += strlen(le);
00326 break;
00327 default:
00328 break;
00329 }
00330 } else {
00331 size_t lelen;
00332
00333 *le++ = '=';
00334 strcpy(le, argDescrip);
00335 lelen = strlen(le);
00336 le += lelen;
00337
00338 #ifdef POPT_WCHAR_HACK
00339 { const char * scopy = argDescrip;
00340 mbstate_t t;
00341 size_t n;
00342
00343 memset (&t, '\0', sizeof (t));
00344
00345 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
00346
00347 displaypad = (lelen-n);
00348 }
00349 #endif
00350 }
00351 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
00352 *le++ = ']';
00353 *le = '\0';
00354 }
00355
00356
00357 if (help)
00358 fprintf(fp," %-*s ", maxLeftCol+displaypad, left);
00359 else {
00360 fprintf(fp," %s\n", left);
00361 goto out;
00362 }
00363
00364 left = _free(left);
00365
00366 if (defs) {
00367 help = defs;
00368 defs = NULL;
00369 }
00370
00371
00372 helpLength = strlen(help);
00373
00374 while (helpLength > lineLength) {
00375 const char * ch;
00376 char format[16];
00377
00378 ch = help + lineLength - 1;
00379 while (ch > help && !isspace(*ch)) ch--;
00380 if (ch == help) break;
00381 while (ch > (help + 1) && isspace(*ch)) ch--;
00382 ch++;
00383
00384 sprintf(format, "%%.%ds\n%%%ds", (int) (ch - help), indentLength);
00385
00386 fprintf(fp, format, help, " ");
00387
00388 help = ch;
00389 while (isspace(*help) && *help) help++;
00390 helpLength = strlen(help);
00391 }
00392
00393
00394 if (helpLength) fprintf(fp, "%s\n", help);
00395
00396 out:
00397
00398 defs = _free(defs);
00399
00400 left = _free(left);
00401 }
00402
00409 static size_t maxArgWidth(const struct poptOption * opt,
00410 const char * translation_domain)
00411
00412 {
00413 size_t max = 0;
00414 size_t len = 0;
00415 const char * s;
00416
00417 if (opt != NULL)
00418 while (opt->longName || opt->shortName || opt->arg) {
00419 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
00420 if (opt->arg)
00421 len = maxArgWidth(opt->arg, translation_domain);
00422 if (len > max) max = len;
00423 } else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00424 len = sizeof(" ")-1;
00425 if (opt->shortName != '\0') len += sizeof("-X")-1;
00426 if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
00427 if (opt->longName) {
00428 len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
00429 ? sizeof("-")-1 : sizeof("--")-1);
00430 len += strlen(opt->longName);
00431 }
00432
00433 s = getArgDescrip(opt, translation_domain);
00434
00435 #ifdef POPT_WCHAR_HACK
00436
00437 if (s) {
00438 const char * scopy = s;
00439 mbstate_t t;
00440 size_t n;
00441
00442 memset (&t, '\0', sizeof (t));
00443
00444 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
00445 len += sizeof("=")-1 + n;
00446 }
00447 #else
00448 if (s)
00449 len += sizeof("=")-1 + strlen(s);
00450 #endif
00451
00452 if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
00453 if (len > max) max = len;
00454 }
00455
00456 opt++;
00457 }
00458
00459 return max;
00460 }
00461
00470 static void itemHelp(FILE * fp,
00471 poptItem items, int nitems, size_t left,
00472 const char * translation_domain)
00473
00474
00475 {
00476 poptItem item;
00477 int i;
00478
00479 if (items != NULL)
00480 for (i = 0, item = items; i < nitems; i++, item++) {
00481 const struct poptOption * opt;
00482 opt = &item->option;
00483 if ((opt->longName || opt->shortName) &&
00484 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
00485 singleOptionHelp(fp, left, opt, translation_domain);
00486 }
00487 }
00488
00497 static void singleTableHelp(poptContext con, FILE * fp,
00498 const struct poptOption * table, size_t left,
00499 const char * translation_domain)
00500
00501
00502 {
00503 const struct poptOption * opt;
00504 const char *sub_transdom;
00505
00506 if (table == poptAliasOptions) {
00507 itemHelp(fp, con->aliases, con->numAliases, left, NULL);
00508 itemHelp(fp, con->execs, con->numExecs, left, NULL);
00509 return;
00510 }
00511
00512 if (table != NULL)
00513 for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
00514 if ((opt->longName || opt->shortName) &&
00515 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
00516 singleOptionHelp(fp, left, opt, translation_domain);
00517 }
00518
00519 if (table != NULL)
00520 for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
00521 if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
00522 continue;
00523 sub_transdom = getTableTranslationDomain(opt->arg);
00524 if (sub_transdom == NULL)
00525 sub_transdom = translation_domain;
00526
00527 if (opt->descrip)
00528 fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
00529
00530 singleTableHelp(con, fp, opt->arg, left, sub_transdom);
00531 }
00532 }
00533
00538 static int showHelpIntro(poptContext con, FILE * fp)
00539
00540
00541 {
00542 int len = 6;
00543 const char * fn;
00544
00545 fprintf(fp, POPT_("Usage:"));
00546 if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
00547
00548
00549 fn = con->optionStack->argv[0];
00550
00551
00552 if (fn == NULL) return len;
00553 if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
00554 fprintf(fp, " %s", fn);
00555 len += strlen(fn) + 1;
00556 }
00557
00558 return len;
00559 }
00560
00561 void poptPrintHelp(poptContext con, FILE * fp, int flags)
00562 {
00563 size_t leftColWidth;
00564
00565 (void) showHelpIntro(con, fp);
00566 if (con->otherHelp)
00567 fprintf(fp, " %s\n", con->otherHelp);
00568 else
00569 fprintf(fp, " %s\n", POPT_("[OPTION...]"));
00570
00571 leftColWidth = maxArgWidth(con->options, NULL);
00572 singleTableHelp(con, fp, con->options, leftColWidth, NULL);
00573 }
00574
00582 static size_t singleOptionUsage(FILE * fp, size_t cursor,
00583 const struct poptOption * opt,
00584 const char *translation_domain)
00585
00586
00587 {
00588 size_t len = 4;
00589 char shortStr[2] = { '\0', '\0' };
00590 const char * item = shortStr;
00591 const char * argDescrip = getArgDescrip(opt, translation_domain);
00592
00593 if (opt->shortName != '\0' && opt->longName != NULL) {
00594 len += 2;
00595 if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
00596 len += strlen(opt->longName);
00597 } else if (opt->shortName != '\0') {
00598 len++;
00599 shortStr[0] = opt->shortName;
00600 shortStr[1] = '\0';
00601 } else if (opt->longName) {
00602 len += strlen(opt->longName);
00603 if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
00604 item = opt->longName;
00605 }
00606
00607 if (len == 4) return cursor;
00608
00609 #ifdef POPT_WCHAR_HACK
00610
00611 if (argDescrip) {
00612 const char * scopy = argDescrip;
00613 mbstate_t t;
00614 size_t n;
00615
00616 memset (&t, '\0', sizeof (t));
00617
00618 n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
00619 len += sizeof("=")-1 + n;
00620 }
00621 #else
00622 if (argDescrip)
00623 len += sizeof("=")-1 + strlen(argDescrip);
00624 #endif
00625
00626 if ((cursor + len) > 79) {
00627 fprintf(fp, "\n ");
00628 cursor = 7;
00629 }
00630
00631 if (opt->longName && opt->shortName) {
00632 fprintf(fp, " [-%c|-%s%s%s%s]",
00633 opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
00634 opt->longName,
00635 (argDescrip ? " " : ""),
00636 (argDescrip ? argDescrip : ""));
00637 } else {
00638 fprintf(fp, " [-%s%s%s%s]",
00639 ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
00640 item,
00641 (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
00642 (argDescrip ? argDescrip : ""));
00643 }
00644
00645 return cursor + len + 1;
00646 }
00647
00656 static size_t itemUsage(FILE * fp, size_t cursor,
00657 poptItem item, int nitems,
00658 const char * translation_domain)
00659
00660
00661 {
00662 int i;
00663
00664
00665 if (item != NULL)
00666 for (i = 0; i < nitems; i++, item++) {
00667 const struct poptOption * opt;
00668 opt = &item->option;
00669 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
00670 translation_domain = (const char *)opt->arg;
00671 } else if ((opt->longName || opt->shortName) &&
00672 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00673 cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
00674 }
00675 }
00676
00677
00678 return cursor;
00679 }
00680
00684 typedef struct poptDone_s {
00685 int nopts;
00686 int maxopts;
00687 const void ** opts;
00688 } * poptDone;
00689
00700 static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor,
00701 const struct poptOption * opt,
00702 const char * translation_domain,
00703 poptDone done)
00704
00705
00706 {
00707
00708 if (opt != NULL)
00709 for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
00710 if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
00711 translation_domain = (const char *)opt->arg;
00712 } else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
00713 if (done) {
00714 int i = 0;
00715 for (i = 0; i < done->nopts; i++) {
00716
00717 const void * that = done->opts[i];
00718
00719 if (that == NULL || that != opt->arg)
00720 continue;
00721 break;
00722 }
00723
00724 if (opt->arg == NULL || i < done->nopts)
00725 continue;
00726
00727 if (done->nopts < done->maxopts)
00728 done->opts[done->nopts++] = (const void *) opt->arg;
00729
00730 }
00731 cursor = singleTableUsage(con, fp, cursor, opt->arg,
00732 translation_domain, done);
00733 } else if ((opt->longName || opt->shortName) &&
00734 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
00735 cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
00736 }
00737 }
00738
00739
00740 return cursor;
00741 }
00742
00751 static int showShortOptions(const struct poptOption * opt, FILE * fp,
00752 char * str)
00753
00754
00755
00756 {
00757
00758 char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
00759 int len = 0;
00760
00761
00762 if (opt != NULL)
00763 for (; (opt->longName || opt->shortName || opt->arg); opt++) {
00764 if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
00765 s[strlen(s)] = opt->shortName;
00766 else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
00767 if (opt->arg)
00768 len = showShortOptions(opt->arg, fp, s);
00769 }
00770
00771
00772
00773 if (s == str && *s != '\0') {
00774 fprintf(fp, " [-%s]", s);
00775 len = strlen(s) + sizeof(" [-]")-1;
00776 }
00777 return len;
00778 }
00779
00780 void poptPrintUsage(poptContext con, FILE * fp, int flags)
00781 {
00782 poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done));
00783 size_t cursor;
00784
00785 done->nopts = 0;
00786 done->maxopts = 64;
00787 cursor = done->maxopts * sizeof(*done->opts);
00788
00789 done->opts = memset(alloca(cursor), 0, cursor);
00790
00791 done->opts[done->nopts++] = (const void *) con->options;
00792
00793
00794
00795 cursor = showHelpIntro(con, fp);
00796 cursor += showShortOptions(con->options, fp, NULL);
00797 cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
00798 cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
00799 cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
00800
00801 if (con->otherHelp) {
00802 cursor += strlen(con->otherHelp) + 1;
00803 if (cursor > 79) fprintf(fp, "\n ");
00804 fprintf(fp, " %s", con->otherHelp);
00805 }
00806
00807 fprintf(fp, "\n");
00808 }
00809
00810 void poptSetOtherOptionHelp(poptContext con, const char * text)
00811 {
00812 con->otherHelp = _free(con->otherHelp);
00813 con->otherHelp = xstrdup(text);
00814 }