File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / popt / popthelp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, v3_1_2p5, rsync3_0_9p0, RSYNC3_1_0, RSYNC3_0_9, HEAD
rsync

    1: /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
    2: 
    3: /** \ingroup popt
    4:  * \file popt/popthelp.c
    5:  */
    6: 
    7: /* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
    8:    file accompanying popt source distributions, available from 
    9:    ftp://ftp.rpm.org/pub/rpm/dist. */
   10: 
   11: #include "system.h"
   12: 
   13: /*#define POPT_WCHAR_HACK*/
   14: #ifdef 	POPT_WCHAR_HACK
   15: #include <wchar.h>			/* for mbsrtowcs */
   16: /*@access mbstate_t @*/
   17: #endif
   18: #include "poptint.h"
   19: 
   20: /*@access poptContext@*/
   21: 
   22: /**
   23:  * Display arguments.
   24:  * @param con		context
   25:  * @param foo		(unused)
   26:  * @param key		option(s)
   27:  * @param arg		(unused)
   28:  * @param data		(unused)
   29:  */
   30: static void displayArgs(poptContext con,
   31: 		/*@unused@*/ UNUSED(enum poptCallbackReason foo),
   32: 		struct poptOption * key, 
   33: 		/*@unused@*/ UNUSED(const char * arg), /*@unused@*/ UNUSED(void * data))
   34: 	/*@globals fileSystem@*/
   35: 	/*@modifies fileSystem@*/
   36: {
   37:     if (key->shortName == '?')
   38: 	poptPrintHelp(con, stdout, 0);
   39:     else
   40: 	poptPrintUsage(con, stdout, 0);
   41:     exit(0);
   42: }
   43: 
   44: #ifdef	NOTYET
   45: /*@unchecked@*/
   46: static int show_option_defaults = 0;
   47: #endif
   48: 
   49: /**
   50:  * Empty table marker to enable displaying popt alias/exec options.
   51:  */
   52: /*@observer@*/ /*@unchecked@*/
   53: struct poptOption poptAliasOptions[] = {
   54:     POPT_TABLEEND
   55: };
   56: 
   57: /**
   58:  * Auto help table options.
   59:  */
   60: /*@-castfcnptr@*/
   61: /*@observer@*/ /*@unchecked@*/
   62: struct poptOption poptHelpOptions[] = {
   63:   { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
   64:   { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
   65:   { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
   66:     POPT_TABLEEND
   67: } ;
   68: 
   69: /*@observer@*/ /*@unchecked@*/
   70: static struct poptOption poptHelpOptions2[] = {
   71: /*@-readonlytrans@*/
   72:   { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
   73: /*@=readonlytrans@*/
   74:   { NULL, '\0', POPT_ARG_CALLBACK, (void *)&displayArgs, '\0', NULL, NULL },
   75:   { "help", '?', 0, NULL, '?', N_("Show this help message"), NULL },
   76:   { "usage", '\0', 0, NULL, 'u', N_("Display brief usage message"), NULL },
   77: #ifdef	NOTYET
   78:   { "defaults", '\0', POPT_ARG_NONE, &show_option_defaults, 0,
   79: 	N_("Display option defaults in message"), NULL },
   80: #endif
   81:     POPT_TABLEEND
   82: } ;
   83: 
   84: /*@observer@*/ /*@unchecked@*/
   85: struct poptOption * poptHelpOptionsI18N = poptHelpOptions2;
   86: /*@=castfcnptr@*/
   87: 
   88: /**
   89:  * @param table		option(s)
   90:  */
   91: /*@observer@*/ /*@null@*/ static const char *
   92: getTableTranslationDomain(/*@null@*/ const struct poptOption *table)
   93: 	/*@*/
   94: {
   95:     const struct poptOption *opt;
   96: 
   97:     if (table != NULL)
   98:     for (opt = table; opt->longName || opt->shortName || opt->arg; opt++) {
   99: 	if (opt->argInfo == POPT_ARG_INTL_DOMAIN)
  100: 	    return opt->arg;
  101:     }
  102:     return NULL;
  103: }
  104: 
  105: /**
  106:  * @param opt		option(s)
  107:  * @param translation_domain	translation domain
  108:  */
  109: /*@observer@*/ /*@null@*/ static const char *
  110: getArgDescrip(const struct poptOption * opt,
  111: 		/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
  112: 		/*@null@*/ UNUSED(const char * translation_domain))
  113: 		/*@=paramuse@*/
  114: 	/*@*/
  115: {
  116:     if (!(opt->argInfo & POPT_ARG_MASK)) return NULL;
  117: 
  118:     if (opt == (poptHelpOptions + 1) || opt == (poptHelpOptions + 2))
  119: 	if (opt->argDescrip) return POPT_(opt->argDescrip);
  120: 
  121:     if (opt->argDescrip) return D_(translation_domain, opt->argDescrip);
  122: 
  123:     switch (opt->argInfo & POPT_ARG_MASK) {
  124:     /*case POPT_ARG_NONE:	return POPT_("NONE");*/ /* impossible */
  125: #ifdef	DYING
  126:     case POPT_ARG_VAL:		return POPT_("VAL");
  127: #else
  128:     case POPT_ARG_VAL:		return NULL;
  129: #endif
  130:     case POPT_ARG_INT:		return POPT_("INT");
  131:     case POPT_ARG_LONG:		return POPT_("LONG");
  132:     case POPT_ARG_STRING:	return POPT_("STRING");
  133:     case POPT_ARG_FLOAT:	return POPT_("FLOAT");
  134:     case POPT_ARG_DOUBLE:	return POPT_("DOUBLE");
  135:     default:			return POPT_("ARG");
  136:     }
  137: }
  138: 
  139: /**
  140:  * Display default value for an option.
  141:  * @param lineLength	display positions remaining
  142:  * @param opt		option(s)
  143:  * @param translation_domain	translation domain
  144:  * @return
  145:  */
  146: static /*@only@*/ /*@null@*/ char *
  147: singleOptionDefaultValue(size_t lineLength,
  148: 		const struct poptOption * opt,
  149: 		/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
  150: 		/*@null@*/ UNUSED(const char * translation_domain))
  151: 		/*@=paramuse@*/
  152: 	/*@*/
  153: {
  154:     const char * defstr = D_(translation_domain, "default");
  155:     size_t limit, bufsize = 4*lineLength + 1;
  156:     char * le = malloc(bufsize);
  157:     char * l = le;
  158: 
  159:     if (le == NULL) return NULL;	/* XXX can't happen */
  160: /*@-boundswrite@*/
  161:     *le++ = '(';
  162:     le += strlcpy(le, defstr, bufsize - 3);
  163:     *le++ = ':';
  164:     *le++ = ' ';
  165:     limit = bufsize - (le - l) - 1; /* -1 for closing paren */
  166:     if (opt->arg)	/* XXX programmer error */
  167:     switch (opt->argInfo & POPT_ARG_MASK) {
  168:     case POPT_ARG_VAL:
  169:     case POPT_ARG_INT:
  170:     {	long aLong = *((int *)opt->arg);
  171: 	le += snprintf(le, limit, "%ld", aLong);
  172:     }	break;
  173:     case POPT_ARG_LONG:
  174:     {	long aLong = *((long *)opt->arg);
  175: 	le += snprintf(le, limit, "%ld", aLong);
  176:     }	break;
  177:     case POPT_ARG_FLOAT:
  178:     {	double aDouble = *((float *)opt->arg);
  179: 	le += snprintf(le, limit, "%g", aDouble);
  180:     }	break;
  181:     case POPT_ARG_DOUBLE:
  182:     {	double aDouble = *((double *)opt->arg);
  183: 	le += snprintf(le, limit, "%g", aDouble);
  184:     }	break;
  185:     case POPT_ARG_STRING:
  186:     {	const char * s = *(const char **)opt->arg;
  187: 	if (s == NULL) {
  188: 	    le += strlcpy(le, "null", limit);
  189: 	} else {
  190: 	    size_t len;
  191: 	    limit -= 2; /* make room for quotes */
  192: 	    *le++ = '"';
  193: 	    len = strlcpy(le, s, limit);
  194: 	    if (len >= limit) {
  195: 		le += limit - 3 - 1;
  196: 		*le++ = '.'; *le++ = '.'; *le++ = '.';
  197: 	    } else
  198: 		le += len;
  199: 	    *le++ = '"';
  200: 	}
  201:     }	break;
  202:     case POPT_ARG_NONE:
  203:     default:
  204: 	l = _free(l);
  205: 	return NULL;
  206: 	/*@notreached@*/ break;
  207:     }
  208:     *le++ = ')';
  209:     *le = '\0';
  210: /*@=boundswrite@*/
  211: 
  212:     return l;
  213: }
  214: 
  215: /**
  216:  * Display help text for an option.
  217:  * @param fp		output file handle
  218:  * @param maxLeftCol	largest argument display width
  219:  * @param opt		option(s)
  220:  * @param translation_domain	translation domain
  221:  */
  222: static void singleOptionHelp(FILE * fp, size_t maxLeftCol, 
  223: 		const struct poptOption * opt,
  224: 		/*@null@*/ UNUSED(const char * translation_domain))
  225: 	/*@globals fileSystem @*/
  226: 	/*@modifies *fp, fileSystem @*/
  227: {
  228:     size_t indentLength = maxLeftCol + 5;
  229:     size_t lineLength = 79 - indentLength;
  230:     const char * help = D_(translation_domain, opt->descrip);
  231:     const char * argDescrip = getArgDescrip(opt, translation_domain);
  232:     size_t helpLength;
  233:     char * defs = NULL;
  234:     char * left;
  235:     size_t lelen, limit;
  236:     size_t nb = maxLeftCol + 1;
  237:     int displaypad = 0;
  238: 
  239:     /* Make sure there's more than enough room in target buffer. */
  240:     if (opt->longName)	nb += strlen(opt->longName);
  241:     if (argDescrip)	nb += strlen(argDescrip);
  242: 
  243: /*@-boundswrite@*/
  244:     left = malloc(nb);
  245:     if (left == NULL) return;	/* XXX can't happen */
  246:     left[0] = '\0';
  247:     left[maxLeftCol] = '\0';
  248: 
  249:     if (opt->longName && opt->shortName)
  250: 	snprintf(left, nb, "-%c, %s%s", opt->shortName,
  251: 		((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
  252: 		opt->longName);
  253:     else if (opt->shortName != '\0') 
  254: 	snprintf(left, nb, "-%c", opt->shortName);
  255:     else if (opt->longName)
  256: 	snprintf(left, nb, "%s%s",
  257: 		((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "-" : "--"),
  258: 		opt->longName);
  259:     if (!*left) goto out;
  260: 
  261:     if (argDescrip) {
  262: 	char * le = left + strlen(left);
  263: 
  264: 	if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
  265: 	    *le++ = '[';
  266: 
  267: 	/* Choose type of output */
  268: 	/*@-branchstate@*/
  269: 	if (opt->argInfo & POPT_ARGFLAG_SHOW_DEFAULT) {
  270: 	    defs = singleOptionDefaultValue(lineLength, opt, translation_domain);
  271: 	    if (defs) {
  272: 		size_t bufsize = (help ? strlen(help) : 0) + sizeof " " + strlen(defs);
  273: 		char * t = malloc(bufsize);
  274: 		if (t) {
  275: 		    snprintf(t, bufsize, "%s %s", help ? help : "", defs);
  276: 		    defs = _free(defs);
  277: 		}
  278: 		defs = t;
  279: 	    }
  280: 	}
  281: 	/*@=branchstate@*/
  282: 
  283: 	if (opt->argDescrip == NULL) {
  284: 	    switch (opt->argInfo & POPT_ARG_MASK) {
  285: 	    case POPT_ARG_NONE:
  286: 		break;
  287: 	    case POPT_ARG_VAL:
  288: #ifdef	NOTNOW	/* XXX pug ugly nerdy output */
  289: 	    {	long aLong = opt->val;
  290: 		int ops = (opt->argInfo & POPT_ARGFLAG_LOGICALOPS);
  291: 		int negate = (opt->argInfo & POPT_ARGFLAG_NOT);
  292: 
  293: 		/* Don't bother displaying typical values */
  294: 		if (!ops && (aLong == 0L || aLong == 1L || aLong == -1L))
  295: 		    break;
  296: 		*le++ = '[';
  297: 		switch (ops) {
  298: 		case POPT_ARGFLAG_OR:
  299: 		    *le++ = '|';
  300: 		    /*@innerbreak@*/ break;
  301: 		case POPT_ARGFLAG_AND:
  302: 		    *le++ = '&';
  303: 		    /*@innerbreak@*/ break;
  304: 		case POPT_ARGFLAG_XOR:
  305: 		    *le++ = '^';
  306: 		    /*@innerbreak@*/ break;
  307: 		default:
  308: 		    /*@innerbreak@*/ break;
  309: 		}
  310: 		*le++ = (opt->longName != NULL ? '=' : ' ');
  311: 		if (negate) *le++ = '~';
  312: 		/*@-formatconst@*/
  313: 		limit = nb - (le - left);
  314: 		lelen = snprintf(le, limit, (ops ? "0x%lx" : "%ld"), aLong);
  315: 		le += lelen >= limit ? limit - 1 : lelen;
  316: 		/*@=formatconst@*/
  317: 		*le++ = ']';
  318: 	    }
  319: #endif
  320: 		break;
  321: 	    case POPT_ARG_INT:
  322: 	    case POPT_ARG_LONG:
  323: 	    case POPT_ARG_FLOAT:
  324: 	    case POPT_ARG_DOUBLE:
  325: 	    case POPT_ARG_STRING:
  326: 		*le++ = (opt->longName != NULL ? '=' : ' ');
  327: 		limit = nb - (le - left);
  328: 		lelen = strlcpy(le, argDescrip, limit);
  329: 		le += lelen >= limit ? limit - 1 : lelen;
  330: 		break;
  331: 	    default:
  332: 		break;
  333: 	    }
  334: 	} else {
  335: 
  336: 	    *le++ = '=';
  337: 	    limit = nb - (le - left);
  338: 	    lelen = strlcpy(le, argDescrip, limit);
  339: 	    if (lelen >= limit)
  340: 		lelen = limit - 1;
  341: 	    le += lelen;
  342: 
  343: #ifdef	POPT_WCHAR_HACK
  344: 	    {	const char * scopy = argDescrip;
  345: 		mbstate_t t;
  346: 		size_t n;
  347: 
  348: 		memset ((void *)&t, '\0', sizeof (t));	/* In initial state.  */
  349: 		/* Determine number of characters.  */
  350: 		n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
  351: 
  352: 		displaypad = (int) (lelen-n);
  353: 	    }
  354: #endif
  355: 	}
  356: 	if (opt->argInfo & POPT_ARGFLAG_OPTIONAL)
  357: 	    *le++ = ']';
  358: 	*le = '\0';
  359:     }
  360: /*@=boundswrite@*/
  361: 
  362:     if (help)
  363: 	fprintf(fp,"  %-*s   ", (int)maxLeftCol+displaypad, left);
  364:     else {
  365: 	fprintf(fp,"  %s\n", left); 
  366: 	goto out;
  367:     }
  368: 
  369:     left = _free(left);
  370: /*@-branchstate@*/
  371:     if (defs) {
  372: 	help = defs;
  373: 	defs = NULL;
  374:     }
  375: /*@=branchstate@*/
  376: 
  377:     helpLength = strlen(help);
  378: /*@-boundsread@*/
  379:     while (helpLength > lineLength) {
  380: 	const char * ch;
  381: 	char format[16];
  382: 
  383: 	ch = help + lineLength - 1;
  384: 	while (ch > help && !isSpace(ch)) ch--;
  385: 	if (ch == help) break;		/* give up */
  386: 	while (ch > (help + 1) && isSpace(ch)) ch--;
  387: 	ch++;
  388: 
  389: 	snprintf(format, sizeof format, "%%.%ds\n%%%ds", (int) (ch - help), (int) indentLength);
  390: 	/*@-formatconst@*/
  391: 	fprintf(fp, format, help, " ");
  392: 	/*@=formatconst@*/
  393: 	help = ch;
  394: 	while (isSpace(help) && *help) help++;
  395: 	helpLength = strlen(help);
  396:     }
  397: /*@=boundsread@*/
  398: 
  399:     if (helpLength) fprintf(fp, "%s\n", help);
  400: 
  401: out:
  402:     /*@-dependenttrans@*/
  403:     defs = _free(defs);
  404:     /*@=dependenttrans@*/
  405:     left = _free(left);
  406: }
  407: 
  408: /**
  409:  * Find display width for longest argument string.
  410:  * @param opt		option(s)
  411:  * @param translation_domain	translation domain
  412:  * @return		display width
  413:  */
  414: static size_t maxArgWidth(const struct poptOption * opt,
  415: 		       /*@null@*/ UNUSED(const char * translation_domain))
  416: 	/*@*/
  417: {
  418:     size_t max = 0;
  419:     size_t len = 0;
  420:     const char * s;
  421:     
  422:     if (opt != NULL)
  423:     while (opt->longName || opt->shortName || opt->arg) {
  424: 	if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
  425: 	    if (opt->arg)	/* XXX program error */
  426: 	    len = maxArgWidth(opt->arg, translation_domain);
  427: 	    if (len > max) max = len;
  428: 	} else if (!(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
  429: 	    len = sizeof("  ")-1;
  430: 	    if (opt->shortName != '\0') len += sizeof("-X")-1;
  431: 	    if (opt->shortName != '\0' && opt->longName) len += sizeof(", ")-1;
  432: 	    if (opt->longName) {
  433: 		len += ((opt->argInfo & POPT_ARGFLAG_ONEDASH)
  434: 			? sizeof("-")-1 : sizeof("--")-1);
  435: 		len += strlen(opt->longName);
  436: 	    }
  437: 
  438: 	    s = getArgDescrip(opt, translation_domain);
  439: 
  440: #ifdef POPT_WCHAR_HACK
  441: 	    /* XXX Calculate no. of display characters. */
  442: 	    if (s) {
  443: 		const char * scopy = s;
  444: 		mbstate_t t;
  445: 		size_t n;
  446: 
  447: /*@-boundswrite@*/
  448: 		memset ((void *)&t, '\0', sizeof (t));	/* In initial state.  */
  449: /*@=boundswrite@*/
  450: 		/* Determine number of characters.  */
  451: 		n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
  452: 		len += sizeof("=")-1 + n;
  453: 	    }
  454: #else
  455: 	    if (s)
  456: 		len += sizeof("=")-1 + strlen(s);
  457: #endif
  458: 
  459: 	    if (opt->argInfo & POPT_ARGFLAG_OPTIONAL) len += sizeof("[]")-1;
  460: 	    if (len > max) max = len;
  461: 	}
  462: 
  463: 	opt++;
  464:     }
  465:     
  466:     return max;
  467: }
  468: 
  469: /**
  470:  * Display popt alias and exec help.
  471:  * @param fp		output file handle
  472:  * @param items		alias/exec array
  473:  * @param nitems	no. of alias/exec entries
  474:  * @param left		largest argument display width
  475:  * @param translation_domain	translation domain
  476:  */
  477: static void itemHelp(FILE * fp,
  478: 		/*@null@*/ poptItem items, int nitems, size_t left,
  479: 		/*@null@*/ UNUSED(const char * translation_domain))
  480: 	/*@globals fileSystem @*/
  481: 	/*@modifies *fp, fileSystem @*/
  482: {
  483:     poptItem item;
  484:     int i;
  485: 
  486:     if (items != NULL)
  487:     for (i = 0, item = items; i < nitems; i++, item++) {
  488: 	const struct poptOption * opt;
  489: 	opt = &item->option;
  490: 	if ((opt->longName || opt->shortName) && 
  491: 	    !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
  492: 	    singleOptionHelp(fp, left, opt, translation_domain);
  493:     }
  494: }
  495: 
  496: /**
  497:  * Display help text for a table of options.
  498:  * @param con		context
  499:  * @param fp		output file handle
  500:  * @param table		option(s)
  501:  * @param left		largest argument display width
  502:  * @param translation_domain	translation domain
  503:  */
  504: static void singleTableHelp(poptContext con, FILE * fp,
  505: 		/*@null@*/ const struct poptOption * table, size_t left,
  506: 		/*@null@*/ UNUSED(const char * translation_domain))
  507: 	/*@globals fileSystem @*/
  508: 	/*@modifies *fp, fileSystem @*/
  509: {
  510:     const struct poptOption * opt;
  511:     const char *sub_transdom;
  512: 
  513:     if (table == poptAliasOptions) {
  514: 	itemHelp(fp, con->aliases, con->numAliases, left, NULL);
  515: 	itemHelp(fp, con->execs, con->numExecs, left, NULL);
  516: 	return;
  517:     }
  518: 
  519:     if (table != NULL)
  520:     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
  521: 	if ((opt->longName || opt->shortName) && 
  522: 	    !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN))
  523: 	    singleOptionHelp(fp, left, opt, translation_domain);
  524:     }
  525: 
  526:     if (table != NULL)
  527:     for (opt = table; (opt->longName || opt->shortName || opt->arg); opt++) {
  528: 	if ((opt->argInfo & POPT_ARG_MASK) != POPT_ARG_INCLUDE_TABLE)
  529: 	    continue;
  530: 	sub_transdom = getTableTranslationDomain(opt->arg);
  531: 	if (sub_transdom == NULL)
  532: 	    sub_transdom = translation_domain;
  533: 	    
  534: 	if (opt->descrip)
  535: 	    fprintf(fp, "\n%s\n", D_(sub_transdom, opt->descrip));
  536: 
  537: 	singleTableHelp(con, fp, opt->arg, left, sub_transdom);
  538:     }
  539: }
  540: 
  541: /**
  542:  * @param con		context
  543:  * @param fp		output file handle
  544:  */
  545: static int showHelpIntro(poptContext con, FILE * fp)
  546: 	/*@globals fileSystem @*/
  547: 	/*@modifies *fp, fileSystem @*/
  548: {
  549:     int len = 6;
  550:     const char * fn;
  551: 
  552:     fprintf(fp, POPT_("Usage:"));
  553:     if (!(con->flags & POPT_CONTEXT_KEEP_FIRST)) {
  554: /*@-boundsread@*/
  555: 	/*@-nullderef -type@*/	/* LCL: wazzup? */
  556: 	fn = con->optionStack->argv[0];
  557: 	/*@=nullderef =type@*/
  558: /*@=boundsread@*/
  559: 	if (fn == NULL) return len;
  560: 	if (strchr(fn, '/')) fn = strrchr(fn, '/') + 1;
  561: 	fprintf(fp, " %s", fn);
  562: 	len += strlen(fn) + 1;
  563:     }
  564: 
  565:     return len;
  566: }
  567: 
  568: void poptPrintHelp(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
  569: {
  570:     size_t leftColWidth;
  571: 
  572:     (void) showHelpIntro(con, fp);
  573:     if (con->otherHelp)
  574: 	fprintf(fp, " %s\n", con->otherHelp);
  575:     else
  576: 	fprintf(fp, " %s\n", POPT_("[OPTION...]"));
  577: 
  578:     leftColWidth = maxArgWidth(con->options, NULL);
  579:     singleTableHelp(con, fp, con->options, leftColWidth, NULL);
  580: }
  581: 
  582: /**
  583:  * Display usage text for an option.
  584:  * @param fp		output file handle
  585:  * @param cursor	current display position
  586:  * @param opt		option(s)
  587:  * @param translation_domain	translation domain
  588:  */
  589: static size_t singleOptionUsage(FILE * fp, size_t cursor, 
  590: 		const struct poptOption * opt,
  591: 		/*@null@*/ const char *translation_domain)
  592: 	/*@globals fileSystem @*/
  593: 	/*@modifies *fp, fileSystem @*/
  594: {
  595:     size_t len = 4;
  596:     char shortStr[2] = { '\0', '\0' };
  597:     const char * item = shortStr;
  598:     const char * argDescrip = getArgDescrip(opt, translation_domain);
  599: 
  600:     if (opt->shortName != '\0' && opt->longName != NULL) {
  601: 	len += 2;
  602: 	if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
  603: 	len += strlen(opt->longName);
  604:     } else if (opt->shortName != '\0') {
  605: 	len++;
  606: 	shortStr[0] = opt->shortName;
  607: 	shortStr[1] = '\0';
  608:     } else if (opt->longName) {
  609: 	len += strlen(opt->longName);
  610: 	if (!(opt->argInfo & POPT_ARGFLAG_ONEDASH)) len++;
  611: 	item = opt->longName;
  612:     }
  613: 
  614:     if (len == 4) return cursor;
  615: 
  616: #ifdef POPT_WCHAR_HACK
  617:     /* XXX Calculate no. of display characters. */
  618:     if (argDescrip) {
  619: 	const char * scopy = argDescrip;
  620: 	mbstate_t t;
  621: 	size_t n;
  622: 
  623: /*@-boundswrite@*/
  624: 	memset ((void *)&t, '\0', sizeof (t));	/* In initial state.  */
  625: /*@=boundswrite@*/
  626: 	/* Determine number of characters.  */
  627: 	n = mbsrtowcs (NULL, &scopy, strlen(scopy), &t);
  628: 	len += sizeof("=")-1 + n;
  629:     }
  630: #else
  631:     if (argDescrip) 
  632: 	len += sizeof("=")-1 + strlen(argDescrip);
  633: #endif
  634: 
  635:     if ((cursor + len) > 79) {
  636: 	fprintf(fp, "\n       ");
  637: 	cursor = 7;
  638:     } 
  639: 
  640:     if (opt->longName && opt->shortName) {
  641: 	fprintf(fp, " [-%c|-%s%s%s%s]",
  642: 	    opt->shortName, ((opt->argInfo & POPT_ARGFLAG_ONEDASH) ? "" : "-"),
  643: 	    opt->longName,
  644: 	    (argDescrip ? " " : ""),
  645: 	    (argDescrip ? argDescrip : ""));
  646:     } else {
  647: 	fprintf(fp, " [-%s%s%s%s]",
  648: 	    ((opt->shortName || (opt->argInfo & POPT_ARGFLAG_ONEDASH)) ? "" : "-"),
  649: 	    item,
  650: 	    (argDescrip ? (opt->shortName != '\0' ? " " : "=") : ""),
  651: 	    (argDescrip ? argDescrip : ""));
  652:     }
  653: 
  654:     return cursor + len + 1;
  655: }
  656: 
  657: /**
  658:  * Display popt alias and exec usage.
  659:  * @param fp		output file handle
  660:  * @param cursor	current display position
  661:  * @param item		alias/exec array
  662:  * @param nitems	no. of ara/exec entries
  663:  * @param translation_domain	translation domain
  664:  */
  665: static size_t itemUsage(FILE * fp, size_t cursor,
  666: 		/*@null@*/ poptItem item, int nitems,
  667: 		/*@null@*/ UNUSED(const char * translation_domain))
  668: 	/*@globals fileSystem @*/
  669: 	/*@modifies *fp, fileSystem @*/
  670: {
  671:     int i;
  672: 
  673:     /*@-branchstate@*/		/* FIX: W2DO? */
  674:     if (item != NULL)
  675:     for (i = 0; i < nitems; i++, item++) {
  676: 	const struct poptOption * opt;
  677: 	opt = &item->option;
  678:         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
  679: 	    translation_domain = (const char *)opt->arg;
  680: 	} else if ((opt->longName || opt->shortName) &&
  681: 		 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
  682: 	    cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
  683: 	}
  684:     }
  685:     /*@=branchstate@*/
  686: 
  687:     return cursor;
  688: }
  689: 
  690: /**
  691:  * Keep track of option tables already processed.
  692:  */
  693: typedef struct poptDone_s {
  694:     int nopts;
  695:     int maxopts;
  696:     const void ** opts;
  697: } * poptDone;
  698: 
  699: /**
  700:  * Display usage text for a table of options.
  701:  * @param con		context
  702:  * @param fp		output file handle
  703:  * @param cursor	current display position
  704:  * @param opt		option(s)
  705:  * @param translation_domain	translation domain
  706:  * @param done		tables already processed
  707:  * @return
  708:  */
  709: static size_t singleTableUsage(poptContext con, FILE * fp, size_t cursor,
  710: 		/*@null@*/ const struct poptOption * opt,
  711: 		/*@null@*/ UNUSED(const char * translation_domain),
  712: 		/*@null@*/ poptDone done)
  713: 	/*@globals fileSystem @*/
  714: 	/*@modifies *fp, done, fileSystem @*/
  715: {
  716:     /*@-branchstate@*/		/* FIX: W2DO? */
  717:     if (opt != NULL)
  718:     for (; (opt->longName || opt->shortName || opt->arg) ; opt++) {
  719:         if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INTL_DOMAIN) {
  720: 	    translation_domain = (const char *)opt->arg;
  721: 	} else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE) {
  722: 	    if (done) {
  723: 		int i = 0;
  724: 		for (i = 0; i < done->nopts; i++) {
  725: /*@-boundsread@*/
  726: 		    const void * that = done->opts[i];
  727: /*@=boundsread@*/
  728: 		    if (that == NULL || that != opt->arg)
  729: 			/*@innercontinue@*/ continue;
  730: 		    /*@innerbreak@*/ break;
  731: 		}
  732: 		/* Skip if this table has already been processed. */
  733: 		if (opt->arg == NULL || i < done->nopts)
  734: 		    continue;
  735: /*@-boundswrite@*/
  736: 		if (done->nopts < done->maxopts)
  737: 		    done->opts[done->nopts++] = (const void *) opt->arg;
  738: /*@=boundswrite@*/
  739: 	    }
  740: 	    cursor = singleTableUsage(con, fp, cursor, opt->arg,
  741: 			translation_domain, done);
  742: 	} else if ((opt->longName || opt->shortName) &&
  743: 		 !(opt->argInfo & POPT_ARGFLAG_DOC_HIDDEN)) {
  744: 	    cursor = singleOptionUsage(fp, cursor, opt, translation_domain);
  745: 	}
  746:     }
  747:     /*@=branchstate@*/
  748: 
  749:     return cursor;
  750: }
  751: 
  752: /**
  753:  * Return concatenated short options for display.
  754:  * @todo Sub-tables should be recursed.
  755:  * @param opt		option(s)
  756:  * @param fp		output file handle
  757:  * @retval str		concatenation of short options
  758:  * @return		length of display string
  759:  */
  760: static int showShortOptions(const struct poptOption * opt, FILE * fp,
  761: 		/*@null@*/ char * str)
  762: 	/*@globals fileSystem @*/
  763: 	/*@modifies *str, *fp, fileSystem @*/
  764: 	/*@requires maxRead(str) >= 0 @*/
  765: {
  766:     /* bufsize larger then the ascii set, lazy alloca on top level call. */
  767:     char * s = (str != NULL ? str : memset(alloca(300), 0, 300));
  768:     int len = 0;
  769: 
  770:     if (s == NULL)
  771: 	return 0;
  772: 
  773: /*@-boundswrite@*/
  774:     if (opt != NULL)
  775:     for (; (opt->longName || opt->shortName || opt->arg); opt++) {
  776: 	if (opt->shortName && !(opt->argInfo & POPT_ARG_MASK))
  777: 	    s[strlen(s)] = opt->shortName;
  778: 	else if ((opt->argInfo & POPT_ARG_MASK) == POPT_ARG_INCLUDE_TABLE)
  779: 	    if (opt->arg)	/* XXX program error */
  780: 		len = showShortOptions(opt->arg, fp, s);
  781:     } 
  782: /*@=boundswrite@*/
  783: 
  784:     /* On return to top level, print the short options, return print length. */
  785:     if (s == str && *s != '\0') {
  786: 	fprintf(fp, " [-%s]", s);
  787: 	len = strlen(s) + sizeof(" [-]")-1;
  788:     }
  789:     return len;
  790: }
  791: 
  792: void poptPrintUsage(poptContext con, FILE * fp, /*@unused@*/ UNUSED(int flags))
  793: {
  794:     poptDone done = memset(alloca(sizeof(*done)), 0, sizeof(*done));
  795:     size_t cursor;
  796: 
  797:     done->nopts = 0;
  798:     done->maxopts = 64;
  799:     cursor = done->maxopts * sizeof(*done->opts);
  800: /*@-boundswrite@*/
  801:     done->opts = memset(alloca(cursor), 0, cursor);
  802:     /*@-keeptrans@*/
  803:     done->opts[done->nopts++] = (const void *) con->options;
  804:     /*@=keeptrans@*/
  805: /*@=boundswrite@*/
  806: 
  807:     cursor = showHelpIntro(con, fp);
  808:     cursor += showShortOptions(con->options, fp, NULL);
  809:     cursor = singleTableUsage(con, fp, cursor, con->options, NULL, done);
  810:     cursor = itemUsage(fp, cursor, con->aliases, con->numAliases, NULL);
  811:     cursor = itemUsage(fp, cursor, con->execs, con->numExecs, NULL);
  812: 
  813:     if (con->otherHelp) {
  814: 	cursor += strlen(con->otherHelp) + 1;
  815: 	if (cursor > 79) fprintf(fp, "\n       ");
  816: 	fprintf(fp, " %s", con->otherHelp);
  817:     }
  818: 
  819:     fprintf(fp, "\n");
  820: }
  821: 
  822: void poptSetOtherOptionHelp(poptContext con, const char * text)
  823: {
  824:     con->otherHelp = _free(con->otherHelp);
  825:     con->otherHelp = xstrdup(text);
  826: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>