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