diff options
Diffstat (limited to 'contrib/ntp/sntp/libopts/makeshell.c')
-rw-r--r-- | contrib/ntp/sntp/libopts/makeshell.c | 1314 |
1 files changed, 574 insertions, 740 deletions
diff --git a/contrib/ntp/sntp/libopts/makeshell.c b/contrib/ntp/sntp/libopts/makeshell.c index 8447d45..a61df42 100644 --- a/contrib/ntp/sntp/libopts/makeshell.c +++ b/contrib/ntp/sntp/libopts/makeshell.c @@ -1,606 +1,364 @@ -/* - * $Id: makeshell.c,v 4.20 2007/02/04 17:44:12 bkorb Exp $ - * Time-stamp: "2007-01-27 06:05:45 bkorb" +/** + * \file makeshell.c * * This module will interpret the options set in the tOptions * structure and create a Bourne shell script capable of parsing them. - */ - -/* - * Automated Options copyright 1992-2007 Bruce Korb - * - * Automated Options is free software. - * You may redistribute it and/or modify it under the terms of the - * GNU General Public License, as published by the Free Software - * Foundation; either version 2, or (at your option) any later version. - * - * Automated Options is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Automated Options. See the file "COPYING". If not, - * write to: The Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. * - * As a special exception, Bruce Korb gives permission for additional - * uses of the text contained in his release of AutoOpts. - * - * The exception is that, if you link the AutoOpts library with other - * files to produce an executable, this does not by itself cause the - * resulting executable to be covered by the GNU General Public License. - * Your use of that executable is in no way restricted on account of - * linking the AutoOpts library code into it. - * - * This exception does not however invalidate any other reasons why - * the executable file might be covered by the GNU General Public License. - * - * This exception applies only to the code released by Bruce Korb under - * the name AutoOpts. If you copy code from other sources under the - * General Public License into a copy of AutoOpts, as the General Public - * License permits, the exception does not apply to the code that you add - * in this way. To avoid misleading anyone as to the status of such - * modified files, you must delete this exception notice from them. - * - * If you write modifications of your own for AutoOpts, it is your choice - * whether to permit this exception to apply to your modifications. - * If you do not wish that, delete this exception notice. + * @addtogroup autoopts + * @{ */ - -tOptions* pShellParseOptions = NULL; - -/* * * * * * * * * * * * * * * * * * * * * - * - * Setup Format Strings - */ -tSCC zStartMarker[] = -"# # # # # # # # # # -- do not modify this marker --\n#\n" -"# DO NOT EDIT THIS SECTION"; - -tSCC zPreamble[] = -"%s OF %s\n#\n" -"# From here to the next `-- do not modify this marker --',\n" -"# the text has been generated %s\n"; - -tSCC zEndPreamble[] = -"# From the %s option definitions\n#\n"; - -tSCC zMultiDef[] = "\n" -"if test -z \"${%1$s_%2$s}\"\n" -"then\n" -" %1$s_%2$s_CT=0\n" -"else\n" -" %1$s_%2$s_CT=1\n" -" %1$s_%2$s_1=\"${%1$s_%2$s}\"\n" -"fi\n" -"export %1$s_%2$s_CT"; - -tSCC zSingleDef[] = "\n" -"%1$s_%2$s=\"${%1$s_%2$s-'%3$s'}\"\n" -"%1$s_%2$s_set=false\n" -"export %1$s_%2$s\n"; - -tSCC zSingleNoDef[] = "\n" -"%1$s_%2$s=\"${%1$s_%2$s}\"\n" -"%1$s_%2$s_set=false\n" -"export %1$s_%2$s\n"; - -/* * * * * * * * * * * * * * * * * * * * * - * - * LOOP START +/* + * This file is part of AutoOpts, a companion to AutoGen. + * AutoOpts is free software. + * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved * - * The loop may run in either of two modes: - * all options are named options (loop only) - * regular, marked option processing. - */ -tSCC zLoopCase[] = "\n" -"OPT_PROCESS=true\n" -"OPT_ARG=\"$1\"\n\n" -"while ${OPT_PROCESS} && [ $# -gt 0 ]\ndo\n" -" OPT_ELEMENT=''\n" -" OPT_ARG_VAL=''\n\n" - /* - * 'OPT_ARG' may or may not match the current $1 - */ -" case \"${OPT_ARG}\" in\n" -" -- )\n" -" OPT_PROCESS=false\n" -" shift\n" -" ;;\n\n"; - -tSCC zLoopOnly[] = "\n" -"OPT_ARG=\"$1\"\n\n" -"while [ $# -gt 0 ]\ndo\n" -" OPT_ELEMENT=''\n" -" OPT_ARG_VAL=''\n\n" -" OPT_ARG=\"${1}\"\n"; - -/* * * * * * * * * * * * * * * * + * 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. * - * CASE SELECTORS + * The GNU Lesser General Public License, version 3 or later + * See the files "COPYING.lgplv3" and "COPYING.gplv3" * - * If the loop runs as a regular option loop, - * then we must have selectors for each acceptable option - * type (long option, flag character and non-option) - */ -tSCC zLongSelection[] = -" --* )\n"; - -tSCC zFlagSelection[] = -" -* )\n"; - -tSCC zEndSelection[] = -" ;;\n\n"; - -tSCC zNoSelection[] = -" * )\n" -" OPT_PROCESS=false\n" -" ;;\n" -" esac\n\n"; - -/* * * * * * * * * * * * * * * * + * The Modified Berkeley Software Distribution License + * See the file "COPYING.mbsd" * - * LOOP END - */ -tSCC zLoopEnd[] = -" if [ -n \"${OPT_ARG_VAL}\" ]\n" -" then\n" -" eval %1$s_${OPT_NAME}${OPT_ELEMENT}=\"'${OPT_ARG_VAL}'\"\n" -" export %1$s_${OPT_NAME}${OPT_ELEMENT}\n" -" fi\n" -"done\n\n" -"unset OPT_PROCESS || :\n" -"unset OPT_ELEMENT || :\n" -"unset OPT_ARG || :\n" -"unset OPT_ARG_NEEDED || :\n" -"unset OPT_NAME || :\n" -"unset OPT_CODE || :\n" -"unset OPT_ARG_VAL || :\n%2$s"; - -tSCC zTrailerMarker[] = "\n" -"# # # # # # # # # #\n#\n" -"# END OF AUTOMATED OPTION PROCESSING\n" -"#\n# # # # # # # # # # -- do not modify this marker --\n"; - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * These files have the following sha256 sums: * - * OPTION SELECTION + * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 + * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 + * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd */ -tSCC zOptionCase[] = -" case \"${OPT_CODE}\" in\n"; - -tSCC zOptionPartName[] = -" '%s' | \\\n"; -tSCC zOptionFullName[] = -" '%s' )\n"; + static inline unsigned char to_uchar (char ch) { return ch; } -tSCC zOptionFlag[] = -" '%c' )\n"; +#define UPPER(_c) (toupper(to_uchar(_c))) +#define LOWER(_c) (tolower(to_uchar(_c))) -tSCC zOptionEndSelect[] = -" ;;\n\n"; - -tSCC zOptionUnknown[] = -" * )\n" -" echo Unknown %s: \"${OPT_CODE}\" >&2\n" -" echo \"$%s_USAGE_TEXT\"\n" -" exit 1\n" -" ;;\n" -" esac\n\n"; +/* = = = START-STATIC-FORWARD = = = */ +static void +emit_var_text(char const * prog, char const * var, int fdin); -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * - * OPTION PROCESSING - * - * Formats for emitting the text for handling particular options - */ -tSCC zTextExit[] = -" echo \"$%s_%s_TEXT\"\n" -" exit 0\n"; - -tSCC zPagedUsageExit[] = -" echo \"$%s_LONGUSAGE_TEXT\" | ${PAGER-more}\n" -" exit 0\n"; - -tSCC zCmdFmt[] = -" %s\n"; - -tSCC zCountTest[] = -" if [ $%1$s_%2$s_CT -ge %3$d ] ; then\n" -" echo Error: more than %3$d %2$s options >&2\n" -" echo \"$%1$s_USAGE_TEXT\"\n" -" exit 1 ; fi\n"; - -tSCC zMultiArg[] = -" %1$s_%2$s_CT=`expr ${%1$s_%2$s_CT} + 1`\n" -" OPT_ELEMENT=\"_${%1$s_%2$s_CT}\"\n" -" OPT_NAME='%2$s'\n"; - -tSCC zSingleArg[] = -" if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n" -" echo Error: duplicate %2$s option >&2\n" -" echo \"$%1$s_USAGE_TEXT\"\n" -" exit 1 ; fi\n" -" %1$s_%2$s_set=true\n" -" OPT_NAME='%2$s'\n"; - -tSCC zNoMultiArg[] = -" %1$s_%2$s_CT=0\n" -" OPT_ELEMENT=''\n" -" %1$s_%2$s='%3$s'\n" -" export %1$s_%2$s\n" -" OPT_NAME='%2$s'\n"; - -tSCC zNoSingleArg[] = -" if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n" -" echo Error: duplicate %2$s option >&2\n" -" echo \"$%1$s_USAGE_TEXT\"\n" -" exit 1 ; fi\n" -" %1$s_%2$s_set=true\n" -" %1$s_%2$s='%3$s'\n" -" export %1$s_%2$s\n" -" OPT_NAME='%2$s'\n"; - -tSCC zMayArg[] = -" eval %1$s_%2$s${OPT_ELEMENT}=true\n" -" export %1$s_%2$s${OPT_ELEMENT}\n" -" OPT_ARG_NEEDED=OK\n"; - -tSCC zMustArg[] = -" OPT_ARG_NEEDED=YES\n"; - -tSCC zCantArg[] = -" eval %1$s_%2$s${OPT_ELEMENT}=true\n" -" export %1$s_%2$s${OPT_ELEMENT}\n" -" OPT_ARG_NEEDED=NO\n"; - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * - * LONG OPTION PROCESSING - * - * Formats for emitting the text for handling long option types - */ -tSCC zLongOptInit[] = -" OPT_CODE=`echo \"X${OPT_ARG}\"|sed 's/^X-*//'`\n" -" shift\n" -" OPT_ARG=\"$1\"\n\n" -" case \"${OPT_CODE}\" in *=* )\n" -" OPT_ARG_VAL=`echo \"${OPT_CODE}\"|sed 's/^[^=]*=//'`\n" -" OPT_CODE=`echo \"${OPT_CODE}\"|sed 's/=.*$//'` ;; esac\n\n"; - -tSCC zLongOptArg[] = -" case \"${OPT_ARG_NEEDED}\" in\n" -" NO )\n" -" OPT_ARG_VAL=''\n" -" ;;\n\n" -" YES )\n" -" if [ -z \"${OPT_ARG_VAL}\" ]\n" -" then\n" -" if [ $# -eq 0 ]\n" -" then\n" -" echo No argument provided for ${OPT_NAME} option >&2\n" -" echo \"$%s_USAGE_TEXT\"\n" -" exit 1\n" -" fi\n\n" -" OPT_ARG_VAL=\"${OPT_ARG}\"\n" -" shift\n" -" OPT_ARG=\"$1\"\n" -" fi\n" -" ;;\n\n" -" OK )\n" -" if [ -z \"${OPT_ARG_VAL}\" ] && [ $# -gt 0 ]\n" -" then\n" -" case \"${OPT_ARG}\" in -* ) ;; * )\n" -" OPT_ARG_VAL=\"${OPT_ARG}\"\n" -" shift\n" -" OPT_ARG=\"$1\" ;; esac\n" -" fi\n" -" ;;\n" -" esac\n"; - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * - * FLAG OPTION PROCESSING - * - * Formats for emitting the text for handling flag option types - */ -tSCC zFlagOptInit[] = -" OPT_CODE=`echo \"X${OPT_ARG}\" | sed 's/X-\\(.\\).*/\\1/'`\n" -" OPT_ARG=` echo \"X${OPT_ARG}\" | sed 's/X-.//'`\n\n"; - -tSCC zFlagOptArg[] = -" case \"${OPT_ARG_NEEDED}\" in\n" -" NO )\n" -" if [ -n \"${OPT_ARG}\" ]\n" -" then\n" -" OPT_ARG=-\"${OPT_ARG}\"\n" -" else\n" -" shift\n" -" OPT_ARG=\"$1\"\n" -" fi\n" -" ;;\n\n" -" YES )\n" -" if [ -n \"${OPT_ARG}\" ]\n" -" then\n" -" OPT_ARG_VAL=\"${OPT_ARG}\"\n\n" -" else\n" -" if [ $# -eq 0 ]\n" -" then\n" -" echo No argument provided for ${OPT_NAME} option >&2\n" -" echo \"$%s_USAGE_TEXT\"\n" -" exit 1\n" -" fi\n" -" shift\n" -" OPT_ARG_VAL=\"$1\"\n" -" fi\n\n" -" shift\n" -" OPT_ARG=\"$1\"\n" -" ;;\n\n" -" OK )\n" -" if [ -n \"${OPT_ARG}\" ]\n" -" then\n" -" OPT_ARG_VAL=\"${OPT_ARG}\"\n" -" shift\n" -" OPT_ARG=\"$1\"\n\n" -" else\n" -" shift\n" -" if [ $# -gt 0 ]\n" -" then\n" -" case \"$1\" in -* ) ;; * )\n" -" OPT_ARG_VAL=\"$1\"\n" -" shift ;; esac\n" -" OPT_ARG=\"$1\"\n" -" fi\n" -" fi\n" -" ;;\n" -" esac\n"; - -tSCC* pzShell = NULL; -static char* pzLeader = NULL; -static char* pzTrailer = NULL; +static void +text_to_var(tOptions * opts, teTextTo which, tOptDesc * od); -/* = = = START-STATIC-FORWARD = = = */ -/* static forward declarations maintained by :mkfwd */ static void -textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD ); +emit_usage(tOptions * opts); static void -emitUsage( tOptions* pOpts ); +emit_wrapup(tOptions * opts); static void -emitSetup( tOptions* pOpts ); +emit_setup(tOptions * opts); static void -printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc ); +emit_action(tOptions * opts, tOptDesc * od); static void -printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc ); +emit_inaction(tOptions * opts, tOptDesc * od); static void -emitFlag( tOptions* pOpts ); +emit_flag(tOptions * opts); static void -emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts ); +emit_match_expr(char const * name, tOptDesc * cod, tOptions * opts); static void -emitLong( tOptions* pOpts ); +emit_long(tOptions * opts); + +static char * +load_old_output(char const * fname, char const * pname); static void -openOutput( char const* pzFile ); +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 + + * arg: + tOptions * + pOpts + program options descriptor + * * doc: * Emit a shell script that will parse the command line options. =*/ void -optionParseShell( tOptions* pOpts ) +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_OPT( SHELL )) - pzShell = OPT_ARG( SHELL ); + if (HAVE_GENSHELL_OPT(SHELL)) + shell_prog = GENSHELL_OPT_ARG(SHELL); - else if (! ENABLED_OPT( SHELL )) - pzShell = NULL; + else if (! ENABLED_GENSHELL_OPT(SHELL)) + shell_prog = NULL; - else if ((pzShell = getenv( "SHELL" )), - pzShell == NULL) + else if ((shell_prog = getenv("SHELL")), + shell_prog == NULL) - pzShell = "/bin/sh"; + shell_prog = POSIX_SHELL; /* * Check for a specified output file */ - if (HAVE_OPT( SCRIPT )) - openOutput( OPT_ARG( SCRIPT )); - - emitUsage( pOpts ); - emitSetup( pOpts ); + 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 (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) { + switch (opts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) { case OPTPROC_LONGOPT: - fputs( zLoopCase, stdout ); + fputs(LOOP_STR, stdout); - fputs( zLongSelection, stdout ); - fputs( zLongOptInit, stdout ); - emitLong( pOpts ); - printf( zLongOptArg, pOpts->pzPROGNAME ); - fputs( zEndSelection, 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( zNoSelection, stdout ); + fputs(NOT_FOUND_STR, stdout); break; case 0: - fputs( zLoopOnly, stdout ); - fputs( zLongOptInit, stdout ); - emitLong( pOpts ); - printf( zLongOptArg, pOpts->pzPROGNAME ); + fputs(ONLY_OPTS_LOOP, stdout); + fputs(INIT_LOPT_STR, stdout); + emit_long(opts); + printf(LOPT_ARG_FMT, opts->pzPROGNAME); break; case OPTPROC_SHORTOPT: - fputs( zLoopCase, stdout ); + fputs(LOOP_STR, stdout); - fputs( zFlagSelection, stdout ); - fputs( zFlagOptInit, stdout ); - emitFlag( pOpts ); - printf( zFlagOptArg, pOpts->pzPROGNAME ); - fputs( zEndSelection, 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( zNoSelection, stdout ); + fputs(NOT_FOUND_STR, stdout); break; case OPTPROC_LONGOPT|OPTPROC_SHORTOPT: - fputs( zLoopCase, stdout ); + fputs(LOOP_STR, stdout); - fputs( zLongSelection, stdout ); - fputs( zLongOptInit, stdout ); - emitLong( pOpts ); - printf( zLongOptArg, pOpts->pzPROGNAME ); - fputs( zEndSelection, 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( zFlagSelection, stdout ); - fputs( zFlagOptInit, stdout ); - emitFlag( pOpts ); - printf( zFlagOptArg, pOpts->pzPROGNAME ); - fputs( zEndSelection, 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( zNoSelection, stdout ); + fputs(NOT_FOUND_STR, stdout); break; } - printf( zLoopEnd, pOpts->pzPROGNAME, zTrailerMarker ); - if ((pzTrailer != NULL) && (*pzTrailer != '\0')) - fputs( pzTrailer, stdout ); - else if (ENABLED_OPT( SHELL )) - printf( "\nenv | grep '^%s_'\n", pOpts->pzPROGNAME ); + 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); - fflush( stdout ); - fchmod( STDOUT_FILENO, 0755 ); - fclose( stdout ); +#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 -textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD ) +text_to_var(tOptions * opts, teTextTo which, tOptDesc * od) { -# define _TT_(n) tSCC z ## n [] = #n; +# define _TT_(n) static char const z ## n [] = #n; TEXTTO_TABLE # undef _TT_ # define _TT_(n) z ## n , - static char const* apzTTNames[] = { TEXTTO_TABLE }; + static char const * ttnames[] = { TEXTTO_TABLE }; # undef _TT_ -#if defined(__windows__) && !defined(__CYGWIN__) - printf( "%1$s_%2$s_TEXT='no %2$s text'\n", - pOpts->pzPROGNAME, apzTTNames[ whichVar ]); +#if ! defined(HAVE_WORKING_FORK) + printf(SET_NO_TEXT_FMT, opts->pzPROGNAME, ttnames[which]); #else - int nlHoldCt = 0; - int pipeFd[2]; - FILE* fp; + int fdpair[2]; - printf( "%s_%s_TEXT='", pOpts->pzPROGNAME, apzTTNames[ whichVar ]); - fflush( stdout ); + fflush(stdout); + fflush(stderr); - if (pipe( pipeFd ) != 0) { - fprintf( stderr, zBadPipe, errno, strerror( errno )); - exit( EXIT_FAILURE ); - } + if (pipe(fdpair) != 0) + fserr_exit(opts->pzProgName, "pipe", zinter_proc_pipe); switch (fork()) { case -1: - fprintf( stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName); - exit( EXIT_FAILURE ); - break; + fserr_exit(opts->pzProgName, "fork", opts->pzProgName); + /* NOTREACHED */ case 0: - dup2( pipeFd[1], STDERR_FILENO ); - dup2( pipeFd[1], STDOUT_FILENO ); - close( pipeFd[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 (whichVar) { + switch (which) { case TT_LONGUSAGE: - (*(pOpts->pUsageProc))( pOpts, EXIT_SUCCESS ); + (*(opts->pUsageProc))(opts, EXIT_SUCCESS); /* NOTREACHED */ - exit( EXIT_FAILURE ); case TT_USAGE: - (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE ); + (*(opts->pUsageProc))(opts, EXIT_FAILURE); /* NOTREACHED */ - exit( EXIT_FAILURE ); case TT_VERSION: - if (pOD->fOptState & OPTST_ALLOC_ARG) { - AGFREE(pOD->optArg.argString); - pOD->fOptState &= ~OPTST_ALLOC_ARG; + if (od->fOptState & OPTST_ALLOC_ARG) { + AGFREE(od->optArg.argString); + od->fOptState &= ~OPTST_ALLOC_ARG; } - pOD->optArg.argString = "c"; - optionPrintVersion( pOpts, pOD ); + od->optArg.argString = "c"; + optionPrintVersion(opts, od); /* NOTREACHED */ default: - exit( EXIT_FAILURE ); + option_exits(EXIT_FAILURE); + /* NOTREACHED */ } + /* NOTREACHED */ default: - close( pipeFd[1] ); - fp = fdopen( pipeFd[0], "r" FOPEN_BINARY_FLAG ); + close(fdpair[1]); } - for (;;) { - int ch = fgetc( fp ); - switch (ch) { - - case '\n': - nlHoldCt++; - break; - - case '\'': - while (nlHoldCt > 0) { - fputc( '\n', stdout ); - nlHoldCt--; - } - fputs( "'\\''", stdout ); - break; - - case EOF: - goto endCharLoop; - - default: - while (nlHoldCt > 0) { - fputc( '\n', stdout ); - nlHoldCt--; - } - fputc( ch, stdout ); - break; - } - } endCharLoop:; - - fputs( "'\n\n", stdout ); - close( pipeFd[0] ); + emit_var_text(opts->pzPROGNAME, ttnames[which], fdpair[0]); #endif } - +/** + * capture usage text in shell variables. + * + */ static void -emitUsage( tOptions* pOpts ) +emit_usage(tOptions * opts) { - char zTimeBuf[ AO_NAME_SIZE ]; + char tm_nm_buf[AO_NAME_SIZE]; /* * First, switch stdout to the output file name. @@ -608,54 +366,61 @@ emitUsage( tOptions* pOpts ) * by the definitions (rather than the current * executable name). Down case the upper cased name. */ - if (pzLeader != NULL) - fputs( pzLeader, stdout ); + if (script_leader != NULL) + fputs(script_leader, stdout); { - tSCC zStdout[] = "stdout"; - tCC* pzOutName; + char const * out_nm; { - time_t curTime = time( NULL ); - struct tm* pTime = localtime( &curTime ); - strftime(zTimeBuf, AO_NAME_SIZE, "%A %B %e, %Y at %r %Z", pTime ); + time_t c_tim = time(NULL); + struct tm * ptm = localtime(&c_tim); + strftime(tm_nm_buf, AO_NAME_SIZE, TIME_FMT, ptm ); } - if (HAVE_OPT( SCRIPT )) - pzOutName = OPT_ARG( SCRIPT ); - else pzOutName = zStdout; + if (HAVE_GENSHELL_OPT(SCRIPT)) + out_nm = GENSHELL_OPT_ARG(SCRIPT); + else out_nm = STDOUT; - if ((pzLeader == NULL) && (pzShell != NULL)) - printf( "#! %s\n", pzShell ); + if ((script_leader == NULL) && (shell_prog != NULL)) + printf(SHELL_MAGIC, shell_prog); - printf( zPreamble, zStartMarker, pzOutName, zTimeBuf ); + 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 + * 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; - tCC* pz = pOpts->pzPROGNAME; + char * pzPN = tm_nm_buf; + char const * pz = opts->pzPROGNAME; + char ** pp; + + /* Copy the program name into the time/name buffer */ for (;;) { - if ((*pzPN++ = tolower( *pz++ )) == '\0') + if ((*pzPN++ = (char)tolower(*pz++)) == NUL) break; } - } - printf( zEndPreamble, pOpts->pzPROGNAME ); + pp = VOIDP(&(opts->pzProgPath)); + *pp = tm_nm_buf; + pp = VOIDP(&(opts->pzProgName)); + *pp = tm_nm_buf; + } - pOpts->pzProgPath = pOpts->pzProgName = zTimeBuf; - textToVariable( pOpts, TT_LONGUSAGE, NULL ); - textToVariable( pOpts, TT_USAGE, NULL ); + text_to_var(opts, TT_LONGUSAGE, NULL); + text_to_var(opts, TT_USAGE, NULL); { - tOptDesc* pOptDesc = pOpts->pOptDesc; - int optionCt = pOpts->optCt; + tOptDesc * pOptDesc = opts->pOptDesc; + int optionCt = opts->optCt; for (;;) { if (pOptDesc->pOptProc == optionPrintVersion) { - textToVariable( pOpts, TT_VERSION, pOptDesc ); + text_to_var(opts, TT_VERSION, pOptDesc); break; } @@ -666,254 +431,291 @@ emitUsage( tOptions* pOpts ) } } +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 -emitSetup( tOptions* pOpts ) +emit_setup(tOptions * opts) { - tOptDesc* pOptDesc = pOpts->pOptDesc; - int optionCt = pOpts->presetOptCt; - char const* pzFmt; - char const* pzDefault; + tOptDesc * od = opts->pOptDesc; + int opt_ct = opts->presetOptCt; + char const * fmt; + char const * def_val; - for (;optionCt > 0; pOptDesc++, --optionCt) { - char zVal[16]; + 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(pOptDesc) || (pOptDesc->pz_NAME == NULL)) + if (SKIP_OPT(od) || (od->pz_NAME == NULL)) continue; - if (pOptDesc->optMaxCt > 1) - pzFmt = zMultiDef; - else pzFmt = zSingleDef; + 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(pOptDesc->fOptState)) { + switch (OPTST_GET_ARGTYPE(od->fOptState)) { case OPARG_TYPE_ENUMERATION: - (*(pOptDesc->pOptProc))( (tOptions*)2UL, pOptDesc ); - pzDefault = pOptDesc->optArg.argString; + (*(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( zVal, sizeof( zVal ), "%d", - (int)pOptDesc->optArg.argInt ); - pzDefault = zVal; + snprintf(int_val_buf, sizeof(int_val_buf), "%d", + (int)od->optArg.argInt); + def_val = int_val_buf; break; case OPARG_TYPE_MEMBERSHIP: - snprintf( zVal, sizeof( zVal ), "%lu", - (unsigned long)pOptDesc->optArg.argIntptr ); - pzDefault = zVal; + snprintf(int_val_buf, sizeof(int_val_buf), "%lu", + (unsigned long)od->optArg.argIntptr); + def_val = int_val_buf; break; case OPARG_TYPE_BOOLEAN: - pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false"; + def_val = (od->optArg.argBool) ? TRUE_STR : FALSE_STR; break; default: - if (pOptDesc->optArg.argString == NULL) { - if (pzFmt == zSingleDef) - pzFmt = zSingleNoDef; - pzDefault = NULL; + if (od->optArg.argString == NULL) { + if (fmt == SGL_DEF_FMT) + fmt = SGL_NO_DEF_FMT; + def_val = NULL; } else - pzDefault = pOptDesc->optArg.argString; + def_val = od->optArg.argString; } - printf( pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault ); + printf(fmt, opts->pzPROGNAME, od->pz_NAME, def_val); } } - static void -printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc ) +emit_action(tOptions * opts, tOptDesc * od) { - if (pOptDesc->pOptProc == optionPrintVersion) - printf( zTextExit, pOpts->pzPROGNAME, "VERSION" ); + if (od->pOptProc == optionPrintVersion) + printf(ECHO_N_EXIT, opts->pzPROGNAME, VER_STR); - else if (pOptDesc->pOptProc == optionPagedUsage) - printf( zPagedUsageExit, pOpts->pzPROGNAME ); + else if (od->pOptProc == optionPagedUsage) + printf(PAGE_USAGE_TEXT, opts->pzPROGNAME); - else if (pOptDesc->pOptProc == optionLoadOpt) { - printf( zCmdFmt, "echo 'Warning: Cannot load options files' >&2" ); - printf( zCmdFmt, "OPT_ARG_NEEDED=YES" ); + else if (od->pOptProc == optionLoadOpt) { + printf(LVL3_CMD, NO_LOAD_WARN); + printf(LVL3_CMD, YES_NEED_OPT_ARG); - } else if (pOptDesc->pz_NAME == NULL) { + } else if (od->pz_NAME == NULL) { - if (pOptDesc->pOptProc == NULL) { - printf( zCmdFmt, "echo 'Warning: Cannot save options files' " - ">&2" ); - printf( zCmdFmt, "OPT_ARG_NEEDED=OK" ); + if (od->pOptProc == NULL) { + printf(LVL3_CMD, NO_SAVE_OPTS); + printf(LVL3_CMD, OK_NEED_OPT_ARG); } else - printf( zTextExit, pOpts->pzPROGNAME, "LONGUSAGE" ); + printf(ECHO_N_EXIT, opts->pzPROGNAME, LONG_USE_STR); } else { - if (pOptDesc->optMaxCt == 1) - printf( zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME ); + if (od->optMaxCt == 1) + printf(SGL_ARG_FMT, opts->pzPROGNAME, od->pz_NAME); else { - if ((unsigned)pOptDesc->optMaxCt < NOLIMIT) - printf( zCountTest, pOpts->pzPROGNAME, - pOptDesc->pz_NAME, pOptDesc->optMaxCt ); + if ((unsigned)od->optMaxCt < NOLIMIT) + printf(CHK_MAX_COUNT, opts->pzPROGNAME, + od->pz_NAME, od->optMaxCt); - printf( zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME ); + printf(MULTI_ARG_FMT, opts->pzPROGNAME, od->pz_NAME); } /* * Fix up the args. */ - if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) { - printf( zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME ); + 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 (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) { - printf( zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME ); + } else if (od->fOptState & OPTST_ARG_OPTIONAL) { + printf(SET_MULTI_ARG, opts->pzPROGNAME, od->pz_NAME); + printf(LVL3_CMD, OK_NEED_OPT_ARG); } else { - fputs( zMustArg, stdout ); + printf(LVL3_CMD, YES_NEED_OPT_ARG); } } - fputs( zOptionEndSelect, stdout ); + fputs(zOptionEndSelect, stdout); } - static void -printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc ) +emit_inaction(tOptions * opts, tOptDesc * od) { - if (pOptDesc->pOptProc == optionLoadOpt) { - printf( zCmdFmt, "echo 'Warning: Cannot suppress the loading of " - "options files' >&2" ); + if (od->pOptProc == optionLoadOpt) { + printf(LVL3_CMD, NO_SUPPRESS_LOAD); - } else if (pOptDesc->optMaxCt == 1) - printf( zNoSingleArg, pOpts->pzPROGNAME, - pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx ); + } else if (od->optMaxCt == 1) + printf(NO_SGL_ARG_FMT, opts->pzPROGNAME, + od->pz_NAME, od->pz_DisablePfx); else - printf( zNoMultiArg, pOpts->pzPROGNAME, - pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx ); + printf(NO_MULTI_ARG_FMT, opts->pzPROGNAME, + od->pz_NAME, od->pz_DisablePfx); - printf( zCmdFmt, "OPT_ARG_NEEDED=NO" ); - fputs( zOptionEndSelect, stdout ); + 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 -emitFlag( tOptions* pOpts ) +emit_flag(tOptions * opts) { - tOptDesc* pOptDesc = pOpts->pOptDesc; - int optionCt = pOpts->optCt; + tOptDesc * od = opts->pOptDesc; + int opt_ct = opts->optCt; - fputs( zOptionCase, stdout ); + fputs(zOptionCase, stdout); - for (;optionCt > 0; pOptDesc++, --optionCt) { + for (;opt_ct > 0; od++, --opt_ct) { - if (SKIP_OPT(pOptDesc)) + if (SKIP_OPT(od) || ! IS_GRAPHIC_CHAR(od->optValue)) continue; - if (isprint( pOptDesc->optValue )) { - printf( zOptionFlag, pOptDesc->optValue ); - printOptionAction( pOpts, pOptDesc ); - } + printf(zOptionFlag, od->optValue); + emit_action(opts, od); } - printf( zOptionUnknown, "flag", pOpts->pzPROGNAME ); + printf(UNK_OPT_FMT, FLAG_STR, opts->pzPROGNAME); } - -/* - * Emit the match text for a long option +/** + * 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 -emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts ) +emit_match_expr(char const * name, tOptDesc * cod, tOptions * opts) { - 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; + char name_bf[32]; + unsigned int min_match_ct = 2; + unsigned int max_match_ct = strlen(name) - 1; - /* - * 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 (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; } - if (--oCt <= 0) - break; - pOD++; } /* - * IF the 'min' is all or one short of the name length, - * THEN the entire string must be matched. + * Don't bother emitting partial matches if there is only one possible + * partial match. */ - if ( (pzMatchName[min ] == NUL) - || (pzMatchName[min+1] == NUL) ) - printf( zOptionFullName, pzMatchName ); + if (min_match_ct < max_match_ct) { + char * pz = name_bf + min_match_ct; + int nm_ix = min_match_ct; - else { - int matchCt = 0; - for (; matchCt <= min; matchCt++) - *pz++ = pzMatchName[matchCt]; + memcpy(name_bf, name, min_match_ct); for (;;) { *pz = NUL; - printf( zOptionPartName, zName ); - *pz++ = pzMatchName[matchCt++]; - if (pzMatchName[matchCt] == NUL) { + printf(zOptionPartName, name_bf); + *pz++ = name[nm_ix++]; + if (name[nm_ix] == NUL) { *pz = NUL; - printf( zOptionFullName, zName ); break; } } } -} +leave: + printf(zOptionFullName, name); +} -/* - * Emit GNU-standard long option handling code +/** + * Emit GNU-standard long option handling code. + * + * @param[in] opts the program options */ static void -emitLong( tOptions* pOpts ) +emit_long(tOptions * opts) { - tOptDesc* pOD = pOpts->pOptDesc; - int ct = pOpts->optCt; + tOptDesc * od = opts->pOptDesc; + int ct = opts->optCt; - fputs( zOptionCase, stdout ); + fputs(zOptionCase, stdout); /* * do each option, ... @@ -922,109 +724,134 @@ emitLong( tOptions* pOpts ) /* * Documentation & compiled-out options */ - if (SKIP_OPT(pOD)) + if (SKIP_OPT(od)) continue; - emitMatchExpr( pOD->pz_Name, pOD, pOpts ); - printOptionAction( pOpts, pOD ); + 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 (pOD->pz_DisableName != NULL) { - emitMatchExpr( pOD->pz_DisableName, pOD, pOpts ); - printOptionInaction( pOpts, pOD ); + if (od->pz_DisableName != NULL) { + emit_match_expr(od->pz_DisableName, od, opts); + emit_inaction(opts, od); } - } while (pOD++, --ct > 0); + } while (od++, --ct > 0); - printf( zOptionUnknown, "option", pOpts->pzPROGNAME ); + printf(UNK_OPT_FMT, OPTION_STR, opts->pzPROGNAME); } - -static void -openOutput( char const* pzFile ) +/** + * 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) { - FILE* fp; - char* pzData = NULL; + /* + * 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; - do { - char* pzScan; - size_t sizeLeft; + if (fp == NULL) + return NULL; - /* - * IF we cannot stat the file, - * THEN assume we are creating a new file. - * Skip the loading of the old data. - */ - if (stat( pzFile, &stbf ) != 0) + /* + * 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; - /* - * The file must be a regular file - */ - if (! S_ISREG( stbf.st_mode )) { - fprintf( stderr, zNotFile, pzFile ); - exit( EXIT_FAILURE ); - } + stbf.st_size -= (ssize_t)inct; - pzData = AGALOC(stbf.st_size + 1, "file data"); - fp = fopen( pzFile, "r" FOPEN_BINARY_FLAG ); + if (stbf.st_size == 0) + break; - sizeLeft = (unsigned)stbf.st_size; - pzScan = pzData; + scan += inct; + } - /* - * Read in all the data as fast as our OS will let us. - */ - for (;;) { - int inct = fread( (void*)pzScan, (size_t)1, sizeLeft, fp); - if (inct == 0) - break; + *scan = NUL; + fclose(fp); - pzScan += inct; - sizeLeft -= inct; + return text; +} - if (sizeLeft == 0) - break; - } +/** + * 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) +{ - /* - * NUL-terminate the leader and look for the trailer - */ - *pzScan = '\0'; - fclose( fp ); - pzScan = strstr( pzData, zStartMarker ); - if (pzScan == NULL) { - pzTrailer = pzData; + 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; } - *(pzScan++) = NUL; - pzScan = strstr( pzScan, zTrailerMarker ); - if (pzScan == NULL) { - pzTrailer = pzData; + *(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 + * Check to see if the data contains our marker. + * If it does, then we will skip over it */ - pzTrailer = pzScan + sizeof( zTrailerMarker ) - 1; - pzLeader = pzData; - } while (AG_FALSE); + script_trailer = scn + END_MARK_LEN; + script_leader = txt; + } while (false); - freopen( pzFile, "w" FOPEN_BINARY_FLAG, stdout ); + 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* + pOpts + program options descriptor + - * arg: + int + exitCode + usage text type to produce + + * 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 @@ -1034,19 +861,21 @@ openOutput( char const* pzFile ) * and create shell script variables containing the two types of text. =*/ void -genshelloptUsage( tOptions* pOpts, int exitCode ) +genshelloptUsage(tOptions * opts, int exit_cd) { -#if defined(__windows__) && !defined(__CYGWIN__) - optionUsage( pOpts, exitCode ); +#if ! defined(HAVE_WORKING_FORK) + optionUsage(opts, exit_cd); #else /* * IF not EXIT_SUCCESS, * THEN emit the short form of usage. */ - if (exitCode != EXIT_SUCCESS) - optionUsage( pOpts, exitCode ); - fflush( stderr ); - fflush( stdout ); + 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; @@ -1055,20 +884,19 @@ genshelloptUsage( tOptions* pOpts, int exitCode ) */ switch (fork()) { case -1: - optionUsage( pOpts, EXIT_FAILURE ); - /*NOTREACHED*/ - _exit( EXIT_FAILURE ); + optionUsage(opts, EXIT_FAILURE); + /* NOTREACHED */ case 0: pagerState = PAGER_STATE_CHILD; - optionUsage( pOpts, EXIT_SUCCESS ); - /*NOTREACHED*/ - _exit( EXIT_FAILURE ); + optionUsage(opts, EXIT_SUCCESS); + /* NOTREACHED */ + _exit(EXIT_FAILURE); default: { int sts; - wait( &sts ); + wait(&sts); } } @@ -1077,11 +905,12 @@ genshelloptUsage( tOptions* pOpts, int exitCode ) * gets it from the command line */ { - char* pz; - AGDUPSTR( pz, pShellParseOptions->pzPROGNAME, "program name" ); - pShellParseOptions->pzProgName = pz; + char * pz; + char ** pp = VOIDP(&(optionParseShellOptions->pzProgName)); + AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name"); + *pp = pz; while (*pz != NUL) { - *pz = tolower( *pz ); + *pz = (char)LOWER(*pz); pz++; } } @@ -1089,8 +918,8 @@ genshelloptUsage( tOptions* pOpts, int exitCode ) /* * Separate the makeshell usage from the client usage */ - fprintf( option_usage_fp, zGenshell, pShellParseOptions->pzProgName ); - fflush( option_usage_fp ); + fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName); + fflush(option_usage_fp); /* * Now, print the client usage. @@ -1100,20 +929,25 @@ genshelloptUsage( tOptions* pOpts, int exitCode ) pagerState = PAGER_STATE_CHILD; /*FALLTHROUGH*/ case -1: - optionUsage( pShellParseOptions, EXIT_FAILURE ); + optionUsage(optionParseShellOptions, EXIT_FAILURE); default: { int sts; - wait( &sts ); + wait(&sts); } } - exit( EXIT_SUCCESS ); + 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" |