2014-07-23 11:17:30 +04:00
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/** \ingroup popt
* \ file popt / popthelp . c
*/
/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING
file accompanying popt source distributions , available from
ftp : //ftp.rpm.org/pub/rpm/dist. */
# include "system.h"
2018-05-08 08:25:12 +03:00
# define POPT_USE_TIOCGWINSZ
# ifdef POPT_USE_TIOCGWINSZ
# include <sys/ioctl.h>
# endif
# define POPT_WCHAR_HACK
# ifdef POPT_WCHAR_HACK
# include <wchar.h> /* for mbsrtowcs */
/*@access mbstate_t @*/
# endif
2014-07-23 11:17:30 +04:00
# include "poptint.h"
2018-05-08 08:25:12 +03:00
/*@access poptContext@*/
2014-07-23 11:17:30 +04:00
/**
* Display arguments .
* @ param con context
* @ param foo ( unused )
* @ param key option ( s )
* @ param arg ( unused )
* @ param data ( unused )
*/
2018-05-08 08:25:12 +03:00
/*@exits@*/
2014-07-23 11:17:30 +04:00
static void displayArgs ( poptContext con ,
2018-05-08 08:25:12 +03:00
/*@unused@*/ UNUSED ( enum poptCallbackReason foo ) ,
2014-07-23 11:17:30 +04:00
struct poptOption * key ,
2018-05-08 08:25:12 +03:00
/*@unused@*/ UNUSED ( const char * arg ) ,
/*@unused@*/ UNUSED ( void * data ) )
2014-07-23 11:17:30 +04:00
/*@globals fileSystem@*/
/*@modifies fileSystem@*/
{
if ( key - > shortName = = ' ? ' )
poptPrintHelp ( con , stdout , 0 ) ;
else
poptPrintUsage ( con , stdout , 0 ) ;
2018-05-08 08:25:12 +03:00
# if !defined(__LCLINT__) /* XXX keep both splint & valgrind happy */
con = poptFreeContext ( con ) ;
# endif
2014-07-23 11:17:30 +04:00
exit ( 0 ) ;
}
# ifdef NOTYET
/*@unchecked@*/
static int show_option_defaults = 0 ;
# endif
/**
* Empty table marker to enable displaying popt alias / exec options .
*/
/*@observer@*/ /*@unchecked@*/
struct poptOption poptAliasOptions [ ] = {
POPT_TABLEEND
} ;
/**
* Auto help table options .
*/
/*@-castfcnptr@*/
/*@observer@*/ /*@unchecked@*/
struct poptOption poptHelpOptions [ ] = {
2018-05-08 08:25:12 +03:00
{ NULL , ' \0 ' , POPT_ARG_CALLBACK , ( void * ) displayArgs , 0 , NULL , NULL } ,
{ " help " , ' ? ' , 0 , NULL , ( int ) ' ? ' , N_ ( " Show this help message " ) , NULL } ,
{ " usage " , ' \0 ' , 0 , NULL , ( int ) ' u ' , N_ ( " Display brief usage message " ) , NULL } ,
POPT_TABLEEND
} ;
/*@observer@*/ /*@unchecked@*/
static struct poptOption poptHelpOptions2 [ ] = {
/*@-readonlytrans@*/
{ NULL , ' \0 ' , POPT_ARG_INTL_DOMAIN , PACKAGE , 0 , NULL , NULL } ,
/*@=readonlytrans@*/
{ NULL , ' \0 ' , POPT_ARG_CALLBACK , ( void * ) displayArgs , 0 , NULL , NULL } ,
{ " help " , ' ? ' , 0 , NULL , ( int ) ' ? ' , N_ ( " Show this help message " ) , NULL } ,
{ " usage " , ' \0 ' , 0 , NULL , ( int ) ' u ' , N_ ( " Display brief usage message " ) , NULL } ,
2014-07-23 11:17:30 +04:00
# ifdef NOTYET
{ " defaults " , ' \0 ' , POPT_ARG_NONE , & show_option_defaults , 0 ,
N_ ( " Display option defaults in message " ) , NULL } ,
# endif
2018-05-08 08:25:12 +03:00
{ " " , ' \0 ' , 0 , NULL , 0 , N_ ( " Terminate options " ) , NULL } ,
2014-07-23 11:17:30 +04:00
POPT_TABLEEND
} ;
2018-05-08 08:25:12 +03:00
/*@observer@*/ /*@unchecked@*/
struct poptOption * poptHelpOptionsI18N = poptHelpOptions2 ;
2014-07-23 11:17:30 +04:00
/*@=castfcnptr@*/
2018-05-08 08:25:12 +03:00
# define _POPTHELP_MAXLINE ((size_t)79)
typedef struct columns_s {
size_t cur ;
size_t max ;
} * columns_t ;
2014-07-23 11:17:30 +04:00
/**
2018-05-08 08:25:12 +03:00
* Return no . of columns in output window .
* @ param fp FILE
* @ return no . of columns
2014-07-23 11:17:30 +04:00
*/
2018-05-08 08:25:12 +03:00
static size_t maxColumnWidth ( FILE * fp )
/*@*/
{
size_t maxcols = _POPTHELP_MAXLINE ;
# if defined(TIOCGWINSZ)
struct winsize ws ;
int fdno = fileno ( fp ? fp : stdout ) ;
memset ( & ws , 0 , sizeof ( ws ) ) ;
if ( fdno > = 0 & & ! ioctl ( fdno , ( unsigned long ) TIOCGWINSZ , & ws ) ) {
size_t ws_col = ( size_t ) ws . ws_col ;
if ( ws_col > maxcols & & ws_col < ( size_t ) 256 )
maxcols = ws_col - 1 ;
}
# endif
return maxcols ;
}
/**
* Determine number of display characters in a string .
* @ param s string
* @ return no . of display characters .
*/
static inline size_t stringDisplayWidth ( const char * s )
2014-07-23 11:17:30 +04:00
/*@*/
{
2018-05-08 08:25:12 +03:00
size_t n = strlen ( s ) ;
# ifdef POPT_WCHAR_HACK
mbstate_t t ;
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
memset ( ( void * ) & t , 0 , sizeof ( t ) ) ; /* In initial state. */
/* Determine number of display characters. */
n = mbsrtowcs ( NULL , & s , n , & t ) ;
# else
n = 0 ;
for ( ; * s ; s = POPT_next_char ( s ) )
n + + ;
# endif
return n ;
}
/**
* @ param opt option ( s )
*/
/*@observer@*/ /*@null@*/ static const char *
getTableTranslationDomain ( /*@null@*/ const struct poptOption * opt )
/*@*/
{
if ( opt ! = NULL )
for ( ; opt - > longName | | opt - > shortName | | opt - > arg ; opt + + ) {
2014-07-23 11:17:30 +04:00
if ( opt - > argInfo = = POPT_ARG_INTL_DOMAIN )
2018-05-08 08:25:12 +03:00
return opt - > arg ;
2014-07-23 11:17:30 +04:00
}
return NULL ;
}
/**
* @ param opt option ( s )
* @ param translation_domain translation domain
*/
/*@observer@*/ /*@null@*/ static const char *
getArgDescrip ( const struct poptOption * opt ,
/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
/*@null@*/ const char * translation_domain )
/*@=paramuse@*/
/*@*/
{
2018-05-08 08:25:12 +03:00
if ( ! poptArgType ( opt ) ) return NULL ;
if ( poptArgType ( opt ) = = POPT_ARG_MAINCALL )
return opt - > argDescrip ;
if ( poptArgType ( opt ) = = POPT_ARG_ARGV )
return opt - > argDescrip ;
if ( opt - > argDescrip ) {
/* Some strings need popt library, not application, i18n domain. */
if ( opt = = ( poptHelpOptions + 1 )
| | opt = = ( poptHelpOptions + 2 )
| | ! strcmp ( opt - > argDescrip , N_ ( " Help options: " ) )
| | ! strcmp ( opt - > argDescrip , N_ ( " Options implemented via popt alias/exec: " ) ) )
return POPT_ ( opt - > argDescrip ) ;
/* Use the application i18n domain. */
return D_ ( translation_domain , opt - > argDescrip ) ;
}
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
switch ( poptArgType ( opt ) ) {
2014-07-23 11:17:30 +04:00
case POPT_ARG_NONE : return POPT_ ( " NONE " ) ;
# ifdef DYING
case POPT_ARG_VAL : return POPT_ ( " VAL " ) ;
# else
case POPT_ARG_VAL : return NULL ;
# endif
case POPT_ARG_INT : return POPT_ ( " INT " ) ;
2018-05-08 08:25:12 +03:00
case POPT_ARG_SHORT : return POPT_ ( " SHORT " ) ;
2014-07-23 11:17:30 +04:00
case POPT_ARG_LONG : return POPT_ ( " LONG " ) ;
2018-05-08 08:25:12 +03:00
case POPT_ARG_LONGLONG : return POPT_ ( " LONGLONG " ) ;
2014-07-23 11:17:30 +04:00
case POPT_ARG_STRING : return POPT_ ( " STRING " ) ;
case POPT_ARG_FLOAT : return POPT_ ( " FLOAT " ) ;
case POPT_ARG_DOUBLE : return POPT_ ( " DOUBLE " ) ;
2018-05-08 08:25:12 +03:00
case POPT_ARG_MAINCALL : return NULL ;
case POPT_ARG_ARGV : return NULL ;
2014-07-23 11:17:30 +04:00
default : return POPT_ ( " ARG " ) ;
}
}
/**
* Display default value for an option .
2018-05-08 08:25:12 +03:00
* @ param lineLength display positions remaining
2014-07-23 11:17:30 +04:00
* @ param opt option ( s )
* @ param translation_domain translation domain
* @ return
*/
static /*@only@*/ /*@null@*/ char *
2018-05-08 08:25:12 +03:00
singleOptionDefaultValue ( size_t lineLength ,
2014-07-23 11:17:30 +04:00
const struct poptOption * opt ,
/*@-paramuse@*/ /* FIX: i18n macros disabled with lclint */
/*@null@*/ const char * translation_domain )
/*@=paramuse@*/
/*@*/
{
const char * defstr = D_ ( translation_domain , " default " ) ;
2018-05-08 08:25:12 +03:00
char * le = malloc ( 4 * lineLength + 1 ) ;
2014-07-23 11:17:30 +04:00
char * l = le ;
if ( le = = NULL ) return NULL ; /* XXX can't happen */
* le = ' \0 ' ;
* le + + = ' ( ' ;
2018-05-08 08:25:12 +03:00
le = stpcpy ( le , defstr ) ;
2014-07-23 11:17:30 +04:00
* le + + = ' : ' ;
* le + + = ' ' ;
2018-05-08 08:25:12 +03:00
if ( opt - > arg ) { /* XXX programmer error */
poptArg arg = { . ptr = opt - > arg } ;
switch ( poptArgType ( opt ) ) {
2014-07-23 11:17:30 +04:00
case POPT_ARG_VAL :
case POPT_ARG_INT :
2018-05-08 08:25:12 +03:00
le + = sprintf ( le , " %d " , arg . intp [ 0 ] ) ;
break ;
case POPT_ARG_SHORT :
le + = sprintf ( le , " %hd " , arg . shortp [ 0 ] ) ;
break ;
2014-07-23 11:17:30 +04:00
case POPT_ARG_LONG :
2018-05-08 08:25:12 +03:00
le + = sprintf ( le , " %ld " , arg . longp [ 0 ] ) ;
break ;
case POPT_ARG_LONGLONG :
le + = sprintf ( le , " %lld " , arg . longlongp [ 0 ] ) ;
break ;
2014-07-23 11:17:30 +04:00
case POPT_ARG_FLOAT :
2018-05-08 08:25:12 +03:00
{ double aDouble = ( double ) arg . floatp [ 0 ] ;
2014-07-23 11:17:30 +04:00
le + = sprintf ( le , " %g " , aDouble ) ;
} break ;
case POPT_ARG_DOUBLE :
2018-05-08 08:25:12 +03:00
le + = sprintf ( le , " %g " , arg . doublep [ 0 ] ) ;
break ;
case POPT_ARG_MAINCALL :
le + = sprintf ( le , " %p " , opt - > arg ) ;
break ;
case POPT_ARG_ARGV :
le + = sprintf ( le , " %p " , opt - > arg ) ;
break ;
2014-07-23 11:17:30 +04:00
case POPT_ARG_STRING :
2018-05-08 08:25:12 +03:00
{ const char * s = arg . argv [ 0 ] ;
if ( s = = NULL )
le = stpcpy ( le , " null " ) ;
else {
size_t limit = 4 * lineLength - ( le - l ) - sizeof ( " \" \" ) " ) ;
size_t slen ;
2014-07-23 11:17:30 +04:00
* le + + = ' " ' ;
2018-05-08 08:25:12 +03:00
strncpy ( le , s , limit ) ; le [ limit ] = ' \0 ' ; le + = ( slen = strlen ( le ) ) ;
if ( slen = = limit & & s [ limit ] )
le [ - 1 ] = le [ - 2 ] = le [ - 3 ] = ' . ' ;
2014-07-23 11:17:30 +04:00
* le + + = ' " ' ;
}
} break ;
case POPT_ARG_NONE :
default :
2018-05-08 08:25:12 +03:00
l = _free ( l ) ;
2014-07-23 11:17:30 +04:00
return NULL ;
/*@notreached@*/ break ;
}
2018-05-08 08:25:12 +03:00
}
2014-07-23 11:17:30 +04:00
* le + + = ' ) ' ;
* le = ' \0 ' ;
return l ;
}
/**
* Display help text for an option .
* @ param fp output file handle
2018-05-08 08:25:12 +03:00
* @ param columns output display width control
2014-07-23 11:17:30 +04:00
* @ param opt option ( s )
* @ param translation_domain translation domain
*/
2018-05-08 08:25:12 +03:00
static void singleOptionHelp ( FILE * fp , columns_t columns ,
2014-07-23 11:17:30 +04:00
const struct poptOption * opt ,
/*@null@*/ const char * translation_domain )
/*@globals fileSystem @*/
2018-05-08 08:25:12 +03:00
/*@modifies fp, fileSystem @*/
2014-07-23 11:17:30 +04:00
{
2018-05-08 08:25:12 +03:00
size_t maxLeftCol = columns - > cur ;
size_t indentLength = maxLeftCol + 5 ;
size_t lineLength = columns - > max - indentLength ;
2014-07-23 11:17:30 +04:00
const char * help = D_ ( translation_domain , opt - > descrip ) ;
const char * argDescrip = getArgDescrip ( opt , translation_domain ) ;
2018-05-08 08:25:12 +03:00
/* Display shortName iff printable non-space. */
int prtshort = ( int ) ( isprint ( ( int ) opt - > shortName ) & & opt - > shortName ! = ' ' ) ;
size_t helpLength ;
2014-07-23 11:17:30 +04:00
char * defs = NULL ;
char * left ;
2018-05-08 08:25:12 +03:00
size_t nb = maxLeftCol + 1 ;
int displaypad = 0 ;
int xx ;
2014-07-23 11:17:30 +04:00
/* Make sure there's more than enough room in target buffer. */
if ( opt - > longName ) nb + = strlen ( opt - > longName ) ;
2018-05-08 08:25:12 +03:00
if ( F_ISSET ( opt , TOGGLE ) ) nb + = sizeof ( " [no] " ) - 1 ;
2014-07-23 11:17:30 +04:00
if ( argDescrip ) nb + = strlen ( argDescrip ) ;
2018-05-08 08:25:12 +03:00
left = malloc ( nb ) ;
2014-07-23 11:17:30 +04:00
if ( left = = NULL ) return ; /* XXX can't happen */
left [ 0 ] = ' \0 ' ;
left [ maxLeftCol ] = ' \0 ' ;
2018-05-08 08:25:12 +03:00
# define prtlong (opt->longName != NULL) /* XXX splint needs a clue */
if ( ! ( prtshort | | prtlong ) )
goto out ;
if ( prtshort & & prtlong ) {
char * dash = F_ISSET ( opt , ONEDASH ) ? " - " : " -- " ;
left [ 0 ] = ' - ' ;
left [ 1 ] = opt - > shortName ;
( void ) stpcpy ( stpcpy ( stpcpy ( left + 2 , " , " ) , dash ) , opt - > longName ) ;
} else if ( prtshort ) {
left [ 0 ] = ' - ' ;
left [ 1 ] = opt - > shortName ;
left [ 2 ] = ' \0 ' ;
} else if ( prtlong ) {
/* XXX --long always padded for alignment with/without "-X, ". */
char * dash = poptArgType ( opt ) = = POPT_ARG_MAINCALL ? " "
: ( F_ISSET ( opt , ONEDASH ) ? " - " : " -- " ) ;
const char * longName = opt - > longName ;
const char * toggle ;
if ( F_ISSET ( opt , TOGGLE ) ) {
toggle = " [no] " ;
if ( longName [ 0 ] = = ' n ' & & longName [ 1 ] = = ' o ' ) {
longName + = sizeof ( " no " ) - 1 ;
if ( longName [ 0 ] = = ' - ' )
longName + + ;
}
} else
toggle = " " ;
( void ) stpcpy ( stpcpy ( stpcpy ( stpcpy ( left , " " ) , dash ) , toggle ) , longName ) ;
}
# undef prtlong
2014-07-23 11:17:30 +04:00
if ( argDescrip ) {
char * le = left + strlen ( left ) ;
2018-05-08 08:25:12 +03:00
if ( F_ISSET ( opt , OPTIONAL ) )
2014-07-23 11:17:30 +04:00
* le + + = ' [ ' ;
/* Choose type of output */
2018-05-08 08:25:12 +03:00
if ( F_ISSET ( opt , SHOW_DEFAULT ) ) {
defs = singleOptionDefaultValue ( lineLength , opt , translation_domain ) ;
if ( defs ) {
char * t = malloc ( ( help ? strlen ( help ) : 0 ) +
2014-07-23 11:17:30 +04:00
strlen ( defs ) + sizeof ( " " ) ) ;
2018-05-08 08:25:12 +03:00
if ( t ) {
char * te = t ;
if ( help )
te = stpcpy ( te , help ) ;
* te + + = ' ' ;
strcpy ( te , defs ) ;
defs = _free ( defs ) ;
defs = t ;
2014-07-23 11:17:30 +04:00
}
2018-05-08 08:25:12 +03:00
}
2014-07-23 11:17:30 +04:00
}
if ( opt - > argDescrip = = NULL ) {
2018-05-08 08:25:12 +03:00
switch ( poptArgType ( opt ) ) {
2014-07-23 11:17:30 +04:00
case POPT_ARG_NONE :
break ;
case POPT_ARG_VAL :
# ifdef NOTNOW /* XXX pug ugly nerdy output */
{ long aLong = opt - > val ;
2018-05-08 08:25:12 +03:00
int ops = F_ISSET ( opt , LOGICALOPS ) ;
int negate = F_ISSET ( opt , NOT ) ;
2014-07-23 11:17:30 +04:00
/* Don't bother displaying typical values */
if ( ! ops & & ( aLong = = 0L | | aLong = = 1L | | aLong = = - 1L ) )
break ;
* le + + = ' [ ' ;
switch ( ops ) {
case POPT_ARGFLAG_OR :
* le + + = ' | ' ;
/*@innerbreak@*/ break ;
case POPT_ARGFLAG_AND :
* le + + = ' & ' ;
/*@innerbreak@*/ break ;
case POPT_ARGFLAG_XOR :
* le + + = ' ^ ' ;
/*@innerbreak@*/ break ;
default :
/*@innerbreak@*/ break ;
}
2018-05-08 08:25:12 +03:00
* le + + = ( opt - > longName ! = NULL ? ' = ' : ' ' ) ;
2014-07-23 11:17:30 +04:00
if ( negate ) * le + + = ' ~ ' ;
/*@-formatconst@*/
le + = sprintf ( le , ( ops ? " 0x%lx " : " %ld " ) , aLong ) ;
/*@=formatconst@*/
* le + + = ' ] ' ;
}
# endif
break ;
case POPT_ARG_INT :
2018-05-08 08:25:12 +03:00
case POPT_ARG_SHORT :
2014-07-23 11:17:30 +04:00
case POPT_ARG_LONG :
2018-05-08 08:25:12 +03:00
case POPT_ARG_LONGLONG :
2014-07-23 11:17:30 +04:00
case POPT_ARG_FLOAT :
case POPT_ARG_DOUBLE :
case POPT_ARG_STRING :
2018-05-08 08:25:12 +03:00
* le + + = ( opt - > longName ! = NULL ? ' = ' : ' ' ) ;
le = stpcpy ( le , argDescrip ) ;
2014-07-23 11:17:30 +04:00
break ;
default :
break ;
}
} else {
2018-05-08 08:25:12 +03:00
char * leo ;
/* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
if ( ! strchr ( " =( " , argDescrip [ 0 ] ) )
* le + + = ( ( poptArgType ( opt ) = = POPT_ARG_MAINCALL ) ? ' ' :
( poptArgType ( opt ) = = POPT_ARG_ARGV ) ? ' ' : ' = ' ) ;
le = stpcpy ( leo = le , argDescrip ) ;
/* Adjust for (possible) wide characters. */
displaypad = ( int ) ( ( le - leo ) - stringDisplayWidth ( argDescrip ) ) ;
2014-07-23 11:17:30 +04:00
}
2018-05-08 08:25:12 +03:00
if ( F_ISSET ( opt , OPTIONAL ) )
2014-07-23 11:17:30 +04:00
* le + + = ' ] ' ;
* le = ' \0 ' ;
}
if ( help )
2018-05-08 08:25:12 +03:00
xx = POPT_fprintf ( fp , " %-*s " , ( int ) ( maxLeftCol + displaypad ) , left ) ;
2014-07-23 11:17:30 +04:00
else {
2018-05-08 08:25:12 +03:00
xx = POPT_fprintf ( fp , " %s \n " , left ) ;
2014-07-23 11:17:30 +04:00
goto out ;
}
2018-05-08 08:25:12 +03:00
left = _free ( left ) ;
if ( defs )
2014-07-23 11:17:30 +04:00
help = defs ;
helpLength = strlen ( help ) ;
while ( helpLength > lineLength ) {
const char * ch ;
char format [ 16 ] ;
ch = help + lineLength - 1 ;
2018-05-08 08:25:12 +03:00
while ( ch > help & & ! _isspaceptr ( ch ) )
ch = POPT_prev_char ( ch ) ;
2014-07-23 11:17:30 +04:00
if ( ch = = help ) break ; /* give up */
2018-05-08 08:25:12 +03:00
while ( ch > ( help + 1 ) & & _isspaceptr ( ch ) )
ch = POPT_prev_char ( ch ) ;
ch = POPT_next_char ( ch ) ;
/*
* XXX strdup is necessary to add NUL terminator so that an unknown
* no . of ( possible ) multi - byte characters can be displayed .
*/
{ char * fmthelp = xstrdup ( help ) ;
if ( fmthelp ) {
fmthelp [ ch - help ] = ' \0 ' ;
sprintf ( format , " %%s \n %%%ds " , ( int ) indentLength ) ;
/*@-formatconst@*/
xx = POPT_fprintf ( fp , format , fmthelp , " " ) ;
/*@=formatconst@*/
free ( fmthelp ) ;
}
}
2014-07-23 11:17:30 +04:00
help = ch ;
2018-05-08 08:25:12 +03:00
while ( _isspaceptr ( help ) & & * help )
help = POPT_next_char ( help ) ;
2014-07-23 11:17:30 +04:00
helpLength = strlen ( help ) ;
}
if ( helpLength ) fprintf ( fp , " %s \n " , help ) ;
2018-05-08 08:25:12 +03:00
help = NULL ;
2014-07-23 11:17:30 +04:00
out :
/*@-dependenttrans@*/
2018-05-08 08:25:12 +03:00
defs = _free ( defs ) ;
2014-07-23 11:17:30 +04:00
/*@=dependenttrans@*/
2018-05-08 08:25:12 +03:00
left = _free ( left ) ;
2014-07-23 11:17:30 +04:00
}
/**
2018-05-08 08:25:12 +03:00
* Find display width for longest argument string .
2014-07-23 11:17:30 +04:00
* @ param opt option ( s )
* @ param translation_domain translation domain
2018-05-08 08:25:12 +03:00
* @ return display width
2014-07-23 11:17:30 +04:00
*/
2018-05-08 08:25:12 +03:00
static size_t maxArgWidth ( const struct poptOption * opt ,
2014-07-23 11:17:30 +04:00
/*@null@*/ const char * translation_domain )
/*@*/
{
2018-05-08 08:25:12 +03:00
size_t max = 0 ;
size_t len = 0 ;
const char * argDescrip ;
2014-07-23 11:17:30 +04:00
if ( opt ! = NULL )
while ( opt - > longName | | opt - > shortName | | opt - > arg ) {
2018-05-08 08:25:12 +03:00
if ( poptArgType ( opt ) = = POPT_ARG_INCLUDE_TABLE ) {
2014-07-23 11:17:30 +04:00
if ( opt - > arg ) /* XXX program error */
2018-05-08 08:25:12 +03:00
len = maxArgWidth ( opt - > arg , translation_domain ) ;
2014-07-23 11:17:30 +04:00
if ( len > max ) max = len ;
2018-05-08 08:25:12 +03:00
} else if ( ! F_ISSET ( opt , DOC_HIDDEN ) ) {
2014-07-23 11:17:30 +04:00
len = sizeof ( " " ) - 1 ;
2018-05-08 08:25:12 +03:00
/* XXX --long always padded for alignment with/without "-X, ". */
len + = sizeof ( " -X, " ) - 1 ;
2014-07-23 11:17:30 +04:00
if ( opt - > longName ) {
2018-05-08 08:25:12 +03:00
len + = ( F_ISSET ( opt , ONEDASH ) ? sizeof ( " - " ) : sizeof ( " -- " ) ) - 1 ;
2014-07-23 11:17:30 +04:00
len + = strlen ( opt - > longName ) ;
}
2018-05-08 08:25:12 +03:00
argDescrip = getArgDescrip ( opt , translation_domain ) ;
if ( argDescrip ) {
/* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
if ( ! strchr ( " =( " , argDescrip [ 0 ] ) ) len + = sizeof ( " = " ) - 1 ;
/* Adjust for (possible) wide characters. */
len + = stringDisplayWidth ( argDescrip ) ;
}
if ( F_ISSET ( opt , OPTIONAL ) ) len + = sizeof ( " [] " ) - 1 ;
2014-07-23 11:17:30 +04:00
if ( len > max ) max = len ;
}
opt + + ;
}
return max ;
}
/**
* Display popt alias and exec help .
* @ param fp output file handle
* @ param items alias / exec array
* @ param nitems no . of alias / exec entries
2018-05-08 08:25:12 +03:00
* @ param columns output display width control
2014-07-23 11:17:30 +04:00
* @ param translation_domain translation domain
*/
static void itemHelp ( FILE * fp ,
2018-05-08 08:25:12 +03:00
/*@null@*/ poptItem items , int nitems ,
columns_t columns ,
2014-07-23 11:17:30 +04:00
/*@null@*/ const char * translation_domain )
/*@globals fileSystem @*/
2018-05-08 08:25:12 +03:00
/*@modifies fp, fileSystem @*/
2014-07-23 11:17:30 +04:00
{
poptItem item ;
int i ;
if ( items ! = NULL )
for ( i = 0 , item = items ; i < nitems ; i + + , item + + ) {
const struct poptOption * opt ;
opt = & item - > option ;
2018-05-08 08:25:12 +03:00
if ( ( opt - > longName | | opt - > shortName ) & & ! F_ISSET ( opt , DOC_HIDDEN ) )
singleOptionHelp ( fp , columns , opt , translation_domain ) ;
2014-07-23 11:17:30 +04:00
}
}
/**
* Display help text for a table of options .
* @ param con context
* @ param fp output file handle
* @ param table option ( s )
2018-05-08 08:25:12 +03:00
* @ param columns output display width control
2014-07-23 11:17:30 +04:00
* @ param translation_domain translation domain
*/
static void singleTableHelp ( poptContext con , FILE * fp ,
2018-05-08 08:25:12 +03:00
/*@null@*/ const struct poptOption * table ,
columns_t columns ,
2014-07-23 11:17:30 +04:00
/*@null@*/ const char * translation_domain )
/*@globals fileSystem @*/
2018-05-08 08:25:12 +03:00
/*@modifies fp, columns->cur, fileSystem @*/
2014-07-23 11:17:30 +04:00
{
const struct poptOption * opt ;
const char * sub_transdom ;
2018-05-08 08:25:12 +03:00
int xx ;
2014-07-23 11:17:30 +04:00
if ( table = = poptAliasOptions ) {
2018-05-08 08:25:12 +03:00
itemHelp ( fp , con - > aliases , con - > numAliases , columns , NULL ) ;
itemHelp ( fp , con - > execs , con - > numExecs , columns , NULL ) ;
2014-07-23 11:17:30 +04:00
return ;
}
if ( table ! = NULL )
2018-05-08 08:25:12 +03:00
for ( opt = table ; opt - > longName | | opt - > shortName | | opt - > arg ; opt + + ) {
if ( ( opt - > longName | | opt - > shortName ) & & ! F_ISSET ( opt , DOC_HIDDEN ) )
singleOptionHelp ( fp , columns , opt , translation_domain ) ;
2014-07-23 11:17:30 +04:00
}
if ( table ! = NULL )
2018-05-08 08:25:12 +03:00
for ( opt = table ; opt - > longName | | opt - > shortName | | opt - > arg ; opt + + ) {
if ( poptArgType ( opt ) ! = POPT_ARG_INCLUDE_TABLE )
2014-07-23 11:17:30 +04:00
continue ;
2018-05-08 08:25:12 +03:00
sub_transdom = getTableTranslationDomain ( opt - > arg ) ;
2014-07-23 11:17:30 +04:00
if ( sub_transdom = = NULL )
sub_transdom = translation_domain ;
2018-05-08 08:25:12 +03:00
/* If no popt aliases/execs, skip poptAliasOption processing. */
if ( opt - > arg = = poptAliasOptions & & ! ( con - > numAliases | | con - > numExecs ) )
continue ;
2014-07-23 11:17:30 +04:00
if ( opt - > descrip )
2018-05-08 08:25:12 +03:00
xx = POPT_fprintf ( fp , " \n %s \n " , D_ ( sub_transdom , opt - > descrip ) ) ;
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
singleTableHelp ( con , fp , opt - > arg , columns , sub_transdom ) ;
2014-07-23 11:17:30 +04:00
}
}
/**
* @ param con context
* @ param fp output file handle
*/
2018-05-08 08:25:12 +03:00
static size_t showHelpIntro ( poptContext con , FILE * fp )
2014-07-23 11:17:30 +04:00
/*@globals fileSystem @*/
2018-05-08 08:25:12 +03:00
/*@modifies fp, fileSystem @*/
2014-07-23 11:17:30 +04:00
{
2018-05-08 08:25:12 +03:00
size_t len = ( size_t ) 6 ;
int xx ;
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
xx = POPT_fprintf ( fp , POPT_ ( " Usage: " ) ) ;
2014-07-23 11:17:30 +04:00
if ( ! ( con - > flags & POPT_CONTEXT_KEEP_FIRST ) ) {
2018-05-08 08:25:12 +03:00
struct optionStackEntry * os = con - > optionStack ;
const char * fn = ( os - > argv ? os - > argv [ 0 ] : NULL ) ;
2014-07-23 11:17:30 +04:00
if ( fn = = NULL ) return len ;
if ( strchr ( fn , ' / ' ) ) fn = strrchr ( fn , ' / ' ) + 1 ;
2018-05-08 08:25:12 +03:00
/* XXX POPT_fprintf not needed for argv[0] display. */
2014-07-23 11:17:30 +04:00
fprintf ( fp , " %s " , fn ) ;
len + = strlen ( fn ) + 1 ;
}
return len ;
}
2018-05-08 08:25:12 +03:00
void poptPrintHelp ( poptContext con , FILE * fp , /*@unused@*/ UNUSED ( int flags ) )
2014-07-23 11:17:30 +04:00
{
2018-05-08 08:25:12 +03:00
columns_t columns = calloc ( ( size_t ) 1 , sizeof ( * columns ) ) ;
int xx ;
2014-07-23 11:17:30 +04:00
( void ) showHelpIntro ( con , fp ) ;
if ( con - > otherHelp )
2018-05-08 08:25:12 +03:00
xx = POPT_fprintf ( fp , " %s \n " , con - > otherHelp ) ;
2014-07-23 11:17:30 +04:00
else
2018-05-08 08:25:12 +03:00
xx = POPT_fprintf ( fp , " %s \n " , POPT_ ( " [OPTION...] " ) ) ;
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
if ( columns ) {
columns - > cur = maxArgWidth ( con - > options , NULL ) ;
columns - > max = maxColumnWidth ( fp ) ;
singleTableHelp ( con , fp , con - > options , columns , NULL ) ;
free ( columns ) ;
}
2014-07-23 11:17:30 +04:00
}
/**
2018-05-08 08:25:12 +03:00
* Display usage text for an option .
2014-07-23 11:17:30 +04:00
* @ param fp output file handle
2018-05-08 08:25:12 +03:00
* @ param columns output display width control
2014-07-23 11:17:30 +04:00
* @ param opt option ( s )
* @ param translation_domain translation domain
*/
2018-05-08 08:25:12 +03:00
static size_t singleOptionUsage ( FILE * fp , columns_t columns ,
2014-07-23 11:17:30 +04:00
const struct poptOption * opt ,
/*@null@*/ const char * translation_domain )
/*@globals fileSystem @*/
2018-05-08 08:25:12 +03:00
/*@modifies fp, columns->cur, fileSystem @*/
2014-07-23 11:17:30 +04:00
{
2018-05-08 08:25:12 +03:00
size_t len = sizeof ( " [] " ) - 1 ;
2014-07-23 11:17:30 +04:00
const char * argDescrip = getArgDescrip ( opt , translation_domain ) ;
2018-05-08 08:25:12 +03:00
/* Display shortName iff printable non-space. */
int prtshort = ( int ) ( isprint ( ( int ) opt - > shortName ) & & opt - > shortName ! = ' ' ) ;
# define prtlong (opt->longName != NULL) /* XXX splint needs a clue */
if ( ! ( prtshort | | prtlong ) )
return columns - > cur ;
len = sizeof ( " [] " ) - 1 ;
if ( prtshort )
len + = sizeof ( " -c " ) - 1 ;
if ( prtlong ) {
if ( prtshort ) len + = sizeof ( " | " ) - 1 ;
len + = ( F_ISSET ( opt , ONEDASH ) ? sizeof ( " - " ) : sizeof ( " -- " ) ) - 1 ;
2014-07-23 11:17:30 +04:00
len + = strlen ( opt - > longName ) ;
}
2018-05-08 08:25:12 +03:00
if ( argDescrip ) {
/* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
if ( ! strchr ( " =( " , argDescrip [ 0 ] ) ) len + = sizeof ( " = " ) - 1 ;
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
/* Adjust for (possible) wide characters. */
len + = stringDisplayWidth ( argDescrip ) ;
}
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
if ( ( columns - > cur + len ) > columns - > max ) {
2014-07-23 11:17:30 +04:00
fprintf ( fp , " \n " ) ;
2018-05-08 08:25:12 +03:00
columns - > cur = ( size_t ) 7 ;
2014-07-23 11:17:30 +04:00
}
2018-05-08 08:25:12 +03:00
fprintf ( fp , " [ " ) ;
if ( prtshort )
fprintf ( fp , " -%c " , opt - > shortName ) ;
if ( prtlong )
fprintf ( fp , " %s%s%s " ,
( prtshort ? " | " : " " ) ,
( F_ISSET ( opt , ONEDASH ) ? " - " : " -- " ) ,
opt - > longName ) ;
# undef prtlong
if ( argDescrip ) {
/* XXX argDescrip[0] determines "--foo=bar" or "--foo bar". */
if ( ! strchr ( " =( " , argDescrip [ 0 ] ) ) fprintf ( fp , " = " ) ;
fprintf ( fp , " %s " , argDescrip ) ;
2014-07-23 11:17:30 +04:00
}
2018-05-08 08:25:12 +03:00
fprintf ( fp , " ] " ) ;
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
return columns - > cur + len + 1 ;
2014-07-23 11:17:30 +04:00
}
/**
* Display popt alias and exec usage .
* @ param fp output file handle
2018-05-08 08:25:12 +03:00
* @ param columns output display width control
2014-07-23 11:17:30 +04:00
* @ param item alias / exec array
* @ param nitems no . of ara / exec entries
* @ param translation_domain translation domain
*/
2018-05-08 08:25:12 +03:00
static size_t itemUsage ( FILE * fp , columns_t columns ,
/*@null@*/ poptItem item , int nitems ,
2014-07-23 11:17:30 +04:00
/*@null@*/ const char * translation_domain )
/*@globals fileSystem @*/
2018-05-08 08:25:12 +03:00
/*@modifies fp, columns->cur, fileSystem @*/
2014-07-23 11:17:30 +04:00
{
int i ;
if ( item ! = NULL )
for ( i = 0 ; i < nitems ; i + + , item + + ) {
const struct poptOption * opt ;
opt = & item - > option ;
2018-05-08 08:25:12 +03:00
if ( poptArgType ( opt ) = = POPT_ARG_INTL_DOMAIN ) {
2014-07-23 11:17:30 +04:00
translation_domain = ( const char * ) opt - > arg ;
2018-05-08 08:25:12 +03:00
} else
if ( ( opt - > longName | | opt - > shortName ) & & ! F_ISSET ( opt , DOC_HIDDEN ) ) {
columns - > cur = singleOptionUsage ( fp , columns , opt , translation_domain ) ;
2014-07-23 11:17:30 +04:00
}
}
2018-05-08 08:25:12 +03:00
return columns - > cur ;
2014-07-23 11:17:30 +04:00
}
/**
* Keep track of option tables already processed .
*/
typedef struct poptDone_s {
int nopts ;
int maxopts ;
2018-05-08 08:25:12 +03:00
/*@null@*/
2014-07-23 11:17:30 +04:00
const void * * opts ;
} * poptDone ;
/**
* Display usage text for a table of options .
* @ param con context
* @ param fp output file handle
2018-05-08 08:25:12 +03:00
* @ param columns output display width control
2014-07-23 11:17:30 +04:00
* @ param opt option ( s )
* @ param translation_domain translation domain
* @ param done tables already processed
* @ return
*/
2018-05-08 08:25:12 +03:00
static size_t singleTableUsage ( poptContext con , FILE * fp , columns_t columns ,
2014-07-23 11:17:30 +04:00
/*@null@*/ const struct poptOption * opt ,
/*@null@*/ const char * translation_domain ,
/*@null@*/ poptDone done )
/*@globals fileSystem @*/
2018-05-08 08:25:12 +03:00
/*@modifies fp, columns->cur, done, fileSystem @*/
2014-07-23 11:17:30 +04:00
{
if ( opt ! = NULL )
for ( ; ( opt - > longName | | opt - > shortName | | opt - > arg ) ; opt + + ) {
2018-05-08 08:25:12 +03:00
if ( poptArgType ( opt ) = = POPT_ARG_INTL_DOMAIN ) {
2014-07-23 11:17:30 +04:00
translation_domain = ( const char * ) opt - > arg ;
2018-05-08 08:25:12 +03:00
} else
if ( poptArgType ( opt ) = = POPT_ARG_INCLUDE_TABLE ) {
2014-07-23 11:17:30 +04:00
if ( done ) {
int i = 0 ;
2018-05-08 08:25:12 +03:00
if ( done - > opts ! = NULL )
2014-07-23 11:17:30 +04:00
for ( i = 0 ; i < done - > nopts ; i + + ) {
const void * that = done - > opts [ i ] ;
if ( that = = NULL | | that ! = opt - > arg )
/*@innercontinue@*/ continue ;
/*@innerbreak@*/ break ;
}
/* Skip if this table has already been processed. */
if ( opt - > arg = = NULL | | i < done - > nopts )
continue ;
2018-05-08 08:25:12 +03:00
if ( done - > opts ! = NULL & & done - > nopts < done - > maxopts )
2014-07-23 11:17:30 +04:00
done - > opts [ done - > nopts + + ] = ( const void * ) opt - > arg ;
}
2018-05-08 08:25:12 +03:00
columns - > cur = singleTableUsage ( con , fp , columns , opt - > arg ,
2014-07-23 11:17:30 +04:00
translation_domain , done ) ;
2018-05-08 08:25:12 +03:00
} else
if ( ( opt - > longName | | opt - > shortName ) & & ! F_ISSET ( opt , DOC_HIDDEN ) ) {
columns - > cur = singleOptionUsage ( fp , columns , opt , translation_domain ) ;
2014-07-23 11:17:30 +04:00
}
}
2018-05-08 08:25:12 +03:00
return columns - > cur ;
2014-07-23 11:17:30 +04:00
}
/**
* Return concatenated 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
*/
2018-05-08 08:25:12 +03:00
static size_t showShortOptions ( const struct poptOption * opt , FILE * fp ,
2014-07-23 11:17:30 +04:00
/*@null@*/ char * str )
/*@globals fileSystem @*/
2018-05-08 08:25:12 +03:00
/*@modifies str, *fp, fileSystem @*/
2014-07-23 11:17:30 +04:00
/*@requires maxRead(str) >= 0 @*/
{
2018-05-08 08:25:12 +03:00
/* bufsize larger then the ascii set, lazy allocation on top level call. */
size_t nb = ( size_t ) 300 ;
char * s = ( str ! = NULL ? str : calloc ( ( size_t ) 1 , nb ) ) ;
size_t len = ( size_t ) 0 ;
if ( s = = NULL )
return 0 ;
2014-07-23 11:17:30 +04:00
if ( opt ! = NULL )
for ( ; ( opt - > longName | | opt - > shortName | | opt - > arg ) ; opt + + ) {
2018-05-08 08:25:12 +03:00
if ( ! F_ISSET ( opt , DOC_HIDDEN ) & & opt - > shortName & & ! poptArgType ( opt ) )
{
/* Display shortName iff unique printable non-space. */
if ( ! strchr ( s , opt - > shortName ) & & isprint ( ( int ) opt - > shortName )
& & opt - > shortName ! = ' ' )
s [ strlen ( s ) ] = opt - > shortName ;
} else if ( poptArgType ( opt ) = = POPT_ARG_INCLUDE_TABLE )
2014-07-23 11:17:30 +04:00
if ( opt - > arg ) /* XXX program error */
2018-05-08 08:25:12 +03:00
len = showShortOptions ( opt - > arg , fp , s ) ;
2014-07-23 11:17:30 +04:00
}
/* On return to top level, print the short options, return print length. */
2018-05-08 08:25:12 +03:00
if ( s ! = str & & * s ! = ' \0 ' ) {
2014-07-23 11:17:30 +04:00
fprintf ( fp , " [-%s] " , s ) ;
len = strlen ( s ) + sizeof ( " [-] " ) - 1 ;
}
2018-05-08 08:25:12 +03:00
/*@-temptrans@*/ /* LCL: local s, not str arg, is being freed. */
if ( s ! = str )
free ( s ) ;
/*@=temptrans@*/
2014-07-23 11:17:30 +04:00
return len ;
}
2018-05-08 08:25:12 +03:00
void poptPrintUsage ( poptContext con , FILE * fp , /*@unused@*/ UNUSED ( int flags ) )
2014-07-23 11:17:30 +04:00
{
2018-05-08 08:25:12 +03:00
columns_t columns = calloc ( ( size_t ) 1 , sizeof ( * columns ) ) ;
struct poptDone_s done_buf ;
poptDone done = & done_buf ;
2014-07-23 11:17:30 +04:00
2018-05-08 08:25:12 +03:00
memset ( done , 0 , sizeof ( * done ) ) ;
2014-07-23 11:17:30 +04:00
done - > nopts = 0 ;
done - > maxopts = 64 ;
2018-05-08 08:25:12 +03:00
if ( columns ) {
columns - > cur = done - > maxopts * sizeof ( * done - > opts ) ;
columns - > max = maxColumnWidth ( fp ) ;
done - > opts = calloc ( ( size_t ) 1 , columns - > cur ) ;
/*@-keeptrans@*/
if ( done - > opts ! = NULL )
done - > opts [ done - > nopts + + ] = ( const void * ) con - > options ;
/*@=keeptrans@*/
columns - > cur = showHelpIntro ( con , fp ) ;
columns - > cur + = showShortOptions ( con - > options , fp , NULL ) ;
columns - > cur = singleTableUsage ( con , fp , columns , con - > options , NULL , done ) ;
columns - > cur = itemUsage ( fp , columns , con - > aliases , con - > numAliases , NULL ) ;
columns - > cur = itemUsage ( fp , columns , con - > execs , con - > numExecs , NULL ) ;
2014-07-23 11:17:30 +04:00
if ( con - > otherHelp ) {
2018-05-08 08:25:12 +03:00
columns - > cur + = strlen ( con - > otherHelp ) + 1 ;
if ( columns - > cur > columns - > max ) fprintf ( fp , " \n " ) ;
2014-07-23 11:17:30 +04:00
fprintf ( fp , " %s " , con - > otherHelp ) ;
}
fprintf ( fp , " \n " ) ;
2018-05-08 08:25:12 +03:00
if ( done - > opts ! = NULL )
free ( done - > opts ) ;
free ( columns ) ;
}
2014-07-23 11:17:30 +04:00
}
void poptSetOtherOptionHelp ( poptContext con , const char * text )
{
2018-05-08 08:25:12 +03:00
con - > otherHelp = _free ( con - > otherHelp ) ;
2014-07-23 11:17:30 +04:00
con - > otherHelp = xstrdup ( text ) ;
}