1181834Sroberto
2181834Sroberto/*
3181834Sroberto *  usage.c  $Id: usage.c,v 4.15 2007/04/28 22:19:23 bkorb Exp $
4181834Sroberto * Time-stamp:      "2007-04-15 11:02:46 bkorb"
5181834Sroberto *
6181834Sroberto *  This module implements the default usage procedure for
7181834Sroberto *  Automated Options.  It may be overridden, of course.
8181834Sroberto *
9181834Sroberto *  Sort options:
10181834Sroberto    --start=END-[S]TATIC-FORWARD --patt='^/\*($|[^:])' \
11181834Sroberto    --out=xx.c key='^[a-zA-Z0-9_]+\(' --trail='^/\*:' \
12181834Sroberto    --spac=2 --input=usage.c
13181834Sroberto */
14181834Sroberto
15181834Sroberto/*
16181834Sroberto *  Automated Options copyright 1992-2007 Bruce Korb
17181834Sroberto *
18181834Sroberto *  Automated Options is free software.
19181834Sroberto *  You may redistribute it and/or modify it under the terms of the
20181834Sroberto *  GNU General Public License, as published by the Free Software
21181834Sroberto *  Foundation; either version 2, or (at your option) any later version.
22181834Sroberto *
23181834Sroberto *  Automated Options is distributed in the hope that it will be useful,
24181834Sroberto *  but WITHOUT ANY WARRANTY; without even the implied warranty of
25181834Sroberto *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26181834Sroberto *  GNU General Public License for more details.
27181834Sroberto *
28181834Sroberto *  You should have received a copy of the GNU General Public License
29181834Sroberto *  along with Automated Options.  See the file "COPYING".  If not,
30181834Sroberto *  write to:  The Free Software Foundation, Inc.,
31181834Sroberto *             51 Franklin Street, Fifth Floor,
32181834Sroberto *             Boston, MA  02110-1301, USA.
33181834Sroberto *
34181834Sroberto * As a special exception, Bruce Korb gives permission for additional
35181834Sroberto * uses of the text contained in his release of AutoOpts.
36181834Sroberto *
37181834Sroberto * The exception is that, if you link the AutoOpts library with other
38181834Sroberto * files to produce an executable, this does not by itself cause the
39181834Sroberto * resulting executable to be covered by the GNU General Public License.
40181834Sroberto * Your use of that executable is in no way restricted on account of
41181834Sroberto * linking the AutoOpts library code into it.
42181834Sroberto *
43181834Sroberto * This exception does not however invalidate any other reasons why
44181834Sroberto * the executable file might be covered by the GNU General Public License.
45181834Sroberto *
46181834Sroberto * This exception applies only to the code released by Bruce Korb under
47181834Sroberto * the name AutoOpts.  If you copy code from other sources under the
48181834Sroberto * General Public License into a copy of AutoOpts, as the General Public
49181834Sroberto * License permits, the exception does not apply to the code that you add
50181834Sroberto * in this way.  To avoid misleading anyone as to the status of such
51181834Sroberto * modified files, you must delete this exception notice from them.
52181834Sroberto *
53181834Sroberto * If you write modifications of your own for AutoOpts, it is your choice
54181834Sroberto * whether to permit this exception to apply to your modifications.
55181834Sroberto * If you do not wish that, delete this exception notice.
56181834Sroberto */
57181834Sroberto
58181834Sroberto#define OPTPROC_L_N_S  (OPTPROC_LONGOPT | OPTPROC_SHORTOPT)
59181834Sroberto
60181834Srobertostatic arg_types_t argTypes;
61181834Sroberto
62181834SrobertoFILE* option_usage_fp = NULL;
63181834Srobertostatic char    zOptFmtLine[ 16 ];
64181834Srobertostatic ag_bool displayEnum;
65181834Sroberto
66181834Sroberto/* = = = START-STATIC-FORWARD = = = */
67181834Sroberto/* static forward declarations maintained by :mkfwd */
68181834Srobertostatic ag_bool
69181834SrobertocheckGNUUsage( tOptions* pOpts );
70181834Sroberto
71181834Srobertostatic void
72181834SrobertoprintExtendedUsage(
73181834Sroberto    tOptions*     pOptions,
74181834Sroberto    tOptDesc*     pOD,
75181834Sroberto    arg_types_t*  pAT );
76181834Sroberto
77181834Srobertostatic void
78181834SrobertoprintInitList(
79181834Sroberto    tCC* const* papz,
80181834Sroberto    ag_bool*    pInitIntro,
81181834Sroberto    tCC*        pzRc,
82181834Sroberto    tCC*        pzPN );
83181834Sroberto
84181834Srobertostatic void
85181834SrobertoprintOneUsage(
86181834Sroberto    tOptions*     pOptions,
87181834Sroberto    tOptDesc*     pOD,
88181834Sroberto    arg_types_t*  pAT );
89181834Sroberto
90181834Srobertostatic void
91181834SrobertoprintOptionUsage(
92181834Sroberto    tOptions* pOpts,
93181834Sroberto    int       ex_code,
94181834Sroberto    tCC*      pOptTitle );
95181834Sroberto
96181834Srobertostatic void
97181834SrobertoprintProgramDetails( tOptions* pOptions );
98181834Sroberto
99181834Srobertostatic int
100181834SrobertosetGnuOptFmts( tOptions* pOpts, tCC** ppT );
101181834Sroberto
102181834Srobertostatic int
103181834SrobertosetStdOptFmts( tOptions* pOpts, tCC** ppT );
104181834Sroberto/* = = = END-STATIC-FORWARD = = = */
105181834Sroberto
106181834Sroberto
107181834Sroberto/*
108181834Sroberto *  Figure out if we should try to format usage text sort-of like
109181834Sroberto *  the way many GNU programs do.
110181834Sroberto */
111181834Srobertostatic ag_bool
112181834SrobertocheckGNUUsage( tOptions* pOpts )
113181834Sroberto{
114181834Sroberto    char* pz = getenv( "AUTOOPTS_USAGE" );
115181834Sroberto    if (pz == NULL)
116181834Sroberto        ;
117181834Sroberto
118181834Sroberto    else if (streqvcmp( pz, "gnu" ) == 0)
119181834Sroberto        pOpts->fOptSet |= OPTPROC_GNUUSAGE;
120181834Sroberto
121181834Sroberto    else if (streqvcmp( pz, "autoopts" ) == 0)
122181834Sroberto        pOpts->fOptSet &= ~OPTPROC_GNUUSAGE;
123181834Sroberto
124181834Sroberto    return (pOpts->fOptSet & OPTPROC_GNUUSAGE) ? AG_TRUE : AG_FALSE;
125181834Sroberto}
126181834Sroberto
127181834Sroberto
128181834Sroberto/*=export_func  optionOnlyUsage
129181834Sroberto *
130181834Sroberto * what:  Print usage text for just the options
131181834Sroberto * arg:   + tOptions*   + pOpts    + program options descriptor +
132181834Sroberto * arg:   + int         + ex_code  + exit code for calling exit(3) +
133181834Sroberto *
134181834Sroberto * doc:
135181834Sroberto *  This routine will print only the usage for each option.
136181834Sroberto *  This function may be used when the emitted usage must incorporate
137181834Sroberto *  information not available to AutoOpts.
138181834Sroberto=*/
139181834Srobertovoid
140181834SrobertooptionOnlyUsage(
141181834Sroberto    tOptions* pOpts,
142181834Sroberto    int       ex_code )
143181834Sroberto{
144181834Sroberto    tCC* pOptTitle = NULL;
145181834Sroberto
146181834Sroberto    /*
147181834Sroberto     *  Determine which header and which option formatting strings to use
148181834Sroberto     */
149181834Sroberto    if (checkGNUUsage(pOpts)) {
150181834Sroberto        (void)setGnuOptFmts( pOpts, &pOptTitle );
151181834Sroberto    }
152181834Sroberto    else {
153181834Sroberto        (void)setStdOptFmts( pOpts, &pOptTitle );
154181834Sroberto    }
155181834Sroberto
156181834Sroberto    printOptionUsage( pOpts, ex_code, pOptTitle );
157181834Sroberto}
158181834Sroberto
159181834Sroberto
160181834Sroberto/*=export_func  optionUsage
161181834Sroberto * private:
162181834Sroberto *
163181834Sroberto * what:  Print usage text
164181834Sroberto * arg:   + tOptions* + pOptions + program options descriptor +
165181834Sroberto * arg:   + int       + exitCode + exit code for calling exit(3) +
166181834Sroberto *
167181834Sroberto * doc:
168181834Sroberto *  This routine will print usage in both GNU-standard and AutoOpts-expanded
169181834Sroberto *  formats.  The descriptor specifies the default, but AUTOOPTS_USAGE will
170181834Sroberto *  over-ride this, providing the value of it is set to either "gnu" or
171181834Sroberto *  "autoopts".  This routine will @strong{not} return.
172181834Sroberto *
173181834Sroberto *  If "exitCode" is "EX_USAGE" (normally 64), then output will to to stdout
174181834Sroberto *  and the actual exit code will be "EXIT_SUCCESS".
175181834Sroberto=*/
176181834Srobertovoid
177181834SrobertooptionUsage(
178181834Sroberto    tOptions* pOptions,
179181834Sroberto    int       usage_exit_code )
180181834Sroberto{
181181834Sroberto    int actual_exit_code =
182181834Sroberto        (usage_exit_code == EX_USAGE) ? EXIT_SUCCESS : usage_exit_code;
183181834Sroberto
184181834Sroberto    displayEnum = AG_FALSE;
185181834Sroberto
186181834Sroberto    /*
187181834Sroberto     *  Paged usage will preset option_usage_fp to an output file.
188181834Sroberto     *  If it hasn't already been set, then set it to standard output
189181834Sroberto     *  on successful exit (help was requested), otherwise error out.
190181834Sroberto     */
191181834Sroberto    if (option_usage_fp == NULL)
192181834Sroberto        option_usage_fp = (actual_exit_code != EXIT_SUCCESS) ? stderr : stdout;
193181834Sroberto
194181834Sroberto    fprintf( option_usage_fp, pOptions->pzUsageTitle, pOptions->pzProgName );
195181834Sroberto
196181834Sroberto    {
197181834Sroberto        tCC* pOptTitle = NULL;
198181834Sroberto
199181834Sroberto        /*
200181834Sroberto         *  Determine which header and which option formatting strings to use
201181834Sroberto         */
202181834Sroberto        if (checkGNUUsage(pOptions)) {
203181834Sroberto            int flen = setGnuOptFmts( pOptions, &pOptTitle );
204181834Sroberto            sprintf( zOptFmtLine, zFmtFmt, flen );
205181834Sroberto            fputc( '\n', option_usage_fp );
206181834Sroberto        }
207181834Sroberto        else {
208181834Sroberto            int flen = setStdOptFmts( pOptions, &pOptTitle );
209181834Sroberto            sprintf( zOptFmtLine, zFmtFmt, flen );
210181834Sroberto
211181834Sroberto            /*
212181834Sroberto             *  When we exit with EXIT_SUCCESS and the first option is a doc
213181834Sroberto             *  option, we do *NOT* want to emit the column headers.
214181834Sroberto             *  Otherwise, we do.
215181834Sroberto             */
216181834Sroberto            if (  (usage_exit_code != EXIT_SUCCESS)
217181834Sroberto               || ((pOptions->pOptDesc->fOptState & OPTST_DOCUMENT) == 0) )
218181834Sroberto
219181834Sroberto                fputs( pOptTitle, option_usage_fp );
220181834Sroberto        }
221181834Sroberto
222181834Sroberto        printOptionUsage( pOptions, usage_exit_code, pOptTitle );
223181834Sroberto    }
224181834Sroberto
225181834Sroberto    /*
226181834Sroberto     *  Describe the mechanics of denoting the options
227181834Sroberto     */
228181834Sroberto    switch (pOptions->fOptSet & OPTPROC_L_N_S) {
229181834Sroberto    case OPTPROC_L_N_S:     fputs( zFlagOkay, option_usage_fp ); break;
230181834Sroberto    case OPTPROC_SHORTOPT:  break;
231181834Sroberto    case OPTPROC_LONGOPT:   fputs( zNoFlags,  option_usage_fp ); break;
232181834Sroberto    case 0:                 fputs( zOptsOnly, option_usage_fp ); break;
233181834Sroberto    }
234181834Sroberto
235181834Sroberto    if ((pOptions->fOptSet & OPTPROC_NUM_OPT) != 0) {
236181834Sroberto        fputs( zNumberOpt, option_usage_fp );
237181834Sroberto    }
238181834Sroberto
239181834Sroberto    if ((pOptions->fOptSet & OPTPROC_REORDER) != 0) {
240181834Sroberto        fputs( zReorder, option_usage_fp );
241181834Sroberto    }
242181834Sroberto
243181834Sroberto    if (pOptions->pzExplain != NULL)
244181834Sroberto        fputs( pOptions->pzExplain, option_usage_fp );
245181834Sroberto
246181834Sroberto    /*
247181834Sroberto     *  IF the user is asking for help (thus exiting with SUCCESS),
248181834Sroberto     *  THEN see what additional information we can provide.
249181834Sroberto     */
250181834Sroberto    if (usage_exit_code == EXIT_SUCCESS)
251181834Sroberto        printProgramDetails( pOptions );
252181834Sroberto
253181834Sroberto    if (pOptions->pzBugAddr != NULL)
254181834Sroberto        fprintf( option_usage_fp, zPlsSendBugs, pOptions->pzBugAddr );
255181834Sroberto    fflush( option_usage_fp );
256181834Sroberto
257181834Sroberto    exit( actual_exit_code );
258181834Sroberto}
259181834Sroberto
260181834Sroberto
261181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
262181834Sroberto *
263181834Sroberto *   PER OPTION TYPE USAGE INFORMATION
264181834Sroberto */
265181834Srobertostatic void
266181834SrobertoprintExtendedUsage(
267181834Sroberto    tOptions*     pOptions,
268181834Sroberto    tOptDesc*     pOD,
269181834Sroberto    arg_types_t*  pAT )
270181834Sroberto{
271181834Sroberto    /*
272181834Sroberto     *  IF there are option conflicts or dependencies,
273181834Sroberto     *  THEN print them here.
274181834Sroberto     */
275181834Sroberto    if (  (pOD->pOptMust != NULL)
276181834Sroberto       || (pOD->pOptCant != NULL) ) {
277181834Sroberto
278181834Sroberto        fputs( zTabHyp, option_usage_fp );
279181834Sroberto
280181834Sroberto        /*
281181834Sroberto         *  DEPENDENCIES:
282181834Sroberto         */
283181834Sroberto        if (pOD->pOptMust != NULL) {
284181834Sroberto            const int* pOptNo = pOD->pOptMust;
285181834Sroberto
286181834Sroberto            fputs( zReqThese, option_usage_fp );
287181834Sroberto            for (;;) {
288181834Sroberto                fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[
289181834Sroberto                             *pOptNo ].pz_Name );
290181834Sroberto                if (*++pOptNo == NO_EQUIVALENT)
291181834Sroberto                    break;
292181834Sroberto            }
293181834Sroberto
294181834Sroberto            if (pOD->pOptCant != NULL)
295181834Sroberto                fputs( zTabHypAnd, option_usage_fp );
296181834Sroberto        }
297181834Sroberto
298181834Sroberto        /*
299181834Sroberto         *  CONFLICTS:
300181834Sroberto         */
301181834Sroberto        if (pOD->pOptCant != NULL) {
302181834Sroberto            const int* pOptNo = pOD->pOptCant;
303181834Sroberto
304181834Sroberto            fputs( zProhib, option_usage_fp );
305181834Sroberto            for (;;) {
306181834Sroberto                fprintf( option_usage_fp, zTabout, pOptions->pOptDesc[
307181834Sroberto                             *pOptNo ].pz_Name );
308181834Sroberto                if (*++pOptNo == NO_EQUIVALENT)
309181834Sroberto                    break;
310181834Sroberto            }
311181834Sroberto        }
312181834Sroberto    }
313181834Sroberto
314181834Sroberto    /*
315181834Sroberto     *  IF there is a disablement string
316181834Sroberto     *  THEN print the disablement info
317181834Sroberto     */
318181834Sroberto    if (pOD->pz_DisableName != NULL )
319181834Sroberto        fprintf( option_usage_fp, zDis, pOD->pz_DisableName );
320181834Sroberto
321181834Sroberto    /*
322181834Sroberto     *  IF the numeric option has a special callback,
323181834Sroberto     *  THEN call it, requesting the range or other special info
324181834Sroberto     */
325181834Sroberto    if (  (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC)
326181834Sroberto       && (pOD->pOptProc != NULL)
327181834Sroberto       && (pOD->pOptProc != optionNumericVal) ) {
328181834Sroberto        (*(pOD->pOptProc))( pOptions, NULL );
329181834Sroberto    }
330181834Sroberto
331181834Sroberto    /*
332181834Sroberto     *  IF the option defaults to being enabled,
333181834Sroberto     *  THEN print that out
334181834Sroberto     */
335181834Sroberto    if (pOD->fOptState & OPTST_INITENABLED)
336181834Sroberto        fputs( zEnab, option_usage_fp );
337181834Sroberto
338181834Sroberto    /*
339181834Sroberto     *  IF  the option is in an equivalence class
340181834Sroberto     *        AND not the designated lead
341181834Sroberto     *  THEN print equivalence and leave it at that.
342181834Sroberto     */
343181834Sroberto    if (  (pOD->optEquivIndex != NO_EQUIVALENT)
344181834Sroberto       && (pOD->optEquivIndex != pOD->optActualIndex )  )  {
345181834Sroberto        fprintf( option_usage_fp, zAlt,
346181834Sroberto                 pOptions->pOptDesc[ pOD->optEquivIndex ].pz_Name );
347181834Sroberto        return;
348181834Sroberto    }
349181834Sroberto
350181834Sroberto    /*
351181834Sroberto     *  IF this particular option can NOT be preset
352181834Sroberto     *    AND some form of presetting IS allowed,
353181834Sroberto     *    AND it is not an auto-managed option (e.g. --help, et al.)
354181834Sroberto     *  THEN advise that this option may not be preset.
355181834Sroberto     */
356181834Sroberto    if (  ((pOD->fOptState & OPTST_NO_INIT) != 0)
357181834Sroberto       && (  (pOptions->papzHomeList != NULL)
358181834Sroberto          || (pOptions->pzPROGNAME != NULL)
359181834Sroberto          )
360181834Sroberto       && (pOD->optIndex < pOptions->presetOptCt)
361181834Sroberto       )
362181834Sroberto
363181834Sroberto        fputs( zNoPreset, option_usage_fp );
364181834Sroberto
365181834Sroberto    /*
366181834Sroberto     *  Print the appearance requirements.
367181834Sroberto     */
368181834Sroberto    if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP)
369181834Sroberto        fputs( zMembers, option_usage_fp );
370181834Sroberto
371181834Sroberto    else switch (pOD->optMinCt) {
372181834Sroberto    case 1:
373181834Sroberto    case 0:
374181834Sroberto        switch (pOD->optMaxCt) {
375181834Sroberto        case 0:       fputs( zPreset, option_usage_fp ); break;
376181834Sroberto        case NOLIMIT: fputs( zNoLim, option_usage_fp );  break;
377181834Sroberto        case 1:       break;
378181834Sroberto            /*
379181834Sroberto             * IF the max is more than one but limited, print "UP TO" message
380181834Sroberto             */
381181834Sroberto        default:      fprintf( option_usage_fp, zUpTo, pOD->optMaxCt );  break;
382181834Sroberto        }
383181834Sroberto        break;
384181834Sroberto
385181834Sroberto    default:
386181834Sroberto        /*
387181834Sroberto         *  More than one is required.  Print the range.
388181834Sroberto         */
389181834Sroberto        fprintf( option_usage_fp, zMust, pOD->optMinCt, pOD->optMaxCt );
390181834Sroberto    }
391181834Sroberto
392181834Sroberto    if (  NAMED_OPTS( pOptions )
393181834Sroberto       && (pOptions->specOptIdx.default_opt == pOD->optIndex))
394181834Sroberto        fputs( zDefaultOpt, option_usage_fp );
395181834Sroberto}
396181834Sroberto
397181834Sroberto
398181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
399181834Sroberto *
400181834Sroberto *   Figure out where all the initialization files might live.
401181834Sroberto *   This requires translating some environment variables and
402181834Sroberto *   testing to see if a name is a directory or a file.  It's
403181834Sroberto *   squishy, but important to tell users how to find these files.
404181834Sroberto */
405181834Srobertostatic void
406181834SrobertoprintInitList(
407181834Sroberto    tCC* const* papz,
408181834Sroberto    ag_bool*    pInitIntro,
409181834Sroberto    tCC*        pzRc,
410181834Sroberto    tCC*        pzPN )
411181834Sroberto{
412181834Sroberto    char zPath[ AG_PATH_MAX+1 ];
413181834Sroberto
414181834Sroberto    if (papz == NULL)
415181834Sroberto        return;
416181834Sroberto
417181834Sroberto    fputs( zPresetIntro, option_usage_fp );
418181834Sroberto    *pInitIntro = AG_FALSE;
419181834Sroberto
420181834Sroberto    for (;;) {
421181834Sroberto        char const* pzPath = *(papz++);
422181834Sroberto
423181834Sroberto        if (pzPath == NULL)
424181834Sroberto            break;
425181834Sroberto
426181834Sroberto        if (optionMakePath(zPath, (int)sizeof( zPath ), pzPath, pzPN))
427181834Sroberto            pzPath = zPath;
428181834Sroberto
429181834Sroberto        /*
430181834Sroberto         *  Print the name of the "homerc" file.  If the "rcfile" name is
431181834Sroberto         *  not empty, we may or may not print that, too...
432181834Sroberto         */
433181834Sroberto        fprintf( option_usage_fp, zPathFmt, pzPath );
434181834Sroberto        if (*pzRc != NUL) {
435181834Sroberto            struct stat sb;
436181834Sroberto
437181834Sroberto            /*
438181834Sroberto             *  IF the "homerc" file is a directory,
439181834Sroberto             *  then append the "rcfile" name.
440181834Sroberto             */
441181834Sroberto            if (  (stat( pzPath, &sb ) == 0)
442181834Sroberto              &&  S_ISDIR( sb.st_mode ) ) {
443181834Sroberto                fputc( DIRCH, option_usage_fp );
444181834Sroberto                fputs( pzRc, option_usage_fp );
445181834Sroberto            }
446181834Sroberto        }
447181834Sroberto
448181834Sroberto        fputc( '\n', option_usage_fp );
449181834Sroberto    }
450181834Sroberto}
451181834Sroberto
452181834Sroberto
453181834Sroberto/*
454181834Sroberto *  Print the usage information for a single option.
455181834Sroberto */
456181834Srobertostatic void
457181834SrobertoprintOneUsage(
458181834Sroberto    tOptions*     pOptions,
459181834Sroberto    tOptDesc*     pOD,
460181834Sroberto    arg_types_t*  pAT )
461181834Sroberto{
462181834Sroberto    /*
463181834Sroberto     *  Flag prefix: IF no flags at all, then omit it.  If not printable
464181834Sroberto     *  (not allowed for this option), then blank, else print it.
465181834Sroberto     *  Follow it with a comma if we are doing GNU usage and long
466181834Sroberto     *  opts are to be printed too.
467181834Sroberto     */
468181834Sroberto    if ((pOptions->fOptSet & OPTPROC_SHORTOPT) == 0)
469181834Sroberto        fputs( pAT->pzSpc, option_usage_fp );
470181834Sroberto    else if (! isgraph( pOD->optValue)) {
471181834Sroberto        if (  (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
472181834Sroberto           == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
473181834Sroberto            fputc( ' ', option_usage_fp );
474181834Sroberto        fputs( pAT->pzNoF, option_usage_fp );
475181834Sroberto    } else {
476181834Sroberto        fprintf( option_usage_fp, "   -%c", pOD->optValue );
477181834Sroberto        if (  (pOptions->fOptSet & (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
478181834Sroberto           == (OPTPROC_GNUUSAGE|OPTPROC_LONGOPT))
479181834Sroberto            fputs( ", ", option_usage_fp );
480181834Sroberto    }
481181834Sroberto
482181834Sroberto    {
483181834Sroberto        char  z[ 80 ];
484181834Sroberto        tCC*  pzArgType;
485181834Sroberto        /*
486181834Sroberto         *  Determine the argument type string first on its usage, then,
487181834Sroberto         *  when the option argument is required, base the type string on the
488181834Sroberto         *  argument type.
489181834Sroberto         */
490181834Sroberto        if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NONE) {
491181834Sroberto            pzArgType = pAT->pzNo;
492181834Sroberto
493181834Sroberto        } else if (pOD->fOptState & OPTST_ARG_OPTIONAL) {
494181834Sroberto            pzArgType = pAT->pzOpt;
495181834Sroberto
496181834Sroberto        } else switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
497181834Sroberto        case OPARG_TYPE_ENUMERATION: pzArgType = pAT->pzKey;  break;
498181834Sroberto        case OPARG_TYPE_MEMBERSHIP:  pzArgType = pAT->pzKeyL; break;
499181834Sroberto        case OPARG_TYPE_BOOLEAN:     pzArgType = pAT->pzBool; break;
500181834Sroberto        case OPARG_TYPE_NUMERIC:     pzArgType = pAT->pzNum;  break;
501181834Sroberto        case OPARG_TYPE_HIERARCHY:   pzArgType = pAT->pzNest; break;
502181834Sroberto        case OPARG_TYPE_STRING:      pzArgType = pAT->pzStr;  break;
503181834Sroberto        default:                     goto bogus_desc;         break;
504181834Sroberto        }
505181834Sroberto
506181834Sroberto        snprintf( z, sizeof(z), pAT->pzOptFmt, pzArgType, pOD->pz_Name,
507181834Sroberto                  (pOD->optMinCt != 0) ? pAT->pzReq : pAT->pzOpt );
508181834Sroberto
509181834Sroberto        fprintf( option_usage_fp, zOptFmtLine, z, pOD->pzText );
510181834Sroberto
511181834Sroberto        switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
512181834Sroberto        case OPARG_TYPE_ENUMERATION:
513181834Sroberto        case OPARG_TYPE_MEMBERSHIP:
514181834Sroberto            displayEnum = (pOD->pOptProc != NULL) ? AG_TRUE : displayEnum;
515181834Sroberto        }
516181834Sroberto    }
517181834Sroberto    return;
518181834Sroberto
519181834Sroberto bogus_desc:
520181834Sroberto    fprintf( stderr, zInvalOptDesc, pOD->pz_Name );
521181834Sroberto    exit( EX_SOFTWARE );
522181834Sroberto}
523181834Sroberto
524181834Sroberto
525181834Sroberto/*
526181834Sroberto *  Print out the usage information for just the options.
527181834Sroberto */
528181834Srobertostatic void
529181834SrobertoprintOptionUsage(
530181834Sroberto    tOptions* pOpts,
531181834Sroberto    int       ex_code,
532181834Sroberto    tCC*      pOptTitle )
533181834Sroberto{
534181834Sroberto    int        ct     = pOpts->optCt;
535181834Sroberto    int        optNo  = 0;
536181834Sroberto    tOptDesc*  pOD    = pOpts->pOptDesc;
537181834Sroberto    int        docCt  = 0;
538181834Sroberto
539181834Sroberto    do  {
540181834Sroberto        if ((pOD->fOptState & OPTST_OMITTED) != 0)
541181834Sroberto            continue;
542181834Sroberto
543181834Sroberto        if ((pOD->fOptState & OPTST_DOCUMENT) != 0) {
544181834Sroberto            if (ex_code == EXIT_SUCCESS) {
545181834Sroberto                fprintf(option_usage_fp, argTypes.pzBrk, pOD->pzText,
546181834Sroberto                        pOptTitle);
547181834Sroberto                docCt++;
548181834Sroberto            }
549181834Sroberto
550181834Sroberto            continue;
551181834Sroberto        }
552181834Sroberto
553181834Sroberto        /*
554181834Sroberto         *  IF       this is the first auto-opt maintained option
555181834Sroberto         *    *AND*  we are doing a full help
556181834Sroberto         *    *AND*  there are documentation options
557181834Sroberto         *    *AND*  the last one was not a doc option,
558181834Sroberto         *  THEN document that the remaining options are not user opts
559181834Sroberto         */
560181834Sroberto        if (  (pOpts->presetOptCt == optNo)
561181834Sroberto              && (ex_code == EXIT_SUCCESS)
562181834Sroberto              && (docCt > 0)
563181834Sroberto              && ((pOD[-1].fOptState & OPTST_DOCUMENT) == 0) )
564181834Sroberto            fprintf( option_usage_fp, argTypes.pzBrk, zAuto, pOptTitle );
565181834Sroberto
566181834Sroberto        printOneUsage( pOpts, pOD, &argTypes );
567181834Sroberto
568181834Sroberto        /*
569181834Sroberto         *  IF we were invoked because of the --help option,
570181834Sroberto         *  THEN print all the extra info
571181834Sroberto         */
572181834Sroberto        if (ex_code == EXIT_SUCCESS)
573181834Sroberto            printExtendedUsage( pOpts, pOD, &argTypes );
574181834Sroberto
575181834Sroberto    }  while (pOD++, optNo++, (--ct > 0));
576181834Sroberto
577181834Sroberto    fputc( '\n', option_usage_fp );
578181834Sroberto}
579181834Sroberto
580181834Sroberto
581181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
582181834Sroberto *
583181834Sroberto *   PROGRAM DETAILS
584181834Sroberto */
585181834Srobertostatic void
586181834SrobertoprintProgramDetails( tOptions* pOptions )
587181834Sroberto{
588181834Sroberto    ag_bool  initIntro = AG_TRUE;
589181834Sroberto
590181834Sroberto    /*
591181834Sroberto     *  Display all the places we look for config files
592181834Sroberto     */
593181834Sroberto    printInitList( pOptions->papzHomeList, &initIntro,
594181834Sroberto                   pOptions->pzRcName, pOptions->pzProgPath );
595181834Sroberto
596181834Sroberto    /*
597181834Sroberto     *  Let the user know about environment variable settings
598181834Sroberto     */
599181834Sroberto    if ((pOptions->fOptSet & OPTPROC_ENVIRON) != 0) {
600181834Sroberto        if (initIntro)
601181834Sroberto            fputs( zPresetIntro, option_usage_fp );
602181834Sroberto
603181834Sroberto        fprintf( option_usage_fp, zExamineFmt, pOptions->pzPROGNAME );
604181834Sroberto    }
605181834Sroberto
606181834Sroberto    /*
607181834Sroberto     *  IF we found an enumeration,
608181834Sroberto     *  THEN hunt for it again.  Call the handler proc with a NULL
609181834Sroberto     *       option struct pointer.  That tells it to display the keywords.
610181834Sroberto     */
611181834Sroberto    if (displayEnum) {
612181834Sroberto        int        ct     = pOptions->optCt;
613181834Sroberto        int        optNo  = 0;
614181834Sroberto        tOptDesc*  pOD    = pOptions->pOptDesc;
615181834Sroberto
616181834Sroberto        fputc( '\n', option_usage_fp );
617181834Sroberto        fflush( option_usage_fp );
618181834Sroberto        do  {
619181834Sroberto            switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
620181834Sroberto            case OPARG_TYPE_ENUMERATION:
621181834Sroberto            case OPARG_TYPE_MEMBERSHIP:
622181834Sroberto                (*(pOD->pOptProc))( NULL, pOD );
623181834Sroberto            }
624181834Sroberto        }  while (pOD++, optNo++, (--ct > 0));
625181834Sroberto    }
626181834Sroberto
627181834Sroberto    /*
628181834Sroberto     *  If there is a detail string, now is the time for that.
629181834Sroberto     */
630181834Sroberto    if (pOptions->pzDetail != NULL)
631181834Sroberto        fputs( pOptions->pzDetail, option_usage_fp );
632181834Sroberto}
633181834Sroberto
634181834Sroberto
635181834Sroberto/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
636181834Sroberto *
637181834Sroberto *   OPTION LINE FORMATTING SETUP
638181834Sroberto *
639181834Sroberto *  The "OptFmt" formats receive three arguments:
640181834Sroberto *  1.  the type of the option's argument
641181834Sroberto *  2.  the long name of the option
642181834Sroberto *  3.  "YES" or "no ", depending on whether or not the option must appear
643181834Sroberto *      on the command line.
644181834Sroberto *  These formats are used immediately after the option flag (if used) has
645181834Sroberto *  been printed.
646181834Sroberto *
647181834Sroberto *  Set up the formatting for GNU-style output
648181834Sroberto */
649181834Srobertostatic int
650181834SrobertosetGnuOptFmts( tOptions* pOpts, tCC** ppT )
651181834Sroberto{
652181834Sroberto    int  flen = 22;
653181834Sroberto    *ppT = zNoRq_ShrtTtl;
654181834Sroberto
655181834Sroberto    argTypes.pzStr  = zGnuStrArg;
656181834Sroberto    argTypes.pzReq  = zOneSpace;
657181834Sroberto    argTypes.pzNum  = zGnuNumArg;
658181834Sroberto    argTypes.pzKey  = zGnuKeyArg;
659181834Sroberto    argTypes.pzKeyL = zGnuKeyLArg;
660181834Sroberto    argTypes.pzBool = zGnuBoolArg;
661181834Sroberto    argTypes.pzNest = zGnuNestArg;
662181834Sroberto    argTypes.pzOpt  = zGnuOptArg;
663181834Sroberto    argTypes.pzNo   = zOneSpace;
664181834Sroberto    argTypes.pzBrk  = zGnuBreak;
665181834Sroberto    argTypes.pzNoF  = zSixSpaces;
666181834Sroberto    argTypes.pzSpc  = zThreeSpaces;
667181834Sroberto
668181834Sroberto    switch (pOpts->fOptSet & OPTPROC_L_N_S) {
669181834Sroberto    case OPTPROC_L_N_S:    argTypes.pzOptFmt = zGnuOptFmt;     break;
670181834Sroberto    case OPTPROC_LONGOPT:  argTypes.pzOptFmt = zGnuOptFmt;     break;
671181834Sroberto    case 0:                argTypes.pzOptFmt = zGnuOptFmt + 2; break;
672181834Sroberto    case OPTPROC_SHORTOPT:
673181834Sroberto        argTypes.pzOptFmt = zShrtGnuOptFmt;
674181834Sroberto        zGnuStrArg[0] = zGnuNumArg[0] = zGnuKeyArg[0] = zGnuBoolArg[0] = ' ';
675181834Sroberto        argTypes.pzOpt = " [arg]";
676181834Sroberto        flen = 8;
677181834Sroberto        break;
678181834Sroberto    }
679181834Sroberto
680181834Sroberto    return flen;
681181834Sroberto}
682181834Sroberto
683181834Sroberto
684181834Sroberto/*
685181834Sroberto *  Standard (AutoOpts normal) option line formatting
686181834Sroberto */
687181834Srobertostatic int
688181834SrobertosetStdOptFmts( tOptions* pOpts, tCC** ppT )
689181834Sroberto{
690181834Sroberto    int  flen = 0;
691181834Sroberto
692181834Sroberto    argTypes.pzStr  = zStdStrArg;
693181834Sroberto    argTypes.pzReq  = zStdReqArg;
694181834Sroberto    argTypes.pzNum  = zStdNumArg;
695181834Sroberto    argTypes.pzKey  = zStdKeyArg;
696181834Sroberto    argTypes.pzKeyL = zStdKeyLArg;
697181834Sroberto    argTypes.pzBool = zStdBoolArg;
698181834Sroberto    argTypes.pzNest = zStdNestArg;
699181834Sroberto    argTypes.pzOpt  = zStdOptArg;
700181834Sroberto    argTypes.pzNo   = zStdNoArg;
701181834Sroberto    argTypes.pzBrk  = zStdBreak;
702181834Sroberto    argTypes.pzNoF  = zFiveSpaces;
703181834Sroberto    argTypes.pzSpc  = zTwoSpaces;
704181834Sroberto
705181834Sroberto    switch (pOpts->fOptSet & (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT)) {
706181834Sroberto    case (OPTPROC_NO_REQ_OPT | OPTPROC_SHORTOPT):
707181834Sroberto        *ppT = zNoRq_ShrtTtl;
708181834Sroberto        argTypes.pzOptFmt = zNrmOptFmt;
709181834Sroberto        flen = 19;
710181834Sroberto        break;
711181834Sroberto
712181834Sroberto    case OPTPROC_NO_REQ_OPT:
713181834Sroberto        *ppT = zNoRq_NoShrtTtl;
714181834Sroberto        argTypes.pzOptFmt = zNrmOptFmt;
715181834Sroberto        flen = 19;
716181834Sroberto        break;
717181834Sroberto
718181834Sroberto    case OPTPROC_SHORTOPT:
719181834Sroberto        *ppT = zReq_ShrtTtl;
720181834Sroberto        argTypes.pzOptFmt = zReqOptFmt;
721181834Sroberto        flen = 24;
722181834Sroberto        break;
723181834Sroberto
724181834Sroberto    case 0:
725181834Sroberto        *ppT = zReq_NoShrtTtl;
726181834Sroberto        argTypes.pzOptFmt = zReqOptFmt;
727181834Sroberto        flen = 24;
728181834Sroberto    }
729181834Sroberto
730181834Sroberto    return flen;
731181834Sroberto}
732181834Sroberto
733181834Sroberto
734181834Sroberto/*:
735181834Sroberto * Local Variables:
736181834Sroberto * mode: C
737181834Sroberto * c-file-style: "stroustrup"
738181834Sroberto * indent-tabs-mode: nil
739181834Sroberto * End:
740181834Sroberto * end of autoopts/usage.c */
741