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