diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-12-02 09:01:21 +0000 |
---|---|---|
committer | <> | 2014-12-04 16:11:25 +0000 |
commit | bdab5265fcbf3f472545073a23f8999749a9f2b9 (patch) | |
tree | c6018dd03dea906f8f1fb5f105f05b71a7dc250a /sntp/libopts/makeshell.c | |
download | ntp-bdab5265fcbf3f472545073a23f8999749a9f2b9.tar.gz |
Imported from /home/lorry/working-area/delta_ntp/ntp-dev-4.2.7p482.tar.gz.ntp-dev-4.2.7p482
Diffstat (limited to 'sntp/libopts/makeshell.c')
-rw-r--r-- | sntp/libopts/makeshell.c | 951 |
1 files changed, 951 insertions, 0 deletions
diff --git a/sntp/libopts/makeshell.c b/sntp/libopts/makeshell.c new file mode 100644 index 0000000..a0bfcac --- /dev/null +++ b/sntp/libopts/makeshell.c @@ -0,0 +1,951 @@ + +/** + * \file makeshell.c + * + * This module will interpret the options set in the tOptions + * structure and create a Bourne shell script capable of parsing them. + * + * @addtogroup autoopts + * @{ + */ +/* + * This file is part of AutoOpts, a companion to AutoGen. + * AutoOpts is free software. + * AutoOpts is Copyright (C) 1992-2014 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 sha256 sums: + * + * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 + * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 + * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd + */ + +/* = = = START-STATIC-FORWARD = = = */ +static void +emit_var_text(char const * prog, char const * var, int fdin); + +static void +text_to_var(tOptions * opts, teTextTo which, tOptDesc * od); + +static void +emit_usage(tOptions * opts); + +static void +emit_wrapup(tOptions * opts); + +static void +emit_setup(tOptions * opts); + +static void +emit_action(tOptions * opts, tOptDesc * od); + +static void +emit_inaction(tOptions * opts, tOptDesc * od); + +static void +emit_flag(tOptions * opts); + +static void +emit_match_expr(char const * name, tOptDesc * cod, tOptions * opts); + +static void +emit_long(tOptions * opts); + +static char * +load_old_output(char const * fname, char const * pname); + +static void +open_out(char const * fname, char const * pname); +/* = = = END-STATIC-FORWARD = = = */ + +LOCAL noreturn void +option_exits(int exit_code) +{ + if (print_exit) + printf("\nexit %d\n", exit_code); + exit(exit_code); +} + +LOCAL noreturn void +ao_bug(char const * msg) +{ + fprintf(stderr, zao_bug_msg, msg); + option_exits(EX_SOFTWARE); +} + +LOCAL void +fserr_warn(char const * prog, char const * op, char const * fname) +{ + fprintf(stderr, zfserr_fmt, prog, errno, strerror(errno), + op, fname); +} + +LOCAL noreturn void +fserr_exit(char const * prog, char const * op, char const * fname) +{ + fserr_warn(prog, op, fname); + option_exits(EXIT_FAILURE); +} + +/*=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 * opts) +{ + /* + * 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), opts->pzProgName); + + emit_usage(opts); + emit_setup(opts); + + /* + * There are four modes of option processing. + */ + switch (opts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) { + case OPTPROC_LONGOPT: + fputs(LOOP_STR, stdout); + + fputs(LONG_OPT_MARK, stdout); + fputs(INIT_LOPT_STR, stdout); + emit_long(opts); + printf(LOPT_ARG_FMT, opts->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(opts); + printf(LOPT_ARG_FMT, opts->pzPROGNAME); + break; + + case OPTPROC_SHORTOPT: + fputs(LOOP_STR, stdout); + + fputs(FLAG_OPT_MARK, stdout); + fputs(INIT_OPT_STR, stdout); + emit_flag(opts); + printf(OPT_ARG_FMT, opts->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(opts); + printf(LOPT_ARG_FMT, opts->pzPROGNAME); + fputs(END_OPT_SEL_STR, stdout); + + fputs(FLAG_OPT_MARK, stdout); + fputs(INIT_OPT_STR, stdout); + emit_flag(opts); + printf(OPT_ARG_FMT, opts->pzPROGNAME); + fputs(END_OPT_SEL_STR, stdout); + + fputs(NOT_FOUND_STR, stdout); + break; + } + + emit_wrapup(opts); + if ((script_trailer != NULL) && (*script_trailer != NUL)) + fputs(script_trailer, stdout); + else if (ENABLED_GENSHELL_OPT(SHELL)) + printf(SHOW_PROG_ENV, opts->pzPROGNAME); + +#ifdef HAVE_FCHMOD + fchmod(STDOUT_FILENO, 0755); +#endif + fclose(stdout); + + if (ferror(stdout)) + fserr_exit(opts->pzProgName, zwriting, zstdout_name); + + AGFREE(script_text); + script_leader = NULL; + script_trailer = NULL; + script_text = NULL; +} + +#ifdef HAVE_WORKING_FORK +/** + * Print the value of "var" to a file descriptor. + * The "fdin" is the read end of a pipe to a forked process that + * is writing usage text to it. We read that text in and re-emit + * to standard out, formatting it so that it is assigned to a + * shell variable. + * + * @param[in] prog The capitalized, c-variable-formatted program name + * @param[in] var a similarly formatted type name + * (LONGUSAGE, USAGE or VERSION) + * @param[in] fdin the input end of a pipe + */ +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(apostrophe, stdout); + break; + + case EOF: + goto done; + + default: + while (nlct > 0) { + fputc(NL, stdout); + nlct--; + } + fputc(ch, stdout); + break; + } + } done:; + + 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. + * + * @param[in] opts the program options + * @param[in] which what to print: long usage, usage or version + * @param[in] od for TT_VERSION, it is the version option + */ +static void +text_to_var(tOptions * opts, teTextTo which, tOptDesc * od) +{ +# define _TT_(n) static char const z ## n [] = #n; + TEXTTO_TABLE +# undef _TT_ +# define _TT_(n) z ## n , + static char const * ttnames[] = { TEXTTO_TABLE }; +# undef _TT_ + +#if ! defined(HAVE_WORKING_FORK) + printf(SET_NO_TEXT_FMT, opts->pzPROGNAME, ttnames[which]); +#else + int fdpair[2]; + + fflush(stdout); + fflush(stderr); + + if (pipe(fdpair) != 0) + fserr_exit(opts->pzProgName, "pipe", zinter_proc_pipe); + + switch (fork()) { + case -1: + fserr_exit(opts->pzProgName, "fork", opts->pzProgName); + /* NOTREACHED */ + + 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(fdpair[1], STDERR_FILENO); + dup2(fdpair[1], STDOUT_FILENO); + close(fdpair[0]); + + switch (which) { + case TT_LONGUSAGE: + (*(opts->pUsageProc))(opts, EXIT_SUCCESS); + /* NOTREACHED */ + + case TT_USAGE: + (*(opts->pUsageProc))(opts, EXIT_FAILURE); + /* NOTREACHED */ + + case TT_VERSION: + if (od->fOptState & OPTST_ALLOC_ARG) { + AGFREE(od->optArg.argString); + od->fOptState &= ~OPTST_ALLOC_ARG; + } + od->optArg.argString = "c"; + optionPrintVersion(opts, od); + /* NOTREACHED */ + + default: + option_exits(EXIT_FAILURE); + /* NOTREACHED */ + } + /* NOTREACHED */ + + default: + close(fdpair[1]); + } + + emit_var_text(opts->pzPROGNAME, ttnames[which], fdpair[0]); +#endif +} + +/** + * capture usage text in shell variables. + * + */ +static void +emit_usage(tOptions * opts) +{ + char tm_nm_buf[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(tm_nm_buf, 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, tm_nm_buf); + } + + printf(END_PRE_FMT, opts->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 = tm_nm_buf; + char const * pz = opts->pzPROGNAME; + char ** pp; + + /* Copy the program name into the time/name buffer */ + for (;;) { + if ((*pzPN++ = (char)tolower(*pz++)) == NUL) + break; + } + + pp = (char **)(void *)&(opts->pzProgPath); + *pp = tm_nm_buf; + pp = (char **)(void *)&(opts->pzProgName); + *pp = tm_nm_buf; + } + + text_to_var(opts, TT_LONGUSAGE, NULL); + text_to_var(opts, TT_USAGE, NULL); + + { + tOptDesc* pOptDesc = opts->pOptDesc; + int optionCt = opts->optCt; + + for (;;) { + if (pOptDesc->pOptProc == optionPrintVersion) { + text_to_var(opts, TT_VERSION, pOptDesc); + break; + } + + if (--optionCt <= 0) + break; + pOptDesc++; + } + } +} + +static void +emit_wrapup(tOptions * opts) +{ + tOptDesc * od = opts->pOptDesc; + int opt_ct = opts->presetOptCt; + char const * fmt; + + printf(FINISH_LOOP, opts->pzPROGNAME); + for (;opt_ct > 0; od++, --opt_ct) { + /* + * Options that are either usage documentation or are compiled out + * are not to be processed. + */ + if (SKIP_OPT(od) || (od->pz_NAME == NULL)) + continue; + + /* + * do not presence check if there is no minimum/must-set + */ + if ((od->optMinCt == 0) && ((od->fOptState & OPTST_MUST_SET) == 0)) + continue; + + if (od->optMaxCt > 1) + fmt = CHK_MIN_COUNT; + else fmt = CHK_ONE_REQUIRED; + + { + int min = (od->optMinCt == 0) ? 1 : od->optMinCt; + printf(fmt, opts->pzPROGNAME, od->pz_NAME, min); + } + } + fputs(END_MARK, stdout); +} + +static void +emit_setup(tOptions * opts) +{ + tOptDesc * od = opts->pOptDesc; + int opt_ct = opts->presetOptCt; + char const * fmt; + char const * def_val; + + for (;opt_ct > 0; od++, --opt_ct) { + char int_val_buf[32]; + + /* + * Options that are either usage documentation or are compiled out + * are not to be processed. + */ + if (SKIP_OPT(od) || (od->pz_NAME == NULL)) + continue; + + if (od->optMaxCt > 1) + fmt = MULTI_DEF_FMT; + else fmt = 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(od->fOptState)) { + case OPARG_TYPE_ENUMERATION: + (*(od->pOptProc))(OPTPROC_EMIT_SHELL, od ); + def_val = od->optArg.argString; + break; + + /* + * Numeric and membership bit options are just printed as a number. + */ + case OPARG_TYPE_NUMERIC: + snprintf(int_val_buf, sizeof(int_val_buf), "%d", + (int)od->optArg.argInt); + def_val = int_val_buf; + break; + + case OPARG_TYPE_MEMBERSHIP: + snprintf(int_val_buf, sizeof(int_val_buf), "%lu", + (unsigned long)od->optArg.argIntptr); + def_val = int_val_buf; + break; + + case OPARG_TYPE_BOOLEAN: + def_val = (od->optArg.argBool) ? TRUE_STR : FALSE_STR; + break; + + default: + if (od->optArg.argString == NULL) { + if (fmt == SGL_DEF_FMT) + fmt = SGL_NO_DEF_FMT; + def_val = NULL; + } + else + def_val = od->optArg.argString; + } + + printf(fmt, opts->pzPROGNAME, od->pz_NAME, def_val); + } +} + +static void +emit_action(tOptions * opts, tOptDesc * od) +{ + if (od->pOptProc == optionPrintVersion) + printf(ECHO_N_EXIT, opts->pzPROGNAME, VER_STR); + + else if (od->pOptProc == optionPagedUsage) + printf(PAGE_USAGE_TEXT, opts->pzPROGNAME); + + else if (od->pOptProc == optionLoadOpt) { + printf(LVL3_CMD, NO_LOAD_WARN); + printf(LVL3_CMD, YES_NEED_OPT_ARG); + + } else if (od->pz_NAME == NULL) { + + if (od->pOptProc == NULL) { + printf(LVL3_CMD, NO_SAVE_OPTS); + printf(LVL3_CMD, OK_NEED_OPT_ARG); + } else + printf(ECHO_N_EXIT, opts->pzPROGNAME, LONG_USE_STR); + + } else { + if (od->optMaxCt == 1) + printf(SGL_ARG_FMT, opts->pzPROGNAME, od->pz_NAME); + else { + if ((unsigned)od->optMaxCt < NOLIMIT) + printf(CHK_MAX_COUNT, opts->pzPROGNAME, + od->pz_NAME, od->optMaxCt); + + printf(MULTI_ARG_FMT, opts->pzPROGNAME, od->pz_NAME); + } + + /* + * Fix up the args. + */ + if (OPTST_GET_ARGTYPE(od->fOptState) == OPARG_TYPE_NONE) { + printf(SET_MULTI_ARG, opts->pzPROGNAME, od->pz_NAME); + printf(LVL3_CMD, NO_ARG_NEEDED); + + } else if (od->fOptState & OPTST_ARG_OPTIONAL) { + printf(SET_MULTI_ARG, opts->pzPROGNAME, od->pz_NAME); + printf(LVL3_CMD, OK_NEED_OPT_ARG); + + } else { + printf(LVL3_CMD, YES_NEED_OPT_ARG); + } + } + fputs(zOptionEndSelect, stdout); +} + +static void +emit_inaction(tOptions * opts, tOptDesc * od) +{ + if (od->pOptProc == optionLoadOpt) { + printf(LVL3_CMD, NO_SUPPRESS_LOAD); + + } else if (od->optMaxCt == 1) + printf(NO_SGL_ARG_FMT, opts->pzPROGNAME, + od->pz_NAME, od->pz_DisablePfx); + else + printf(NO_MULTI_ARG_FMT, opts->pzPROGNAME, + od->pz_NAME, od->pz_DisablePfx); + + printf(LVL3_CMD, NO_ARG_NEEDED); + fputs(zOptionEndSelect, stdout); +} + +/** + * recognize flag options. These go at the end. + * At the end, emit code to handle options we don't recognize. + * + * @param[in] opts the program options + */ +static void +emit_flag(tOptions * opts) +{ + tOptDesc* od = opts->pOptDesc; + int opt_ct = opts->optCt; + + fputs(zOptionCase, stdout); + + for (;opt_ct > 0; od++, --opt_ct) { + + if (SKIP_OPT(od) || ! IS_GRAPHIC_CHAR(od->optValue)) + continue; + + printf(zOptionFlag, od->optValue); + emit_action(opts, od); + } + printf(UNK_OPT_FMT, FLAG_STR, opts->pzPROGNAME); +} + +/** + * Emit the match text for a long option. The passed in \a name may be + * either the enablement name or the disablement name. + * + * @param[in] name The current name to check. + * @param[in] cod current option descriptor + * @param[in] opts the program options + */ +static void +emit_match_expr(char const * name, tOptDesc * cod, tOptions * opts) +{ + char name_bf[32]; + unsigned int min_match_ct = 2; + unsigned int max_match_ct = strlen(name) - 1; + + if (max_match_ct >= sizeof(name_bf) - 1) + goto leave; + + { + tOptDesc * od = opts->pOptDesc; + int ct = opts->optCt; + + for (; ct-- > 0; od++) { + unsigned int match_ct = 0; + + /* + * Omit the current option, Doc opts and compiled out opts. + */ + if ((od == cod) || SKIP_OPT(od)) + 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(od->pz_Name[match_ct]) == toupper(name[match_ct])) + match_ct++; + + if (match_ct > min_match_ct) + min_match_ct = match_ct; + + /* + * Check the disablement name, too. + */ + if (od->pz_DisableName == NULL) + continue; + + match_ct = 0; + while ( toupper(od->pz_DisableName[match_ct]) + == toupper(name[match_ct])) + match_ct++; + if (match_ct > min_match_ct) + min_match_ct = match_ct; + } + } + + /* + * Don't bother emitting partial matches if there is only one possible + * partial match. + */ + if (min_match_ct < max_match_ct) { + char * pz = name_bf + min_match_ct; + int nm_ix = min_match_ct; + + memcpy(name_bf, name, min_match_ct); + + for (;;) { + *pz = NUL; + printf(zOptionPartName, name_bf); + *pz++ = name[nm_ix++]; + if (name[nm_ix] == NUL) { + *pz = NUL; + break; + } + } + } + +leave: + printf(zOptionFullName, name); +} + +/** + * Emit GNU-standard long option handling code. + * + * @param[in] opts the program options + */ +static void +emit_long(tOptions * opts) +{ + tOptDesc * od = opts->pOptDesc; + int ct = opts->optCt; + + fputs(zOptionCase, stdout); + + /* + * do each option, ... + */ + do { + /* + * Documentation & compiled-out options + */ + if (SKIP_OPT(od)) + continue; + + emit_match_expr(od->pz_Name, od, opts); + emit_action(opts, od); + + /* + * Now, do the same thing for the disablement version of the option. + */ + if (od->pz_DisableName != NULL) { + emit_match_expr(od->pz_DisableName, od, opts); + emit_inaction(opts, od); + } + } while (od++, --ct > 0); + + printf(UNK_OPT_FMT, OPTION_STR, opts->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, char const * pname) +{ + /* + * 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))) + fserr_exit(pname, "fstat", fname); + + scan = text = AGALOC(stbf.st_size + 1, "f data"); + + /* + * Read in all the data as fast as our OS will let us. + */ + for (;;) { + size_t inct = fread((void*)scan, 1, (size_t)stbf.st_size, fp); + if (inct == 0) + break; + + stbf.st_size -= (ssize_t)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, char const * pname) +{ + + do { + char * txt = script_text = load_old_output(fname, pname); + 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. Set the trailer to be everything + * after the start mark. The user will need to fix it up. + */ + 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) + fserr_exit(pname, "freopen", fname); +} + +/*=export_func genshelloptUsage + * private: + * what: The usage function for the genshellopt generated program + * + * arg: + tOptions* + opts + program options descriptor + + * arg: + int + exit_cd + 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 * opts, int exit_cd) +{ +#if ! defined(HAVE_WORKING_FORK) + optionUsage(opts, exit_cd); +#else + /* + * IF not EXIT_SUCCESS, + * THEN emit the short form of usage. + */ + if (exit_cd != EXIT_SUCCESS) + optionUsage(opts, exit_cd); + fflush(stderr); + fflush(stdout); + if (ferror(stdout) || ferror(stderr)) + option_exits(EXIT_FAILURE); + + option_usage_fp = stdout; + + /* + * First, print our usage + */ + switch (fork()) { + case -1: + optionUsage(opts, EXIT_FAILURE); + /* NOTREACHED */ + + case 0: + pagerState = PAGER_STATE_CHILD; + optionUsage(opts, 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 = (char)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)) + fserr_exit(opts->pzProgName, zwriting, zstdout_name); + + option_exits(EXIT_SUCCESS); +#endif +} + +/** @} + * + * Local Variables: + * mode: C + * c-file-style: "stroustrup" + * indent-tabs-mode: nil + * End: + * end of autoopts/makeshell.c */ |