xref: /freebsd/contrib/ntp/sntp/libopts/makeshell.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
1ea906c41SOllivier Robert 
22b15cb3dSCy Schubert /**
32b15cb3dSCy Schubert  * \file makeshell.c
4ea906c41SOllivier Robert  *
5ea906c41SOllivier Robert  *  This module will interpret the options set in the tOptions
6ea906c41SOllivier Robert  *  structure and create a Bourne shell script capable of parsing them.
72b15cb3dSCy Schubert  *
82b15cb3dSCy Schubert  * @addtogroup autoopts
92b15cb3dSCy Schubert  * @{
10ea906c41SOllivier Robert  */
11ea906c41SOllivier Robert /*
122b15cb3dSCy Schubert  *  This file is part of AutoOpts, a companion to AutoGen.
132b15cb3dSCy Schubert  *  AutoOpts is free software.
14*a466cc55SCy Schubert  *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
15ea906c41SOllivier Robert  *
162b15cb3dSCy Schubert  *  AutoOpts is available under any one of two licenses.  The license
172b15cb3dSCy Schubert  *  in use must be one of these two and the choice is under the control
182b15cb3dSCy Schubert  *  of the user of the license.
19ea906c41SOllivier Robert  *
202b15cb3dSCy Schubert  *   The GNU Lesser General Public License, version 3 or later
212b15cb3dSCy Schubert  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
22ea906c41SOllivier Robert  *
232b15cb3dSCy Schubert  *   The Modified Berkeley Software Distribution License
242b15cb3dSCy Schubert  *      See the file "COPYING.mbsd"
25ea906c41SOllivier Robert  *
262b15cb3dSCy Schubert  *  These files have the following sha256 sums:
27ea906c41SOllivier Robert  *
282b15cb3dSCy Schubert  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
292b15cb3dSCy Schubert  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
302b15cb3dSCy Schubert  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
31ea906c41SOllivier Robert  */
32ea906c41SOllivier Robert 
to_uchar(char ch)33276da39aSCy Schubert  static inline unsigned char to_uchar (char ch) { return ch; }
34276da39aSCy Schubert 
35276da39aSCy Schubert #define UPPER(_c) (toupper(to_uchar(_c)))
36276da39aSCy Schubert #define LOWER(_c) (tolower(to_uchar(_c)))
37276da39aSCy Schubert 
38*a466cc55SCy Schubert lo_noreturn static void
option_exits(int exit_code)392b15cb3dSCy Schubert option_exits(int exit_code)
402b15cb3dSCy Schubert {
412b15cb3dSCy Schubert     if (print_exit)
422b15cb3dSCy Schubert         printf("\nexit %d\n", exit_code);
432b15cb3dSCy Schubert     exit(exit_code);
442b15cb3dSCy Schubert }
452b15cb3dSCy Schubert 
46*a466cc55SCy Schubert lo_noreturn static void
ao_bug(char const * msg)472b15cb3dSCy Schubert ao_bug(char const * msg)
482b15cb3dSCy Schubert {
492b15cb3dSCy Schubert     fprintf(stderr, zao_bug_msg, msg);
502b15cb3dSCy Schubert     option_exits(EX_SOFTWARE);
512b15cb3dSCy Schubert }
522b15cb3dSCy Schubert 
53*a466cc55SCy Schubert static void
fserr_warn(char const * prog,char const * op,char const * fname)542b15cb3dSCy Schubert fserr_warn(char const * prog, char const * op, char const * fname)
552b15cb3dSCy Schubert {
562b15cb3dSCy Schubert     fprintf(stderr, zfserr_fmt, prog, errno, strerror(errno),
572b15cb3dSCy Schubert             op, fname);
582b15cb3dSCy Schubert }
592b15cb3dSCy Schubert 
60*a466cc55SCy Schubert lo_noreturn static void
fserr_exit(char const * prog,char const * op,char const * fname)612b15cb3dSCy Schubert fserr_exit(char const * prog, char const * op, char const * fname)
622b15cb3dSCy Schubert {
632b15cb3dSCy Schubert     fserr_warn(prog, op, fname);
642b15cb3dSCy Schubert     option_exits(EXIT_FAILURE);
652b15cb3dSCy Schubert }
662b15cb3dSCy Schubert 
67ea906c41SOllivier Robert /*=export_func  optionParseShell
68ea906c41SOllivier Robert  * private:
69ea906c41SOllivier Robert  *
70ea906c41SOllivier Robert  * what:  Decipher a boolean value
71ea906c41SOllivier Robert  * arg:   + tOptions * + pOpts    + program options descriptor +
72ea906c41SOllivier Robert  *
73ea906c41SOllivier Robert  * doc:
74ea906c41SOllivier Robert  *  Emit a shell script that will parse the command line options.
75ea906c41SOllivier Robert =*/
76ea906c41SOllivier Robert void
optionParseShell(tOptions * opts)772b15cb3dSCy Schubert optionParseShell(tOptions * opts)
78ea906c41SOllivier Robert {
79ea906c41SOllivier Robert     /*
80ea906c41SOllivier Robert      *  Check for our SHELL option now.
81ea906c41SOllivier Robert      *  IF the output file contains the "#!" magic marker,
82ea906c41SOllivier Robert      *  it will override anything we do here.
83ea906c41SOllivier Robert      */
842b15cb3dSCy Schubert     if (HAVE_GENSHELL_OPT(SHELL))
852b15cb3dSCy Schubert         shell_prog = GENSHELL_OPT_ARG(SHELL);
86ea906c41SOllivier Robert 
872b15cb3dSCy Schubert     else if (! ENABLED_GENSHELL_OPT(SHELL))
882b15cb3dSCy Schubert         shell_prog = NULL;
89ea906c41SOllivier Robert 
902b15cb3dSCy Schubert     else if ((shell_prog = getenv("SHELL")),
912b15cb3dSCy Schubert              shell_prog == NULL)
92ea906c41SOllivier Robert 
932b15cb3dSCy Schubert         shell_prog = POSIX_SHELL;
94ea906c41SOllivier Robert 
95ea906c41SOllivier Robert     /*
96ea906c41SOllivier Robert      *  Check for a specified output file
97ea906c41SOllivier Robert      */
982b15cb3dSCy Schubert     if (HAVE_GENSHELL_OPT(SCRIPT))
992b15cb3dSCy Schubert         open_out(GENSHELL_OPT_ARG(SCRIPT), opts->pzProgName);
100ea906c41SOllivier Robert 
1012b15cb3dSCy Schubert     emit_usage(opts);
1022b15cb3dSCy Schubert     emit_setup(opts);
103ea906c41SOllivier Robert 
104ea906c41SOllivier Robert     /*
105ea906c41SOllivier Robert      *  There are four modes of option processing.
106ea906c41SOllivier Robert      */
1072b15cb3dSCy Schubert     switch (opts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
108ea906c41SOllivier Robert     case OPTPROC_LONGOPT:
1092b15cb3dSCy Schubert         fputs(LOOP_STR,         stdout);
110ea906c41SOllivier Robert 
1112b15cb3dSCy Schubert         fputs(LONG_OPT_MARK,    stdout);
1122b15cb3dSCy Schubert         fputs(INIT_LOPT_STR,    stdout);
1132b15cb3dSCy Schubert         emit_long(opts);
1142b15cb3dSCy Schubert         printf(LOPT_ARG_FMT,    opts->pzPROGNAME);
1152b15cb3dSCy Schubert         fputs(END_OPT_SEL_STR,  stdout);
116ea906c41SOllivier Robert 
1172b15cb3dSCy Schubert         fputs(NOT_FOUND_STR,    stdout);
118ea906c41SOllivier Robert         break;
119ea906c41SOllivier Robert 
120ea906c41SOllivier Robert     case 0:
1212b15cb3dSCy Schubert         fputs(ONLY_OPTS_LOOP,   stdout);
1222b15cb3dSCy Schubert         fputs(INIT_LOPT_STR,    stdout);
1232b15cb3dSCy Schubert         emit_long(opts);
1242b15cb3dSCy Schubert         printf(LOPT_ARG_FMT,    opts->pzPROGNAME);
125ea906c41SOllivier Robert         break;
126ea906c41SOllivier Robert 
127ea906c41SOllivier Robert     case OPTPROC_SHORTOPT:
1282b15cb3dSCy Schubert         fputs(LOOP_STR,         stdout);
129ea906c41SOllivier Robert 
1302b15cb3dSCy Schubert         fputs(FLAG_OPT_MARK,    stdout);
1312b15cb3dSCy Schubert         fputs(INIT_OPT_STR,     stdout);
1322b15cb3dSCy Schubert         emit_flag(opts);
1332b15cb3dSCy Schubert         printf(OPT_ARG_FMT,     opts->pzPROGNAME);
1342b15cb3dSCy Schubert         fputs(END_OPT_SEL_STR,  stdout);
135ea906c41SOllivier Robert 
1362b15cb3dSCy Schubert         fputs(NOT_FOUND_STR,    stdout);
137ea906c41SOllivier Robert         break;
138ea906c41SOllivier Robert 
139ea906c41SOllivier Robert     case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
1402b15cb3dSCy Schubert         fputs(LOOP_STR,         stdout);
141ea906c41SOllivier Robert 
1422b15cb3dSCy Schubert         fputs(LONG_OPT_MARK,    stdout);
1432b15cb3dSCy Schubert         fputs(INIT_LOPT_STR,    stdout);
1442b15cb3dSCy Schubert         emit_long(opts);
1452b15cb3dSCy Schubert         printf(LOPT_ARG_FMT,    opts->pzPROGNAME);
1462b15cb3dSCy Schubert         fputs(END_OPT_SEL_STR,  stdout);
147ea906c41SOllivier Robert 
1482b15cb3dSCy Schubert         fputs(FLAG_OPT_MARK,    stdout);
1492b15cb3dSCy Schubert         fputs(INIT_OPT_STR,     stdout);
1502b15cb3dSCy Schubert         emit_flag(opts);
1512b15cb3dSCy Schubert         printf(OPT_ARG_FMT,     opts->pzPROGNAME);
1522b15cb3dSCy Schubert         fputs(END_OPT_SEL_STR,  stdout);
153ea906c41SOllivier Robert 
1542b15cb3dSCy Schubert         fputs(NOT_FOUND_STR,    stdout);
155ea906c41SOllivier Robert         break;
156ea906c41SOllivier Robert     }
157ea906c41SOllivier Robert 
1582b15cb3dSCy Schubert     emit_wrapup(opts);
1592b15cb3dSCy Schubert     if ((script_trailer != NULL) && (*script_trailer != NUL))
1602b15cb3dSCy Schubert         fputs(script_trailer, stdout);
1612b15cb3dSCy Schubert     else if (ENABLED_GENSHELL_OPT(SHELL))
1622b15cb3dSCy Schubert         printf(SHOW_PROG_ENV, opts->pzPROGNAME);
163ea906c41SOllivier Robert 
1642b15cb3dSCy Schubert #ifdef HAVE_FCHMOD
165ea906c41SOllivier Robert     fchmod(STDOUT_FILENO, 0755);
1662b15cb3dSCy Schubert #endif
167ea906c41SOllivier Robert     fclose(stdout);
1682b15cb3dSCy Schubert 
1692b15cb3dSCy Schubert     if (ferror(stdout))
1702b15cb3dSCy Schubert         fserr_exit(opts->pzProgName, zwriting, zstdout_name);
1712b15cb3dSCy Schubert 
1722b15cb3dSCy Schubert     AGFREE(script_text);
1732b15cb3dSCy Schubert     script_leader    = NULL;
1742b15cb3dSCy Schubert     script_trailer   = NULL;
1752b15cb3dSCy Schubert     script_text      = NULL;
176ea906c41SOllivier Robert }
177ea906c41SOllivier Robert 
1782b15cb3dSCy Schubert #ifdef HAVE_WORKING_FORK
1792b15cb3dSCy Schubert /**
1802b15cb3dSCy Schubert  * Print the value of "var" to a file descriptor.
1812b15cb3dSCy Schubert  * The "fdin" is the read end of a pipe to a forked process that
1822b15cb3dSCy Schubert  * is writing usage text to it.  We read that text in and re-emit
1832b15cb3dSCy Schubert  * to standard out, formatting it so that it is assigned to a
1842b15cb3dSCy Schubert  * shell variable.
1852b15cb3dSCy Schubert  *
1862b15cb3dSCy Schubert  * @param[in] prog  The capitalized, c-variable-formatted program name
1872b15cb3dSCy Schubert  * @param[in] var   a similarly formatted type name
1882b15cb3dSCy Schubert  *                  (LONGUSAGE, USAGE or VERSION)
1892b15cb3dSCy Schubert  * @param[in] fdin  the input end of a pipe
1902b15cb3dSCy Schubert  */
191ea906c41SOllivier Robert static void
emit_var_text(char const * prog,char const * var,int fdin)1922b15cb3dSCy Schubert emit_var_text(char const * prog, char const * var, int fdin)
193ea906c41SOllivier Robert {
1942b15cb3dSCy Schubert     FILE * fp   = fdopen(fdin, "r" FOPEN_BINARY_FLAG);
1952b15cb3dSCy Schubert     int    nlct = 0; /* defer newlines and skip trailing ones */
196ea906c41SOllivier Robert 
1972b15cb3dSCy Schubert     printf(SET_TEXT_FMT, prog, var);
1982b15cb3dSCy Schubert     if (fp == NULL)
1992b15cb3dSCy Schubert         goto skip_text;
200ea906c41SOllivier Robert 
201ea906c41SOllivier Robert     for (;;) {
202ea906c41SOllivier Robert         int  ch = fgetc(fp);
203ea906c41SOllivier Robert         switch (ch) {
204ea906c41SOllivier Robert 
2052b15cb3dSCy Schubert         case NL:
2062b15cb3dSCy Schubert             nlct++;
207ea906c41SOllivier Robert             break;
208ea906c41SOllivier Robert 
209ea906c41SOllivier Robert         case '\'':
2102b15cb3dSCy Schubert             while (nlct > 0) {
2112b15cb3dSCy Schubert                 fputc(NL, stdout);
2122b15cb3dSCy Schubert                 nlct--;
213ea906c41SOllivier Robert             }
2142b15cb3dSCy Schubert             fputs(apostrophe, stdout);
215ea906c41SOllivier Robert             break;
216ea906c41SOllivier Robert 
217ea906c41SOllivier Robert         case EOF:
2182b15cb3dSCy Schubert             goto done;
219ea906c41SOllivier Robert 
220ea906c41SOllivier Robert         default:
2212b15cb3dSCy Schubert             while (nlct > 0) {
2222b15cb3dSCy Schubert                 fputc(NL, stdout);
2232b15cb3dSCy Schubert                 nlct--;
224ea906c41SOllivier Robert             }
225ea906c41SOllivier Robert             fputc(ch, stdout);
226ea906c41SOllivier Robert             break;
227ea906c41SOllivier Robert         }
2282b15cb3dSCy Schubert     } done:;
229ea906c41SOllivier Robert 
2302b15cb3dSCy Schubert     fclose(fp);
2312b15cb3dSCy Schubert 
2322b15cb3dSCy Schubert  skip_text:
2332b15cb3dSCy Schubert 
2342b15cb3dSCy Schubert     fputs(END_SET_TEXT, stdout);
2352b15cb3dSCy Schubert }
2362b15cb3dSCy Schubert #endif
2372b15cb3dSCy Schubert 
2382b15cb3dSCy Schubert /**
2392b15cb3dSCy Schubert  *  The purpose of this function is to assign "long usage", short usage
2402b15cb3dSCy Schubert  *  and version information to a shell variable.  Rather than wind our
2412b15cb3dSCy Schubert  *  way through all the logic necessary to emit the text directly, we
2422b15cb3dSCy Schubert  *  fork(), have our child process emit the text the normal way and
2432b15cb3dSCy Schubert  *  capture the output in the parent process.
2442b15cb3dSCy Schubert  *
2452b15cb3dSCy Schubert  * @param[in] opts  the program options
2462b15cb3dSCy Schubert  * @param[in] which what to print: long usage, usage or version
2472b15cb3dSCy Schubert  * @param[in] od    for TT_VERSION, it is the version option
2482b15cb3dSCy Schubert  */
2492b15cb3dSCy Schubert static void
text_to_var(tOptions * opts,teTextTo which,tOptDesc * od)2502b15cb3dSCy Schubert text_to_var(tOptions * opts, teTextTo which, tOptDesc * od)
2512b15cb3dSCy Schubert {
2522b15cb3dSCy Schubert #   define _TT_(n) static char const z ## n [] = #n;
2532b15cb3dSCy Schubert     TEXTTO_TABLE
2542b15cb3dSCy Schubert #   undef _TT_
2552b15cb3dSCy Schubert #   define _TT_(n) z ## n ,
2562b15cb3dSCy Schubert       static char const * ttnames[] = { TEXTTO_TABLE };
2572b15cb3dSCy Schubert #   undef _TT_
2582b15cb3dSCy Schubert 
2592b15cb3dSCy Schubert #if ! defined(HAVE_WORKING_FORK)
2602b15cb3dSCy Schubert     printf(SET_NO_TEXT_FMT, opts->pzPROGNAME, ttnames[which]);
2612b15cb3dSCy Schubert #else
2622b15cb3dSCy Schubert     int  fdpair[2];
2632b15cb3dSCy Schubert 
2642b15cb3dSCy Schubert     fflush(stdout);
2652b15cb3dSCy Schubert     fflush(stderr);
2662b15cb3dSCy Schubert 
2672b15cb3dSCy Schubert     if (pipe(fdpair) != 0)
2682b15cb3dSCy Schubert         fserr_exit(opts->pzProgName, "pipe", zinter_proc_pipe);
2692b15cb3dSCy Schubert 
2702b15cb3dSCy Schubert     switch (fork()) {
2712b15cb3dSCy Schubert     case -1:
2722b15cb3dSCy Schubert         fserr_exit(opts->pzProgName, "fork", opts->pzProgName);
2732b15cb3dSCy Schubert         /* NOTREACHED */
2742b15cb3dSCy Schubert 
2752b15cb3dSCy Schubert     case 0:
2762b15cb3dSCy Schubert         /*
2772b15cb3dSCy Schubert          * Send both stderr and stdout to the pipe.  No matter which
2782b15cb3dSCy Schubert          * descriptor is used, we capture the output on the read end.
2792b15cb3dSCy Schubert          */
2802b15cb3dSCy Schubert         dup2(fdpair[1], STDERR_FILENO);
2812b15cb3dSCy Schubert         dup2(fdpair[1], STDOUT_FILENO);
2822b15cb3dSCy Schubert         close(fdpair[0]);
2832b15cb3dSCy Schubert 
2842b15cb3dSCy Schubert         switch (which) {
2852b15cb3dSCy Schubert         case TT_LONGUSAGE:
2862b15cb3dSCy Schubert             (*(opts->pUsageProc))(opts, EXIT_SUCCESS);
287*a466cc55SCy Schubert             /* FALLTHROUGH */ /* NOTREACHED */
2882b15cb3dSCy Schubert 
2892b15cb3dSCy Schubert         case TT_USAGE:
2902b15cb3dSCy Schubert             (*(opts->pUsageProc))(opts, EXIT_FAILURE);
291*a466cc55SCy Schubert             /* FALLTHROUGH */ /* NOTREACHED */
2922b15cb3dSCy Schubert 
2932b15cb3dSCy Schubert         case TT_VERSION:
2942b15cb3dSCy Schubert             if (od->fOptState & OPTST_ALLOC_ARG) {
2952b15cb3dSCy Schubert                 AGFREE(od->optArg.argString);
2962b15cb3dSCy Schubert                 od->fOptState &= ~OPTST_ALLOC_ARG;
2972b15cb3dSCy Schubert             }
2982b15cb3dSCy Schubert             od->optArg.argString = "c";
2992b15cb3dSCy Schubert             optionPrintVersion(opts, od);
300*a466cc55SCy Schubert             /* FALLTHROUGH */ /* NOTREACHED */
3012b15cb3dSCy Schubert 
3022b15cb3dSCy Schubert         default:
3032b15cb3dSCy Schubert             option_exits(EXIT_FAILURE);
304*a466cc55SCy Schubert             /* FALLTHROUGH */ /* NOTREACHED */
3052b15cb3dSCy Schubert         }
306*a466cc55SCy Schubert         /* FALLTHROUGH */ /* NOTREACHED */
3072b15cb3dSCy Schubert 
3082b15cb3dSCy Schubert     default:
3092b15cb3dSCy Schubert         close(fdpair[1]);
3102b15cb3dSCy Schubert     }
3112b15cb3dSCy Schubert 
3122b15cb3dSCy Schubert     emit_var_text(opts->pzPROGNAME, ttnames[which], fdpair[0]);
313ea906c41SOllivier Robert #endif
314ea906c41SOllivier Robert }
315ea906c41SOllivier Robert 
3162b15cb3dSCy Schubert /**
3172b15cb3dSCy Schubert  * capture usage text in shell variables.
3182b15cb3dSCy Schubert  *
3192b15cb3dSCy Schubert  */
320ea906c41SOllivier Robert static void
emit_usage(tOptions * opts)3212b15cb3dSCy Schubert emit_usage(tOptions * opts)
322ea906c41SOllivier Robert {
3232b15cb3dSCy Schubert     char tm_nm_buf[AO_NAME_SIZE];
324ea906c41SOllivier Robert 
325ea906c41SOllivier Robert     /*
326ea906c41SOllivier Robert      *  First, switch stdout to the output file name.
327ea906c41SOllivier Robert      *  Then, change the program name to the one defined
328ea906c41SOllivier Robert      *  by the definitions (rather than the current
329ea906c41SOllivier Robert      *  executable name).  Down case the upper cased name.
330ea906c41SOllivier Robert      */
3312b15cb3dSCy Schubert     if (script_leader != NULL)
3322b15cb3dSCy Schubert         fputs(script_leader, stdout);
333ea906c41SOllivier Robert 
334ea906c41SOllivier Robert     {
3352b15cb3dSCy Schubert         char const * out_nm;
336ea906c41SOllivier Robert 
337ea906c41SOllivier Robert         {
3382b15cb3dSCy Schubert             time_t    c_tim = time(NULL);
3392b15cb3dSCy Schubert             struct tm * ptm = localtime(&c_tim);
3402b15cb3dSCy Schubert             strftime(tm_nm_buf, AO_NAME_SIZE, TIME_FMT, ptm );
341ea906c41SOllivier Robert         }
342ea906c41SOllivier Robert 
3432b15cb3dSCy Schubert         if (HAVE_GENSHELL_OPT(SCRIPT))
3442b15cb3dSCy Schubert              out_nm = GENSHELL_OPT_ARG(SCRIPT);
3452b15cb3dSCy Schubert         else out_nm = STDOUT;
346ea906c41SOllivier Robert 
3472b15cb3dSCy Schubert         if ((script_leader == NULL) && (shell_prog != NULL))
3482b15cb3dSCy Schubert             printf(SHELL_MAGIC, shell_prog);
349ea906c41SOllivier Robert 
3502b15cb3dSCy Schubert         printf(PREAMBLE_FMT, START_MARK, out_nm, tm_nm_buf);
351ea906c41SOllivier Robert     }
352ea906c41SOllivier Robert 
3532b15cb3dSCy Schubert     printf(END_PRE_FMT, opts->pzPROGNAME);
3542b15cb3dSCy Schubert 
355ea906c41SOllivier Robert     /*
3562b15cb3dSCy Schubert      *  Get a copy of the original program name in lower case and
3572b15cb3dSCy Schubert      *  fill in an approximation of the program name from it.
358ea906c41SOllivier Robert      */
359ea906c41SOllivier Robert     {
3602b15cb3dSCy Schubert         char *       pzPN = tm_nm_buf;
3612b15cb3dSCy Schubert         char const * pz   = opts->pzPROGNAME;
3622b15cb3dSCy Schubert         char **      pp;
3632b15cb3dSCy Schubert 
3642b15cb3dSCy Schubert         /* Copy the program name into the time/name buffer */
365ea906c41SOllivier Robert         for (;;) {
366*a466cc55SCy Schubert             if ((*pzPN++ = (char)tolower(*pz++)) == NUL)
367ea906c41SOllivier Robert                 break;
368ea906c41SOllivier Robert         }
3692b15cb3dSCy Schubert 
370276da39aSCy Schubert         pp  = VOIDP(&(opts->pzProgPath));
3712b15cb3dSCy Schubert         *pp = tm_nm_buf;
372276da39aSCy Schubert         pp  = VOIDP(&(opts->pzProgName));
3732b15cb3dSCy Schubert         *pp = tm_nm_buf;
374ea906c41SOllivier Robert     }
375ea906c41SOllivier Robert 
3762b15cb3dSCy Schubert     text_to_var(opts, TT_LONGUSAGE, NULL);
3772b15cb3dSCy Schubert     text_to_var(opts, TT_USAGE,     NULL);
378ea906c41SOllivier Robert 
379ea906c41SOllivier Robert     {
3802b15cb3dSCy Schubert         tOptDesc * pOptDesc = opts->pOptDesc;
3812b15cb3dSCy Schubert         int        optionCt = opts->optCt;
382ea906c41SOllivier Robert 
383ea906c41SOllivier Robert         for (;;) {
384ea906c41SOllivier Robert             if (pOptDesc->pOptProc == optionPrintVersion) {
3852b15cb3dSCy Schubert                 text_to_var(opts, TT_VERSION, pOptDesc);
386ea906c41SOllivier Robert                 break;
387ea906c41SOllivier Robert             }
388ea906c41SOllivier Robert 
389ea906c41SOllivier Robert             if (--optionCt <= 0)
390ea906c41SOllivier Robert                 break;
391ea906c41SOllivier Robert             pOptDesc++;
392ea906c41SOllivier Robert         }
393ea906c41SOllivier Robert     }
394ea906c41SOllivier Robert }
395ea906c41SOllivier Robert 
3962b15cb3dSCy Schubert static void
emit_wrapup(tOptions * opts)3972b15cb3dSCy Schubert emit_wrapup(tOptions * opts)
3982b15cb3dSCy Schubert {
3992b15cb3dSCy Schubert     tOptDesc *   od     = opts->pOptDesc;
4002b15cb3dSCy Schubert     int          opt_ct = opts->presetOptCt;
4012b15cb3dSCy Schubert     char const * fmt;
4022b15cb3dSCy Schubert 
4032b15cb3dSCy Schubert     printf(FINISH_LOOP, opts->pzPROGNAME);
4042b15cb3dSCy Schubert     for (;opt_ct > 0; od++, --opt_ct) {
4052b15cb3dSCy Schubert         /*
4062b15cb3dSCy Schubert          *  Options that are either usage documentation or are compiled out
4072b15cb3dSCy Schubert          *  are not to be processed.
4082b15cb3dSCy Schubert          */
4092b15cb3dSCy Schubert         if (SKIP_OPT(od) || (od->pz_NAME == NULL))
4102b15cb3dSCy Schubert             continue;
4112b15cb3dSCy Schubert 
4122b15cb3dSCy Schubert         /*
4132b15cb3dSCy Schubert          *  do not presence check if there is no minimum/must-set
4142b15cb3dSCy Schubert          */
4152b15cb3dSCy Schubert         if ((od->optMinCt == 0) && ((od->fOptState & OPTST_MUST_SET) == 0))
4162b15cb3dSCy Schubert             continue;
4172b15cb3dSCy Schubert 
4182b15cb3dSCy Schubert         if (od->optMaxCt > 1)
4192b15cb3dSCy Schubert              fmt = CHK_MIN_COUNT;
4202b15cb3dSCy Schubert         else fmt = CHK_ONE_REQUIRED;
4212b15cb3dSCy Schubert 
4222b15cb3dSCy Schubert         {
4232b15cb3dSCy Schubert             int min = (od->optMinCt == 0) ? 1 : od->optMinCt;
4242b15cb3dSCy Schubert             printf(fmt, opts->pzPROGNAME, od->pz_NAME, min);
4252b15cb3dSCy Schubert         }
4262b15cb3dSCy Schubert     }
4272b15cb3dSCy Schubert     fputs(END_MARK, stdout);
4282b15cb3dSCy Schubert }
429ea906c41SOllivier Robert 
430ea906c41SOllivier Robert static void
emit_setup(tOptions * opts)4312b15cb3dSCy Schubert emit_setup(tOptions * opts)
432ea906c41SOllivier Robert {
4332b15cb3dSCy Schubert     tOptDesc *   od     = opts->pOptDesc;
4342b15cb3dSCy Schubert     int          opt_ct = opts->presetOptCt;
4352b15cb3dSCy Schubert     char const * fmt;
4362b15cb3dSCy Schubert     char const * def_val;
437ea906c41SOllivier Robert 
4382b15cb3dSCy Schubert     for (;opt_ct > 0; od++, --opt_ct) {
4392b15cb3dSCy Schubert         char int_val_buf[32];
440ea906c41SOllivier Robert 
441ea906c41SOllivier Robert         /*
442ea906c41SOllivier Robert          *  Options that are either usage documentation or are compiled out
443ea906c41SOllivier Robert          *  are not to be processed.
444ea906c41SOllivier Robert          */
4452b15cb3dSCy Schubert         if (SKIP_OPT(od) || (od->pz_NAME == NULL))
446ea906c41SOllivier Robert             continue;
447ea906c41SOllivier Robert 
4482b15cb3dSCy Schubert         if (od->optMaxCt > 1)
4492b15cb3dSCy Schubert              fmt = MULTI_DEF_FMT;
4502b15cb3dSCy Schubert         else fmt = SGL_DEF_FMT;
451ea906c41SOllivier Robert 
452ea906c41SOllivier Robert         /*
453ea906c41SOllivier Robert          *  IF this is an enumeration/bitmask option, then convert the value
454ea906c41SOllivier Robert          *  to a string before printing the default value.
455ea906c41SOllivier Robert          */
4562b15cb3dSCy Schubert         switch (OPTST_GET_ARGTYPE(od->fOptState)) {
457ea906c41SOllivier Robert         case OPARG_TYPE_ENUMERATION:
4582b15cb3dSCy Schubert             (*(od->pOptProc))(OPTPROC_EMIT_SHELL, od );
4592b15cb3dSCy Schubert             def_val = od->optArg.argString;
460ea906c41SOllivier Robert             break;
461ea906c41SOllivier Robert 
462ea906c41SOllivier Robert         /*
463ea906c41SOllivier Robert          *  Numeric and membership bit options are just printed as a number.
464ea906c41SOllivier Robert          */
465ea906c41SOllivier Robert         case OPARG_TYPE_NUMERIC:
4662b15cb3dSCy Schubert             snprintf(int_val_buf, sizeof(int_val_buf), "%d",
4672b15cb3dSCy Schubert                      (int)od->optArg.argInt);
4682b15cb3dSCy Schubert             def_val = int_val_buf;
469ea906c41SOllivier Robert             break;
470ea906c41SOllivier Robert 
471ea906c41SOllivier Robert         case OPARG_TYPE_MEMBERSHIP:
4722b15cb3dSCy Schubert             snprintf(int_val_buf, sizeof(int_val_buf), "%lu",
4732b15cb3dSCy Schubert                      (unsigned long)od->optArg.argIntptr);
4742b15cb3dSCy Schubert             def_val = int_val_buf;
475ea906c41SOllivier Robert             break;
476ea906c41SOllivier Robert 
477ea906c41SOllivier Robert         case OPARG_TYPE_BOOLEAN:
4782b15cb3dSCy Schubert             def_val = (od->optArg.argBool) ? TRUE_STR : FALSE_STR;
479ea906c41SOllivier Robert             break;
480ea906c41SOllivier Robert 
481ea906c41SOllivier Robert         default:
4822b15cb3dSCy Schubert             if (od->optArg.argString == NULL) {
4832b15cb3dSCy Schubert                 if (fmt == SGL_DEF_FMT)
4842b15cb3dSCy Schubert                     fmt = SGL_NO_DEF_FMT;
4852b15cb3dSCy Schubert                 def_val = NULL;
486ea906c41SOllivier Robert             }
487ea906c41SOllivier Robert             else
4882b15cb3dSCy Schubert                 def_val = od->optArg.argString;
489ea906c41SOllivier Robert         }
490ea906c41SOllivier Robert 
4912b15cb3dSCy Schubert         printf(fmt, opts->pzPROGNAME, od->pz_NAME, def_val);
492ea906c41SOllivier Robert     }
493ea906c41SOllivier Robert }
494ea906c41SOllivier Robert 
495ea906c41SOllivier Robert static void
emit_action(tOptions * opts,tOptDesc * od)4962b15cb3dSCy Schubert emit_action(tOptions * opts, tOptDesc * od)
497ea906c41SOllivier Robert {
4982b15cb3dSCy Schubert     if (od->pOptProc == optionPrintVersion)
4992b15cb3dSCy Schubert         printf(ECHO_N_EXIT, opts->pzPROGNAME, VER_STR);
500ea906c41SOllivier Robert 
5012b15cb3dSCy Schubert     else if (od->pOptProc == optionPagedUsage)
5022b15cb3dSCy Schubert         printf(PAGE_USAGE_TEXT, opts->pzPROGNAME);
503ea906c41SOllivier Robert 
5042b15cb3dSCy Schubert     else if (od->pOptProc == optionLoadOpt) {
5052b15cb3dSCy Schubert         printf(LVL3_CMD, NO_LOAD_WARN);
5062b15cb3dSCy Schubert         printf(LVL3_CMD, YES_NEED_OPT_ARG);
507ea906c41SOllivier Robert 
5082b15cb3dSCy Schubert     } else if (od->pz_NAME == NULL) {
509ea906c41SOllivier Robert 
5102b15cb3dSCy Schubert         if (od->pOptProc == NULL) {
5112b15cb3dSCy Schubert             printf(LVL3_CMD, NO_SAVE_OPTS);
5122b15cb3dSCy Schubert             printf(LVL3_CMD, OK_NEED_OPT_ARG);
513ea906c41SOllivier Robert         } else
5142b15cb3dSCy Schubert             printf(ECHO_N_EXIT, opts->pzPROGNAME, LONG_USE_STR);
515ea906c41SOllivier Robert 
516ea906c41SOllivier Robert     } else {
5172b15cb3dSCy Schubert         if (od->optMaxCt == 1)
5182b15cb3dSCy Schubert             printf(SGL_ARG_FMT, opts->pzPROGNAME, od->pz_NAME);
519ea906c41SOllivier Robert         else {
5202b15cb3dSCy Schubert             if ((unsigned)od->optMaxCt < NOLIMIT)
5212b15cb3dSCy Schubert                 printf(CHK_MAX_COUNT, opts->pzPROGNAME,
5222b15cb3dSCy Schubert                        od->pz_NAME, od->optMaxCt);
523ea906c41SOllivier Robert 
5242b15cb3dSCy Schubert             printf(MULTI_ARG_FMT, opts->pzPROGNAME, od->pz_NAME);
525ea906c41SOllivier Robert         }
526ea906c41SOllivier Robert 
527ea906c41SOllivier Robert         /*
528ea906c41SOllivier Robert          *  Fix up the args.
529ea906c41SOllivier Robert          */
5302b15cb3dSCy Schubert         if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_NONE) {
5312b15cb3dSCy Schubert             printf(SET_MULTI_ARG, opts->pzPROGNAME, od->pz_NAME);
5322b15cb3dSCy Schubert             printf(LVL3_CMD, NO_ARG_NEEDED);
533ea906c41SOllivier Robert 
5342b15cb3dSCy Schubert         } else if (od->fOptState & OPTST_ARG_OPTIONAL) {
5352b15cb3dSCy Schubert             printf(SET_MULTI_ARG,  opts->pzPROGNAME, od->pz_NAME);
5362b15cb3dSCy Schubert             printf(LVL3_CMD, OK_NEED_OPT_ARG);
537ea906c41SOllivier Robert 
538ea906c41SOllivier Robert         } else {
5392b15cb3dSCy Schubert             printf(LVL3_CMD, YES_NEED_OPT_ARG);
540ea906c41SOllivier Robert         }
541ea906c41SOllivier Robert     }
542ea906c41SOllivier Robert     fputs(zOptionEndSelect, stdout);
543ea906c41SOllivier Robert }
544ea906c41SOllivier Robert 
545ea906c41SOllivier Robert static void
emit_inaction(tOptions * opts,tOptDesc * od)5462b15cb3dSCy Schubert emit_inaction(tOptions * opts, tOptDesc * od)
547ea906c41SOllivier Robert {
5482b15cb3dSCy Schubert     if (od->pOptProc == optionLoadOpt) {
5492b15cb3dSCy Schubert         printf(LVL3_CMD, NO_SUPPRESS_LOAD);
550ea906c41SOllivier Robert 
5512b15cb3dSCy Schubert     } else if (od->optMaxCt == 1)
5522b15cb3dSCy Schubert         printf(NO_SGL_ARG_FMT, opts->pzPROGNAME,
5532b15cb3dSCy Schubert                od->pz_NAME, od->pz_DisablePfx);
554ea906c41SOllivier Robert     else
5552b15cb3dSCy Schubert         printf(NO_MULTI_ARG_FMT, opts->pzPROGNAME,
5562b15cb3dSCy Schubert                od->pz_NAME, od->pz_DisablePfx);
557ea906c41SOllivier Robert 
5582b15cb3dSCy Schubert     printf(LVL3_CMD, NO_ARG_NEEDED);
559ea906c41SOllivier Robert     fputs(zOptionEndSelect, stdout);
560ea906c41SOllivier Robert }
561ea906c41SOllivier Robert 
5622b15cb3dSCy Schubert /**
5632b15cb3dSCy Schubert  * recognize flag options.  These go at the end.
5642b15cb3dSCy Schubert  * At the end, emit code to handle options we don't recognize.
5652b15cb3dSCy Schubert  *
5662b15cb3dSCy Schubert  * @param[in] opts  the program options
5672b15cb3dSCy Schubert  */
568ea906c41SOllivier Robert static void
emit_flag(tOptions * opts)5692b15cb3dSCy Schubert emit_flag(tOptions * opts)
570ea906c41SOllivier Robert {
5712b15cb3dSCy Schubert     tOptDesc * od = opts->pOptDesc;
5722b15cb3dSCy Schubert     int        opt_ct = opts->optCt;
573ea906c41SOllivier Robert 
574ea906c41SOllivier Robert     fputs(zOptionCase, stdout);
575ea906c41SOllivier Robert 
5762b15cb3dSCy Schubert     for (;opt_ct > 0; od++, --opt_ct) {
577ea906c41SOllivier Robert 
5782b15cb3dSCy Schubert         if (SKIP_OPT(od) || ! IS_GRAPHIC_CHAR(od->optValue))
579ea906c41SOllivier Robert             continue;
580ea906c41SOllivier Robert 
5812b15cb3dSCy Schubert         printf(zOptionFlag, od->optValue);
5822b15cb3dSCy Schubert         emit_action(opts, od);
583ea906c41SOllivier Robert     }
5842b15cb3dSCy Schubert     printf(UNK_OPT_FMT, FLAG_STR, opts->pzPROGNAME);
585ea906c41SOllivier Robert }
586ea906c41SOllivier Robert 
5872b15cb3dSCy Schubert /**
5882b15cb3dSCy Schubert  *  Emit the match text for a long option.  The passed in \a name may be
5892b15cb3dSCy Schubert  *  either the enablement name or the disablement name.
5902b15cb3dSCy Schubert  *
5912b15cb3dSCy Schubert  * @param[in] name  The current name to check.
5922b15cb3dSCy Schubert  * @param[in] cod   current option descriptor
5932b15cb3dSCy Schubert  * @param[in] opts  the program options
594ea906c41SOllivier Robert  */
595ea906c41SOllivier Robert static void
emit_match_expr(char const * name,tOptDesc * cod,tOptions * opts)5962b15cb3dSCy Schubert emit_match_expr(char const * name, tOptDesc * cod, tOptions * opts)
597ea906c41SOllivier Robert {
5982b15cb3dSCy Schubert     char name_bf[32];
5992b15cb3dSCy Schubert     unsigned int    min_match_ct = 2;
6002b15cb3dSCy Schubert     unsigned int    max_match_ct = strlen(name) - 1;
601ea906c41SOllivier Robert 
6022b15cb3dSCy Schubert     if (max_match_ct >= sizeof(name_bf) - 1)
6032b15cb3dSCy Schubert         goto leave;
6042b15cb3dSCy Schubert 
6052b15cb3dSCy Schubert     {
6062b15cb3dSCy Schubert         tOptDesc *  od = opts->pOptDesc;
6072b15cb3dSCy Schubert         int         ct = opts->optCt;
6082b15cb3dSCy Schubert 
6092b15cb3dSCy Schubert         for (; ct-- > 0; od++) {
6102b15cb3dSCy Schubert             unsigned int match_ct = 0;
611ea906c41SOllivier Robert 
612ea906c41SOllivier Robert             /*
6132b15cb3dSCy Schubert              *  Omit the current option, Doc opts and compiled out opts.
614ea906c41SOllivier Robert              */
6152b15cb3dSCy Schubert             if ((od == cod) || SKIP_OPT(od))
616ea906c41SOllivier Robert                 continue;
617ea906c41SOllivier Robert 
618ea906c41SOllivier Robert             /*
619ea906c41SOllivier Robert              *  Check each character of the name case insensitively.
620ea906c41SOllivier Robert              *  They must not be the same.  They cannot be, because it would
621ea906c41SOllivier Robert              *  not compile correctly if they were.
622ea906c41SOllivier Robert              */
623276da39aSCy Schubert             while (UPPER(od->pz_Name[match_ct]) == UPPER(name[match_ct]))
6242b15cb3dSCy Schubert                 match_ct++;
625ea906c41SOllivier Robert 
6262b15cb3dSCy Schubert             if (match_ct > min_match_ct)
6272b15cb3dSCy Schubert                 min_match_ct = match_ct;
628ea906c41SOllivier Robert 
629ea906c41SOllivier Robert             /*
630ea906c41SOllivier Robert              *  Check the disablement name, too.
631ea906c41SOllivier Robert              */
6322b15cb3dSCy Schubert             if (od->pz_DisableName == NULL)
6332b15cb3dSCy Schubert                 continue;
6342b15cb3dSCy Schubert 
6352b15cb3dSCy Schubert             match_ct = 0;
636*a466cc55SCy Schubert             while (  toupper(od->pz_DisableName[match_ct])
637*a466cc55SCy Schubert                   == toupper(name[match_ct]))
6382b15cb3dSCy Schubert                 match_ct++;
6392b15cb3dSCy Schubert             if (match_ct > min_match_ct)
6402b15cb3dSCy Schubert                 min_match_ct = match_ct;
641ea906c41SOllivier Robert         }
642ea906c41SOllivier Robert     }
643ea906c41SOllivier Robert 
644ea906c41SOllivier Robert     /*
6452b15cb3dSCy Schubert      *  Don't bother emitting partial matches if there is only one possible
6462b15cb3dSCy Schubert      *  partial match.
647ea906c41SOllivier Robert      */
6482b15cb3dSCy Schubert     if (min_match_ct < max_match_ct) {
6492b15cb3dSCy Schubert         char *  pz    = name_bf + min_match_ct;
6502b15cb3dSCy Schubert         int     nm_ix = min_match_ct;
651ea906c41SOllivier Robert 
6522b15cb3dSCy Schubert         memcpy(name_bf, name, min_match_ct);
653ea906c41SOllivier Robert 
654ea906c41SOllivier Robert         for (;;) {
655ea906c41SOllivier Robert             *pz = NUL;
6562b15cb3dSCy Schubert             printf(zOptionPartName, name_bf);
6572b15cb3dSCy Schubert             *pz++ = name[nm_ix++];
6582b15cb3dSCy Schubert             if (name[nm_ix] == NUL) {
659ea906c41SOllivier Robert                 *pz = NUL;
660ea906c41SOllivier Robert                 break;
661ea906c41SOllivier Robert             }
662ea906c41SOllivier Robert         }
663ea906c41SOllivier Robert     }
6642b15cb3dSCy Schubert 
6652b15cb3dSCy Schubert leave:
6662b15cb3dSCy Schubert     printf(zOptionFullName, name);
667ea906c41SOllivier Robert }
668ea906c41SOllivier Robert 
6692b15cb3dSCy Schubert /**
6702b15cb3dSCy Schubert  *  Emit GNU-standard long option handling code.
6712b15cb3dSCy Schubert  *
6722b15cb3dSCy Schubert  * @param[in] opts  the program options
673ea906c41SOllivier Robert  */
674ea906c41SOllivier Robert static void
emit_long(tOptions * opts)6752b15cb3dSCy Schubert emit_long(tOptions * opts)
676ea906c41SOllivier Robert {
6772b15cb3dSCy Schubert     tOptDesc * od = opts->pOptDesc;
6782b15cb3dSCy Schubert     int        ct  = opts->optCt;
679ea906c41SOllivier Robert 
680ea906c41SOllivier Robert     fputs(zOptionCase, stdout);
681ea906c41SOllivier Robert 
682ea906c41SOllivier Robert     /*
683ea906c41SOllivier Robert      *  do each option, ...
684ea906c41SOllivier Robert      */
685ea906c41SOllivier Robert     do  {
686ea906c41SOllivier Robert         /*
687ea906c41SOllivier Robert          *  Documentation & compiled-out options
688ea906c41SOllivier Robert          */
6892b15cb3dSCy Schubert         if (SKIP_OPT(od))
690ea906c41SOllivier Robert             continue;
691ea906c41SOllivier Robert 
6922b15cb3dSCy Schubert         emit_match_expr(od->pz_Name, od, opts);
6932b15cb3dSCy Schubert         emit_action(opts, od);
694ea906c41SOllivier Robert 
695ea906c41SOllivier Robert         /*
696ea906c41SOllivier Robert          *  Now, do the same thing for the disablement version of the option.
697ea906c41SOllivier Robert          */
6982b15cb3dSCy Schubert         if (od->pz_DisableName != NULL) {
6992b15cb3dSCy Schubert             emit_match_expr(od->pz_DisableName, od, opts);
7002b15cb3dSCy Schubert             emit_inaction(opts, od);
701ea906c41SOllivier Robert         }
7022b15cb3dSCy Schubert     } while (od++, --ct > 0);
703ea906c41SOllivier Robert 
7042b15cb3dSCy Schubert     printf(UNK_OPT_FMT, OPTION_STR, opts->pzPROGNAME);
705ea906c41SOllivier Robert }
706ea906c41SOllivier Robert 
7072b15cb3dSCy Schubert /**
7082b15cb3dSCy Schubert  * Load the previous shell script output file.  We need to preserve any
7092b15cb3dSCy Schubert  * hand-edited additions outside of the START_MARK and END_MARKs.
7102b15cb3dSCy Schubert  *
7112b15cb3dSCy Schubert  * @param[in] fname  the output file name
7122b15cb3dSCy Schubert  */
7132b15cb3dSCy Schubert static char *
load_old_output(char const * fname,char const * pname)7142b15cb3dSCy Schubert load_old_output(char const * fname, char const * pname)
715ea906c41SOllivier Robert {
716ea906c41SOllivier Robert     /*
717ea906c41SOllivier Robert      *  IF we cannot stat the file,
718ea906c41SOllivier Robert      *  THEN assume we are creating a new file.
719ea906c41SOllivier Robert      *       Skip the loading of the old data.
720ea906c41SOllivier Robert      */
7212b15cb3dSCy Schubert     FILE * fp = fopen(fname, "r" FOPEN_BINARY_FLAG);
7222b15cb3dSCy Schubert     struct stat stbf;
7232b15cb3dSCy Schubert     char * text;
7242b15cb3dSCy Schubert     char * scan;
7252b15cb3dSCy Schubert 
7262b15cb3dSCy Schubert     if (fp == NULL)
7272b15cb3dSCy Schubert         return NULL;
728ea906c41SOllivier Robert 
729ea906c41SOllivier Robert     /*
7302b15cb3dSCy Schubert      * If we opened it, we should be able to stat it and it needs
7312b15cb3dSCy Schubert      * to be a regular file
732ea906c41SOllivier Robert      */
7332b15cb3dSCy Schubert     if ((fstat(fileno(fp), &stbf) != 0) || (! S_ISREG(stbf.st_mode)))
7342b15cb3dSCy Schubert         fserr_exit(pname, "fstat", fname);
735ea906c41SOllivier Robert 
7362b15cb3dSCy Schubert     scan = text = AGALOC(stbf.st_size + 1, "f data");
737ea906c41SOllivier Robert 
738ea906c41SOllivier Robert     /*
739ea906c41SOllivier Robert      *  Read in all the data as fast as our OS will let us.
740ea906c41SOllivier Robert      */
741ea906c41SOllivier Robert     for (;;) {
742276da39aSCy Schubert         size_t inct = fread(VOIDP(scan), 1, (size_t)stbf.st_size, fp);
743ea906c41SOllivier Robert         if (inct == 0)
744ea906c41SOllivier Robert             break;
745ea906c41SOllivier Robert 
7462b15cb3dSCy Schubert         stbf.st_size -= (ssize_t)inct;
747ea906c41SOllivier Robert 
7482b15cb3dSCy Schubert         if (stbf.st_size == 0)
749ea906c41SOllivier Robert             break;
7502b15cb3dSCy Schubert 
7512b15cb3dSCy Schubert         scan += inct;
752ea906c41SOllivier Robert     }
753ea906c41SOllivier Robert 
7542b15cb3dSCy Schubert     *scan = NUL;
755ea906c41SOllivier Robert     fclose(fp);
7562b15cb3dSCy Schubert 
7572b15cb3dSCy Schubert     return text;
7582b15cb3dSCy Schubert }
7592b15cb3dSCy Schubert 
7602b15cb3dSCy Schubert /**
7612b15cb3dSCy Schubert  * Open the specified output file.  If it already exists, load its
7622b15cb3dSCy Schubert  * contents and save the non-generated (hand edited) portions.
7632b15cb3dSCy Schubert  * If a "start mark" is found, everything before it is preserved leader.
7642b15cb3dSCy Schubert  * If not, the entire thing is a trailer.  Assuming the start is found,
7652b15cb3dSCy Schubert  * then everything after the end marker is the trailer.  If the end
7662b15cb3dSCy Schubert  * mark is not found, the file is actually corrupt, but we take the
7672b15cb3dSCy Schubert  * remainder to be the trailer.
7682b15cb3dSCy Schubert  *
7692b15cb3dSCy Schubert  * @param[in] fname  the output file name
7702b15cb3dSCy Schubert  */
7712b15cb3dSCy Schubert static void
open_out(char const * fname,char const * pname)7722b15cb3dSCy Schubert open_out(char const * fname, char const * pname)
7732b15cb3dSCy Schubert {
7742b15cb3dSCy Schubert 
7752b15cb3dSCy Schubert     do  {
7762b15cb3dSCy Schubert         char * txt = script_text = load_old_output(fname, pname);
7772b15cb3dSCy Schubert         char * scn;
7782b15cb3dSCy Schubert 
7792b15cb3dSCy Schubert         if (txt == NULL)
7802b15cb3dSCy Schubert             break;
7812b15cb3dSCy Schubert 
7822b15cb3dSCy Schubert         scn = strstr(txt, START_MARK);
7832b15cb3dSCy Schubert         if (scn == NULL) {
7842b15cb3dSCy Schubert             script_trailer = txt;
785ea906c41SOllivier Robert             break;
786ea906c41SOllivier Robert         }
787ea906c41SOllivier Robert 
7882b15cb3dSCy Schubert         *(scn++) = NUL;
7892b15cb3dSCy Schubert         scn = strstr(scn, END_MARK);
7902b15cb3dSCy Schubert         if (scn == NULL) {
7912b15cb3dSCy Schubert             /*
7922b15cb3dSCy Schubert              * The file is corrupt.  Set the trailer to be everything
7932b15cb3dSCy Schubert              * after the start mark. The user will need to fix it up.
7942b15cb3dSCy Schubert              */
7952b15cb3dSCy Schubert             script_trailer = txt + strlen(txt) + START_MARK_LEN + 1;
796ea906c41SOllivier Robert             break;
797ea906c41SOllivier Robert         }
798ea906c41SOllivier Robert 
799ea906c41SOllivier Robert         /*
8002b15cb3dSCy Schubert          *  Check to see if the data contains our marker.
8012b15cb3dSCy Schubert          *  If it does, then we will skip over it
802ea906c41SOllivier Robert          */
8032b15cb3dSCy Schubert         script_trailer = scn + END_MARK_LEN;
8042b15cb3dSCy Schubert         script_leader  = txt;
8052b15cb3dSCy Schubert     } while (false);
806ea906c41SOllivier Robert 
8072b15cb3dSCy Schubert     if (freopen(fname, "w" FOPEN_BINARY_FLAG, stdout) != stdout)
8082b15cb3dSCy Schubert         fserr_exit(pname, "freopen", fname);
809ea906c41SOllivier Robert }
810ea906c41SOllivier Robert 
811ea906c41SOllivier Robert /*=export_func genshelloptUsage
812ea906c41SOllivier Robert  * private:
813ea906c41SOllivier Robert  * what: The usage function for the genshellopt generated program
814ea906c41SOllivier Robert  *
8152b15cb3dSCy Schubert  * arg:  + tOptions * + opts    + program options descriptor +
8162b15cb3dSCy Schubert  * arg:  + int        + exit_cd + usage text type to produce +
817ea906c41SOllivier Robert  *
818ea906c41SOllivier Robert  * doc:
819ea906c41SOllivier Robert  *  This function is used to create the usage strings for the option
820ea906c41SOllivier Robert  *  processing shell script code.  Two child processes are spawned
821ea906c41SOllivier Robert  *  each emitting the usage text in either the short (error exit)
822ea906c41SOllivier Robert  *  style or the long style.  The generated program will capture this
823ea906c41SOllivier Robert  *  and create shell script variables containing the two types of text.
824ea906c41SOllivier Robert =*/
825ea906c41SOllivier Robert void
genshelloptUsage(tOptions * opts,int exit_cd)8262b15cb3dSCy Schubert genshelloptUsage(tOptions * opts, int exit_cd)
827ea906c41SOllivier Robert {
8282b15cb3dSCy Schubert #if ! defined(HAVE_WORKING_FORK)
8292b15cb3dSCy Schubert     optionUsage(opts, exit_cd);
830ea906c41SOllivier Robert #else
831ea906c41SOllivier Robert     /*
832ea906c41SOllivier Robert      *  IF not EXIT_SUCCESS,
833ea906c41SOllivier Robert      *  THEN emit the short form of usage.
834ea906c41SOllivier Robert      */
8352b15cb3dSCy Schubert     if (exit_cd != EXIT_SUCCESS)
8362b15cb3dSCy Schubert         optionUsage(opts, exit_cd);
837ea906c41SOllivier Robert     fflush(stderr);
838ea906c41SOllivier Robert     fflush(stdout);
8392b15cb3dSCy Schubert     if (ferror(stdout) || ferror(stderr))
8402b15cb3dSCy Schubert         option_exits(EXIT_FAILURE);
841ea906c41SOllivier Robert 
842ea906c41SOllivier Robert     option_usage_fp = stdout;
843ea906c41SOllivier Robert 
844ea906c41SOllivier Robert     /*
845ea906c41SOllivier Robert      *  First, print our usage
846ea906c41SOllivier Robert      */
847ea906c41SOllivier Robert     switch (fork()) {
848ea906c41SOllivier Robert     case -1:
8492b15cb3dSCy Schubert         optionUsage(opts, EXIT_FAILURE);
850*a466cc55SCy Schubert         /* FALLTHROUGH */ /* NOTREACHED */
851ea906c41SOllivier Robert 
852ea906c41SOllivier Robert     case 0:
853ea906c41SOllivier Robert         pagerState = PAGER_STATE_CHILD;
8542b15cb3dSCy Schubert         optionUsage(opts, EXIT_SUCCESS);
855*a466cc55SCy Schubert         /* FALLTHROUGH */ /* NOTREACHED */
856ea906c41SOllivier Robert 
857ea906c41SOllivier Robert     default:
858ea906c41SOllivier Robert     {
859ea906c41SOllivier Robert         int  sts;
860ea906c41SOllivier Robert         wait(&sts);
861ea906c41SOllivier Robert     }
862ea906c41SOllivier Robert     }
863ea906c41SOllivier Robert 
864ea906c41SOllivier Robert     /*
865ea906c41SOllivier Robert      *  Generate the pzProgName, since optionProcess() normally
866ea906c41SOllivier Robert      *  gets it from the command line
867ea906c41SOllivier Robert      */
868ea906c41SOllivier Robert     {
869ea906c41SOllivier Robert         char *  pz;
870276da39aSCy Schubert         char ** pp = VOIDP(&(optionParseShellOptions->pzProgName));
8712b15cb3dSCy Schubert         AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name");
8722b15cb3dSCy Schubert         *pp = pz;
873ea906c41SOllivier Robert         while (*pz != NUL) {
874276da39aSCy Schubert             *pz = (char)LOWER(*pz);
875ea906c41SOllivier Robert             pz++;
876ea906c41SOllivier Robert         }
877ea906c41SOllivier Robert     }
878ea906c41SOllivier Robert 
879ea906c41SOllivier Robert     /*
880ea906c41SOllivier Robert      *  Separate the makeshell usage from the client usage
881ea906c41SOllivier Robert      */
8822b15cb3dSCy Schubert     fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName);
883ea906c41SOllivier Robert     fflush(option_usage_fp);
884ea906c41SOllivier Robert 
885ea906c41SOllivier Robert     /*
886ea906c41SOllivier Robert      *  Now, print the client usage.
887ea906c41SOllivier Robert      */
888ea906c41SOllivier Robert     switch (fork()) {
889ea906c41SOllivier Robert     case 0:
890ea906c41SOllivier Robert         pagerState = PAGER_STATE_CHILD;
891ea906c41SOllivier Robert         /*FALLTHROUGH*/
892ea906c41SOllivier Robert     case -1:
8932b15cb3dSCy Schubert         optionUsage(optionParseShellOptions, EXIT_FAILURE);
894*a466cc55SCy Schubert         /* FALLTHROUGH */ /* NOTREACHED */
895ea906c41SOllivier Robert 
896ea906c41SOllivier Robert     default:
897ea906c41SOllivier Robert     {
898ea906c41SOllivier Robert         int  sts;
899ea906c41SOllivier Robert         wait(&sts);
900ea906c41SOllivier Robert     }
901ea906c41SOllivier Robert     }
902ea906c41SOllivier Robert 
9032b15cb3dSCy Schubert     fflush(stdout);
9042b15cb3dSCy Schubert     if (ferror(stdout))
9052b15cb3dSCy Schubert         fserr_exit(opts->pzProgName, zwriting, zstdout_name);
9062b15cb3dSCy Schubert 
9072b15cb3dSCy Schubert     option_exits(EXIT_SUCCESS);
908ea906c41SOllivier Robert #endif
909ea906c41SOllivier Robert }
910ea906c41SOllivier Robert 
9112b15cb3dSCy Schubert /** @}
9122b15cb3dSCy Schubert  *
913ea906c41SOllivier Robert  * Local Variables:
914ea906c41SOllivier Robert  * mode: C
915ea906c41SOllivier Robert  * c-file-style: "stroustrup"
916ea906c41SOllivier Robert  * indent-tabs-mode: nil
917ea906c41SOllivier Robert  * End:
918ea906c41SOllivier Robert  * end of autoopts/makeshell.c */
919