summaryrefslogtreecommitdiff
path: root/autoopts/makeshell.c
diff options
context:
space:
mode:
Diffstat (limited to 'autoopts/makeshell.c')
-rw-r--r--autoopts/makeshell.c873
1 files changed, 873 insertions, 0 deletions
diff --git a/autoopts/makeshell.c b/autoopts/makeshell.c
new file mode 100644
index 0000000..5ba949d
--- /dev/null
+++ b/autoopts/makeshell.c
@@ -0,0 +1,873 @@
+
+/**
+ * \file makeshell.c
+ *
+ * Time-stamp: "2012-08-11 08:51:32 bkorb"
+ *
+ * This module will interpret the options set in the tOptions
+ * structure and create a Bourne shell script capable of parsing them.
+ *
+ * This file is part of AutoOpts, a companion to AutoGen.
+ * AutoOpts is free software.
+ * AutoOpts is Copyright (c) 1992-2012 by Bruce Korb - all rights reserved
+ *
+ * AutoOpts is available under any one of two licenses. The license
+ * in use must be one of these two and the choice is under the control
+ * of the user of the license.
+ *
+ * The GNU Lesser General Public License, version 3 or later
+ * See the files "COPYING.lgplv3" and "COPYING.gplv3"
+ *
+ * The Modified Berkeley Software Distribution License
+ * See the file "COPYING.mbsd"
+ *
+ * These files have the following md5sums:
+ *
+ * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
+ * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
+ * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ */
+
+tOptions * optionParseShellOptions = NULL;
+
+static char const * shell_prog = NULL;
+static char * script_leader = NULL;
+static char * script_trailer = NULL;
+static char * script_text = NULL;
+
+/* = = = START-STATIC-FORWARD = = = */
+static void
+emit_var_text(char const * prog, char const * var, int fdin);
+
+static void
+text_to_var(tOptions * pOpts, teTextTo whichVar, tOptDesc * pOD);
+
+static void
+emit_usage(tOptions * pOpts);
+
+static void
+emit_setup(tOptions * pOpts);
+
+static void
+emit_action(tOptions * pOpts, tOptDesc* pOptDesc);
+
+static void
+emit_inaction(tOptions * pOpts, tOptDesc* pOptDesc);
+
+static void
+emit_flag(tOptions * pOpts);
+
+static void
+emit_match_expr(char const * pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts);
+
+static void
+emit_long(tOptions * pOpts);
+
+static char *
+load_old_output(char const * fname);
+
+static void
+open_out(char const * fname);
+/* = = = END-STATIC-FORWARD = = = */
+
+/*=export_func optionParseShell
+ * private:
+ *
+ * what: Decipher a boolean value
+ * arg: + tOptions* + pOpts + program options descriptor +
+ *
+ * doc:
+ * Emit a shell script that will parse the command line options.
+=*/
+void
+optionParseShell(tOptions * pOpts)
+{
+ /*
+ * Check for our SHELL option now.
+ * IF the output file contains the "#!" magic marker,
+ * it will override anything we do here.
+ */
+ if (HAVE_GENSHELL_OPT(SHELL))
+ shell_prog = GENSHELL_OPT_ARG(SHELL);
+
+ else if (! ENABLED_GENSHELL_OPT(SHELL))
+ shell_prog = NULL;
+
+ else if ((shell_prog = getenv("SHELL")),
+ shell_prog == NULL)
+
+ shell_prog = POSIX_SHELL;
+
+ /*
+ * Check for a specified output file
+ */
+ if (HAVE_GENSHELL_OPT(SCRIPT))
+ open_out(GENSHELL_OPT_ARG(SCRIPT));
+
+ emit_usage(pOpts);
+ emit_setup(pOpts);
+
+ /*
+ * There are four modes of option processing.
+ */
+ switch (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
+ case OPTPROC_LONGOPT:
+ fputs(LOOP_STR, stdout);
+
+ fputs(LONG_OPT_MARK, stdout);
+ fputs(INIT_LOPT_STR, stdout);
+ emit_long(pOpts);
+ printf(LOPT_ARG_FMT, pOpts->pzPROGNAME);
+ fputs(END_OPT_SEL_STR, stdout);
+
+ fputs(NOT_FOUND_STR, stdout);
+ break;
+
+ case 0:
+ fputs(ONLY_OPTS_LOOP, stdout);
+ fputs(INIT_LOPT_STR, stdout);
+ emit_long(pOpts);
+ printf(LOPT_ARG_FMT, pOpts->pzPROGNAME);
+ break;
+
+ case OPTPROC_SHORTOPT:
+ fputs(LOOP_STR, stdout);
+
+ fputs(FLAG_OPT_MARK, stdout);
+ fputs(INIT_OPT_STR, stdout);
+ emit_flag(pOpts);
+ printf(OPT_ARG_FMT, pOpts->pzPROGNAME);
+ fputs(END_OPT_SEL_STR, stdout);
+
+ fputs(NOT_FOUND_STR, stdout);
+ break;
+
+ case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
+ fputs(LOOP_STR, stdout);
+
+ fputs(LONG_OPT_MARK, stdout);
+ fputs(INIT_LOPT_STR, stdout);
+ emit_long(pOpts);
+ printf(LOPT_ARG_FMT, pOpts->pzPROGNAME);
+ fputs(END_OPT_SEL_STR, stdout);
+
+ fputs(FLAG_OPT_MARK, stdout);
+ fputs(INIT_OPT_STR, stdout);
+ emit_flag(pOpts);
+ printf(OPT_ARG_FMT, pOpts->pzPROGNAME);
+ fputs(END_OPT_SEL_STR, stdout);
+
+ fputs(NOT_FOUND_STR, stdout);
+ break;
+ }
+
+ printf(zLoopEnd, pOpts->pzPROGNAME, END_MARK);
+ if ((script_trailer != NULL) && (*script_trailer != NUL))
+ fputs(script_trailer, stdout);
+ else if (ENABLED_GENSHELL_OPT(SHELL))
+ printf(SHOW_PROG_ENV, pOpts->pzPROGNAME);
+
+#ifdef HAVE_FCHMOD
+ fchmod(STDOUT_FILENO, 0755);
+#endif
+ fclose(stdout);
+
+ if (ferror(stdout)) {
+ fputs(zOutputFail, stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ AGFREE(script_text);
+ script_leader = NULL;
+ script_trailer = NULL;
+ script_text = NULL;
+}
+
+#ifdef HAVE_WORKING_FORK
+static void
+emit_var_text(char const * prog, char const * var, int fdin)
+{
+ FILE * fp = fdopen(fdin, "r" FOPEN_BINARY_FLAG);
+ int nlct = 0; /* defer newlines and skip trailing ones */
+
+ printf(SET_TEXT_FMT, prog, var);
+ if (fp == NULL)
+ goto skip_text;
+
+ for (;;) {
+ int ch = fgetc(fp);
+ switch (ch) {
+
+ case NL:
+ nlct++;
+ break;
+
+ case '\'':
+ while (nlct > 0) {
+ fputc(NL, stdout);
+ nlct--;
+ }
+ fputs(apostrophy, stdout);
+ break;
+
+ case EOF:
+ goto endCharLoop;
+
+ default:
+ while (nlct > 0) {
+ fputc(NL, stdout);
+ nlct--;
+ }
+ fputc(ch, stdout);
+ break;
+ }
+ } endCharLoop:;
+
+ fclose(fp);
+
+skip_text:
+
+ fputs(END_SET_TEXT, stdout);
+}
+
+#endif
+
+/*
+ * The purpose of this function is to assign "long usage", short usage
+ * and version information to a shell variable. Rather than wind our
+ * way through all the logic necessary to emit the text directly, we
+ * fork(), have our child process emit the text the normal way and
+ * capture the output in the parent process.
+ */
+static void
+text_to_var(tOptions * pOpts, teTextTo whichVar, tOptDesc * pOD)
+{
+# define _TT_(n) static char const z ## n [] = #n;
+ TEXTTO_TABLE
+# undef _TT_
+# define _TT_(n) z ## n ,
+ static char const * apzTTNames[] = { TEXTTO_TABLE };
+# undef _TT_
+
+#if ! defined(HAVE_WORKING_FORK)
+ printf(SET_NO_TEXT_FMT, pOpts->pzPROGNAME, apzTTNames[ whichVar]);
+#else
+ int pipeFd[2];
+
+ fflush(stdout);
+ fflush(stderr);
+
+ if (pipe(pipeFd) != 0) {
+ fprintf(stderr, zBadPipe, errno, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ switch (fork()) {
+ case -1:
+ fprintf(stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
+ exit(EXIT_FAILURE);
+ break;
+
+ case 0:
+ /*
+ * Send both stderr and stdout to the pipe. No matter which
+ * descriptor is used, we capture the output on the read end.
+ */
+ dup2(pipeFd[1], STDERR_FILENO);
+ dup2(pipeFd[1], STDOUT_FILENO);
+ close(pipeFd[0]);
+
+ switch (whichVar) {
+ case TT_LONGUSAGE:
+ (*(pOpts->pUsageProc))(pOpts, EXIT_SUCCESS);
+ /* NOTREACHED */
+
+ case TT_USAGE:
+ (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
+ /* NOTREACHED */
+
+ case TT_VERSION:
+ if (pOD->fOptState & OPTST_ALLOC_ARG) {
+ AGFREE(pOD->optArg.argString);
+ pOD->fOptState &= ~OPTST_ALLOC_ARG;
+ }
+ pOD->optArg.argString = "c";
+ optionPrintVersion(pOpts, pOD);
+ /* NOTREACHED */
+
+ default:
+ exit(EXIT_FAILURE);
+ }
+
+ default:
+ close(pipeFd[1]);
+ }
+
+ emit_var_text(pOpts->pzPROGNAME, apzTTNames[whichVar], pipeFd[0]);
+#endif
+}
+
+
+static void
+emit_usage(tOptions * pOpts)
+{
+ char zTimeBuf[AO_NAME_SIZE];
+
+ /*
+ * First, switch stdout to the output file name.
+ * Then, change the program name to the one defined
+ * by the definitions (rather than the current
+ * executable name). Down case the upper cased name.
+ */
+ if (script_leader != NULL)
+ fputs(script_leader, stdout);
+
+ {
+ char const * out_nm;
+
+ {
+ time_t c_tim = time(NULL);
+ struct tm * ptm = localtime(&c_tim);
+ strftime(zTimeBuf, AO_NAME_SIZE, TIME_FMT, ptm );
+ }
+
+ if (HAVE_GENSHELL_OPT(SCRIPT))
+ out_nm = GENSHELL_OPT_ARG(SCRIPT);
+ else out_nm = STDOUT;
+
+ if ((script_leader == NULL) && (shell_prog != NULL))
+ printf(SHELL_MAGIC, shell_prog);
+
+ printf(PREAMBLE_FMT, START_MARK, out_nm, zTimeBuf);
+ }
+
+ printf(END_PRE_FMT, pOpts->pzPROGNAME);
+
+ /*
+ * Get a copy of the original program name in lower case and
+ * fill in an approximation of the program name from it.
+ */
+ {
+ char * pzPN = zTimeBuf;
+ char const * pz = pOpts->pzPROGNAME;
+ char ** pp;
+
+ for (;;) {
+ if ((*pzPN++ = (char)tolower(*pz++)) == NUL)
+ break;
+ }
+
+ pp = (char **)(void *)&(pOpts->pzProgPath);
+ *pp = zTimeBuf;
+ pp = (char **)(void *)&(pOpts->pzProgName);
+ *pp = zTimeBuf;
+ }
+
+ text_to_var(pOpts, TT_LONGUSAGE, NULL);
+ text_to_var(pOpts, TT_USAGE, NULL);
+
+ {
+ tOptDesc* pOptDesc = pOpts->pOptDesc;
+ int optionCt = pOpts->optCt;
+
+ for (;;) {
+ if (pOptDesc->pOptProc == optionPrintVersion) {
+ text_to_var(pOpts, TT_VERSION, pOptDesc);
+ break;
+ }
+
+ if (--optionCt <= 0)
+ break;
+ pOptDesc++;
+ }
+ }
+}
+
+
+static void
+emit_setup(tOptions * pOpts)
+{
+ tOptDesc * pOptDesc = pOpts->pOptDesc;
+ int optionCt = pOpts->presetOptCt;
+ char const * pzFmt;
+ char const * pzDefault;
+
+ for (;optionCt > 0; pOptDesc++, --optionCt) {
+ char zVal[32];
+
+ /*
+ * Options that are either usage documentation or are compiled out
+ * are not to be processed.
+ */
+ if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
+ continue;
+
+ if (pOptDesc->optMaxCt > 1)
+ pzFmt = MULTI_DEF_FMT;
+ else pzFmt = SGL_DEF_FMT;
+
+ /*
+ * IF this is an enumeration/bitmask option, then convert the value
+ * to a string before printing the default value.
+ */
+ switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) {
+ case OPARG_TYPE_ENUMERATION:
+ (*(pOptDesc->pOptProc))(OPTPROC_EMIT_SHELL, pOptDesc );
+ pzDefault = pOptDesc->optArg.argString;
+ break;
+
+ /*
+ * Numeric and membership bit options are just printed as a number.
+ */
+ case OPARG_TYPE_NUMERIC:
+ snprintf(zVal, sizeof(zVal), "%d",
+ (int)pOptDesc->optArg.argInt);
+ pzDefault = zVal;
+ break;
+
+ case OPARG_TYPE_MEMBERSHIP:
+ snprintf(zVal, sizeof(zVal), "%lu",
+ (unsigned long)pOptDesc->optArg.argIntptr);
+ pzDefault = zVal;
+ break;
+
+ case OPARG_TYPE_BOOLEAN:
+ pzDefault = (pOptDesc->optArg.argBool) ? TRUE_STR : FALSE_STR;
+ break;
+
+ default:
+ if (pOptDesc->optArg.argString == NULL) {
+ if (pzFmt == SGL_DEF_FMT)
+ pzFmt = SGL_NO_DEF_FMT;
+ pzDefault = NULL;
+ }
+ else
+ pzDefault = pOptDesc->optArg.argString;
+ }
+
+ printf(pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault);
+ }
+}
+
+static void
+emit_action(tOptions * pOpts, tOptDesc* pOptDesc)
+{
+ if (pOptDesc->pOptProc == optionPrintVersion)
+ printf(zTextExit, pOpts->pzPROGNAME, VER_STR);
+
+ else if (pOptDesc->pOptProc == optionPagedUsage)
+ printf(zPagedUsageExit, pOpts->pzPROGNAME);
+
+ else if (pOptDesc->pOptProc == optionLoadOpt) {
+ printf(zCmdFmt, NO_LOAD_WARN);
+ printf(zCmdFmt, YES_NEED_OPT_ARG);
+
+ } else if (pOptDesc->pz_NAME == NULL) {
+
+ if (pOptDesc->pOptProc == NULL) {
+ printf(zCmdFmt, NO_SAVE_OPTS);
+ printf(zCmdFmt, OK_NEED_OPT_ARG);
+ } else
+ printf(zTextExit, pOpts->pzPROGNAME, LONG_USE_STR);
+
+ } else {
+ if (pOptDesc->optMaxCt == 1)
+ printf(SGL_ARG_FMT, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
+ else {
+ if ((unsigned)pOptDesc->optMaxCt < NOLIMIT)
+ printf(zCountTest, pOpts->pzPROGNAME,
+ pOptDesc->pz_NAME, pOptDesc->optMaxCt);
+
+ printf(MULTI_ARG_FMT, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
+ }
+
+ /*
+ * Fix up the args.
+ */
+ if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
+ printf(zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
+
+ } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
+ printf(zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
+
+ } else {
+ fputs(zMustArg, stdout);
+ }
+ }
+ fputs(zOptionEndSelect, stdout);
+}
+
+
+static void
+emit_inaction(tOptions * pOpts, tOptDesc* pOptDesc)
+{
+ if (pOptDesc->pOptProc == optionLoadOpt) {
+ printf(zCmdFmt, NO_SUPPRESS_LOAD);
+
+ } else if (pOptDesc->optMaxCt == 1)
+ printf(NO_SGL_ARG_FMT, pOpts->pzPROGNAME,
+ pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx);
+ else
+ printf(NO_MULTI_ARG_FMT, pOpts->pzPROGNAME,
+ pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx);
+
+ printf(zCmdFmt, NO_ARG_NEEDED);
+ fputs(zOptionEndSelect, stdout);
+}
+
+
+static void
+emit_flag(tOptions * pOpts)
+{
+ tOptDesc* pOptDesc = pOpts->pOptDesc;
+ int optionCt = pOpts->optCt;
+
+ fputs(zOptionCase, stdout);
+
+ for (;optionCt > 0; pOptDesc++, --optionCt) {
+
+ if (SKIP_OPT(pOptDesc))
+ continue;
+
+ if (IS_GRAPHIC_CHAR(pOptDesc->optValue)) {
+ printf(zOptionFlag, pOptDesc->optValue);
+ emit_action(pOpts, pOptDesc);
+ }
+ }
+ printf(UNK_OPT_FMT, FLAG_STR, pOpts->pzPROGNAME);
+}
+
+
+/*
+ * Emit the match text for a long option
+ */
+static void
+emit_match_expr(char const * pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts)
+{
+ tOptDesc* pOD = pOpts->pOptDesc;
+ int oCt = pOpts->optCt;
+ int min = 1;
+ char zName[ 256 ];
+ char* pz = zName;
+
+ for (;;) {
+ int matchCt = 0;
+
+ /*
+ * Omit the current option, Documentation opts and compiled out opts.
+ */
+ if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
+ if (--oCt <= 0)
+ break;
+ pOD++;
+ continue;
+ }
+
+ /*
+ * Check each character of the name case insensitively.
+ * They must not be the same. They cannot be, because it would
+ * not compile correctly if they were.
+ */
+ while ( toupper(pOD->pz_Name[matchCt])
+ == toupper(pzMatchName[matchCt]))
+ matchCt++;
+
+ if (matchCt > min)
+ min = matchCt;
+
+ /*
+ * Check the disablement name, too.
+ */
+ if (pOD->pz_DisableName != NULL) {
+ matchCt = 0;
+ while ( toupper(pOD->pz_DisableName[matchCt])
+ == toupper(pzMatchName[matchCt]))
+ matchCt++;
+ if (matchCt > min)
+ min = matchCt;
+ }
+ if (--oCt <= 0)
+ break;
+ pOD++;
+ }
+
+ /*
+ * IF the 'min' is all or one short of the name length,
+ * THEN the entire string must be matched.
+ */
+ if ( (pzMatchName[min ] == NUL)
+ || (pzMatchName[min+1] == NUL) )
+ printf(zOptionFullName, pzMatchName);
+
+ else {
+ int matchCt = 0;
+ for (; matchCt <= min; matchCt++)
+ *pz++ = pzMatchName[matchCt];
+
+ for (;;) {
+ *pz = NUL;
+ printf(zOptionPartName, zName);
+ *pz++ = pzMatchName[matchCt++];
+ if (pzMatchName[matchCt] == NUL) {
+ *pz = NUL;
+ printf(zOptionFullName, zName);
+ break;
+ }
+ }
+ }
+}
+
+
+/**
+ * Emit GNU-standard long option handling code.
+ */
+static void
+emit_long(tOptions * pOpts)
+{
+ tOptDesc* pOD = pOpts->pOptDesc;
+ int ct = pOpts->optCt;
+
+ fputs(zOptionCase, stdout);
+
+ /*
+ * do each option, ...
+ */
+ do {
+ /*
+ * Documentation & compiled-out options
+ */
+ if (SKIP_OPT(pOD))
+ continue;
+
+ emit_match_expr(pOD->pz_Name, pOD, pOpts);
+ emit_action(pOpts, pOD);
+
+ /*
+ * Now, do the same thing for the disablement version of the option.
+ */
+ if (pOD->pz_DisableName != NULL) {
+ emit_match_expr(pOD->pz_DisableName, pOD, pOpts);
+ emit_inaction(pOpts, pOD);
+ }
+ } while (pOD++, --ct > 0);
+
+ printf(UNK_OPT_FMT, OPTION_STR, pOpts->pzPROGNAME);
+}
+
+/**
+ * Load the previous shell script output file. We need to preserve any
+ * hand-edited additions outside of the START_MARK and END_MARKs.
+ *
+ * @param[in] fname the output file name
+ */
+static char *
+load_old_output(char const * fname)
+{
+ /*
+ * IF we cannot stat the file,
+ * THEN assume we are creating a new file.
+ * Skip the loading of the old data.
+ */
+ FILE * fp = fopen(fname, "r" FOPEN_BINARY_FLAG);
+ struct stat stbf;
+ char * text;
+ char * scan;
+
+ if (fp == NULL)
+ return NULL;
+
+ /*
+ * If we opened it, we should be able to stat it and it needs
+ * to be a regular file
+ */
+ if ((fstat(fileno(fp), &stbf) != 0) || (! S_ISREG(stbf.st_mode))) {
+ fprintf(stderr, zNotFile, fname);
+ exit(EXIT_FAILURE);
+ }
+
+ scan = text = AGALOC(stbf.st_size + 1, "f data");
+
+ /*
+ * Read in all the data as fast as our OS will let us.
+ */
+ for (;;) {
+ int inct = fread((void*)scan, (size_t)1, stbf.st_size, fp);
+ if (inct == 0)
+ break;
+
+ stbf.st_size -= inct;
+
+ if (stbf.st_size == 0)
+ break;
+
+ scan += inct;
+ }
+
+ *scan = NUL;
+ fclose(fp);
+
+ return text;
+}
+
+/**
+ * Open the specified output file. If it already exists, load its
+ * contents and save the non-generated (hand edited) portions.
+ * If a "start mark" is found, everything before it is preserved leader.
+ * If not, the entire thing is a trailer. Assuming the start is found,
+ * then everything after the end marker is the trailer. If the end
+ * mark is not found, the file is actually corrupt, but we take the
+ * remainder to be the trailer.
+ *
+ * @param[in] fname the output file name
+ */
+static void
+open_out(char const * fname)
+{
+
+ do {
+ char * txt = script_text = load_old_output(fname);
+ char * scn;
+
+ if (txt == NULL)
+ break;
+
+ scn = strstr(txt, START_MARK);
+ if (scn == NULL) {
+ script_trailer = txt;
+ break;
+ }
+
+ *(scn++) = NUL;
+ scn = strstr(scn, END_MARK);
+ if (scn == NULL) {
+ /*
+ * The file is corrupt.
+ */
+ script_trailer = txt + strlen(txt) + START_MARK_LEN + 1;
+ break;
+ }
+
+ /*
+ * Check to see if the data contains our marker.
+ * If it does, then we will skip over it
+ */
+ script_trailer = scn + END_MARK_LEN;
+ script_leader = txt;
+ } while (false);
+
+ if (freopen(fname, "w" FOPEN_BINARY_FLAG, stdout) != stdout) {
+ fprintf(stderr, zFreopenFail, errno, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+/*=export_func genshelloptUsage
+ * private:
+ * what: The usage function for the genshellopt generated program
+ *
+ * arg: + tOptions* + pOpts + program options descriptor +
+ * arg: + int + exitCode + usage text type to produce +
+ *
+ * doc:
+ * This function is used to create the usage strings for the option
+ * processing shell script code. Two child processes are spawned
+ * each emitting the usage text in either the short (error exit)
+ * style or the long style. The generated program will capture this
+ * and create shell script variables containing the two types of text.
+=*/
+void
+genshelloptUsage(tOptions * pOpts, int exitCode)
+{
+#if ! defined(HAVE_WORKING_FORK)
+ optionUsage(pOpts, exitCode);
+#else
+ /*
+ * IF not EXIT_SUCCESS,
+ * THEN emit the short form of usage.
+ */
+ if (exitCode != EXIT_SUCCESS)
+ optionUsage(pOpts, exitCode);
+ fflush(stderr);
+ fflush(stdout);
+ if (ferror(stdout) || ferror(stderr))
+ exit(EXIT_FAILURE);
+
+ option_usage_fp = stdout;
+
+ /*
+ * First, print our usage
+ */
+ switch (fork()) {
+ case -1:
+ optionUsage(pOpts, EXIT_FAILURE);
+ /* NOTREACHED */
+
+ case 0:
+ pagerState = PAGER_STATE_CHILD;
+ optionUsage(pOpts, EXIT_SUCCESS);
+ /* NOTREACHED */
+ _exit(EXIT_FAILURE);
+
+ default:
+ {
+ int sts;
+ wait(&sts);
+ }
+ }
+
+ /*
+ * Generate the pzProgName, since optionProcess() normally
+ * gets it from the command line
+ */
+ {
+ char * pz;
+ char ** pp = (char **)(void *)&(optionParseShellOptions->pzProgName);
+ AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name");
+ *pp = pz;
+ while (*pz != NUL) {
+ *pz = tolower(*pz);
+ pz++;
+ }
+ }
+
+ /*
+ * Separate the makeshell usage from the client usage
+ */
+ fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName);
+ fflush(option_usage_fp);
+
+ /*
+ * Now, print the client usage.
+ */
+ switch (fork()) {
+ case 0:
+ pagerState = PAGER_STATE_CHILD;
+ /*FALLTHROUGH*/
+ case -1:
+ optionUsage(optionParseShellOptions, EXIT_FAILURE);
+
+ default:
+ {
+ int sts;
+ wait(&sts);
+ }
+ }
+
+ fflush(stdout);
+ if (ferror(stdout)) {
+ fputs(zOutputFail, stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+#endif
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-file-style: "stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * end of autoopts/makeshell.c */