123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956 |
- /**
- * \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-2016 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
- */
- static inline unsigned char to_uchar (char ch) { return ch; }
- #define UPPER(_c) (toupper(to_uchar(_c)))
- #define LOWER(_c) (tolower(to_uchar(_c)))
- /* = = = 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 = VOIDP(&(opts->pzProgPath));
- *pp = tm_nm_buf;
- pp = VOIDP(&(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 (UPPER(od->pz_Name[match_ct]) == UPPER(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(VOIDP(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 = VOIDP(&(optionParseShellOptions->pzProgName));
- AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name");
- *pp = pz;
- while (*pz != NUL) {
- *pz = (char)LOWER(*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 */
|