summaryrefslogtreecommitdiff
path: root/src/libopts/makeshell.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libopts/makeshell.c')
-rw-r--r--src/libopts/makeshell.c707
1 files changed, 406 insertions, 301 deletions
diff --git a/src/libopts/makeshell.c b/src/libopts/makeshell.c
index 79edb7022b..f22e9f0b84 100644
--- a/src/libopts/makeshell.c
+++ b/src/libopts/makeshell.c
@@ -2,14 +2,16 @@
/**
* \file makeshell.c
*
- * Time-stamp: "2012-04-07 09:03:16 bkorb"
- *
* 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-2012 by Bruce Korb - all rights reserved
+ * AutoOpts is Copyright (C) 1992-2013 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
@@ -21,11 +23,11 @@
* The Modified Berkeley Software Distribution License
* See the file "COPYING.mbsd"
*
- * These files have the following md5sums:
+ * These files have the following sha256 sums:
*
- * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
- * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
- * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
+ * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
+ * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
+ * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
*/
tOptions * optionParseShellOptions = NULL;
@@ -33,39 +35,60 @@ 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);
+text_to_var(tOptions * opts, teTextTo which, tOptDesc * od);
static void
-emit_usage(tOptions * pOpts);
+emit_usage(tOptions * opts);
static void
-emit_setup(tOptions * pOpts);
+emit_wrapup(tOptions * opts);
static void
-emit_action(tOptions * pOpts, tOptDesc* pOptDesc);
+emit_setup(tOptions * opts);
static void
-emit_inaction(tOptions * pOpts, tOptDesc* pOptDesc);
+emit_action(tOptions * opts, tOptDesc * od);
static void
-emit_flag(tOptions * pOpts);
+emit_inaction(tOptions * opts, tOptDesc * od);
static void
-emit_match_expr(char const * pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts);
+emit_flag(tOptions * opts);
static void
-emitLong(tOptions * pOpts);
+emit_match_expr(char const * name, tOptDesc * cod, tOptions * opts);
static void
-open_out(char const * pzFile);
+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 void
+fserr_warn(char const * prog, char const * op, char const * fname)
+{
+ fprintf(stderr, zfserr_fmt, prog, errno, strerror(errno),
+ op, fname);
+}
+
+LOCAL void
+fserr_exit(char const * prog, char const * op, char const * fname)
+{
+ fserr_warn(prog, op, fname);
+ exit(EXIT_FAILURE);
+}
+
/*=export_func optionParseShell
* private:
*
@@ -76,7 +99,7 @@ open_out(char const * pzFile);
* Emit a shell script that will parse the command line options.
=*/
void
-optionParseShell(tOptions * pOpts)
+optionParseShell(tOptions * opts)
{
/*
* Check for our SHELL option now.
@@ -98,22 +121,22 @@ optionParseShell(tOptions * pOpts)
* Check for a specified output file
*/
if (HAVE_GENSHELL_OPT(SCRIPT))
- open_out(GENSHELL_OPT_ARG(SCRIPT));
-
- emit_usage(pOpts);
- emit_setup(pOpts);
+ 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(LOOP_STR, stdout);
fputs(LONG_OPT_MARK, stdout);
fputs(INIT_LOPT_STR, stdout);
- emitLong(pOpts);
- printf(LOPT_ARG_FMT, pOpts->pzPROGNAME);
+ emit_long(opts);
+ printf(LOPT_ARG_FMT, opts->pzPROGNAME);
fputs(END_OPT_SEL_STR, stdout);
fputs(NOT_FOUND_STR, stdout);
@@ -122,8 +145,8 @@ optionParseShell(tOptions * pOpts)
case 0:
fputs(ONLY_OPTS_LOOP, stdout);
fputs(INIT_LOPT_STR, stdout);
- emitLong(pOpts);
- printf(LOPT_ARG_FMT, pOpts->pzPROGNAME);
+ emit_long(opts);
+ printf(LOPT_ARG_FMT, opts->pzPROGNAME);
break;
case OPTPROC_SHORTOPT:
@@ -131,8 +154,8 @@ optionParseShell(tOptions * pOpts)
fputs(FLAG_OPT_MARK, stdout);
fputs(INIT_OPT_STR, stdout);
- emit_flag(pOpts);
- printf(OPT_ARG_FMT, pOpts->pzPROGNAME);
+ emit_flag(opts);
+ printf(OPT_ARG_FMT, opts->pzPROGNAME);
fputs(END_OPT_SEL_STR, stdout);
fputs(NOT_FOUND_STR, stdout);
@@ -143,38 +166,53 @@ optionParseShell(tOptions * pOpts)
fputs(LONG_OPT_MARK, stdout);
fputs(INIT_LOPT_STR, stdout);
- emitLong(pOpts);
- printf(LOPT_ARG_FMT, pOpts->pzPROGNAME);
+ 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(pOpts);
- printf(OPT_ARG_FMT, pOpts->pzPROGNAME);
+ emit_flag(opts);
+ printf(OPT_ARG_FMT, opts->pzPROGNAME);
fputs(END_OPT_SEL_STR, stdout);
fputs(NOT_FOUND_STR, stdout);
break;
}
- printf(zLoopEnd, pOpts->pzPROGNAME, END_MARK);
+ emit_wrapup(opts);
if ((script_trailer != NULL) && (*script_trailer != NUL))
fputs(script_trailer, stdout);
else if (ENABLED_GENSHELL_OPT(SHELL))
- printf(SHOW_PROG_ENV, pOpts->pzPROGNAME);
+ printf(SHOW_PROG_ENV, opts->pzPROGNAME);
#ifdef HAVE_FCHMOD
fchmod(STDOUT_FILENO, 0755);
#endif
fclose(stdout);
- if (ferror(stdout)) {
- fputs(zOutputFail, stderr);
- exit(EXIT_FAILURE);
- }
+ 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)
{
@@ -198,11 +236,11 @@ emit_var_text(char const * prog, char const * var, int fdin)
fputc(NL, stdout);
nlct--;
}
- fputs(apostrophy, stdout);
+ fputs(apostrophe, stdout);
break;
case EOF:
- goto endCharLoop;
+ goto done;
default:
while (nlct > 0) {
@@ -212,97 +250,102 @@ emit_var_text(char const * prog, char const * var, int fdin)
fputc(ch, stdout);
break;
}
- } endCharLoop:;
+ } done:;
fclose(fp);
-skip_text:
+ 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 * pOpts, teTextTo whichVar, tOptDesc * pOD)
+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 * apzTTNames[] = { TEXTTO_TABLE };
+ static char const * ttnames[] = { TEXTTO_TABLE };
# undef _TT_
#if ! defined(HAVE_WORKING_FORK)
- printf(SET_NO_TEXT_FMT, pOpts->pzPROGNAME, apzTTNames[ whichVar]);
+ printf(SET_NO_TEXT_FMT, opts->pzPROGNAME, ttnames[which]);
#else
- int pipeFd[2];
+ int fdpair[2];
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:
/*
* 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]);
+ 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 */
case TT_USAGE:
- (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
+ (*(opts->pUsageProc))(opts, EXIT_FAILURE);
/* NOTREACHED */
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);
+ /* NOTREACHED */
}
+ /* NOTREACHED */
default:
- close(pipeFd[1]);
+ close(fdpair[1]);
}
- emit_var_text(pOpts->pzPROGNAME, apzTTNames[whichVar], pipeFd[0]);
+ emit_var_text(opts->pzPROGNAME, ttnames[which], fdpair[0]);
#endif
}
-
+/**
+ * capture usage text in shell variables.
+ *
+ */
static void
-emit_usage(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.
@@ -319,7 +362,7 @@ emit_usage(tOptions * pOpts)
{
time_t c_tim = time(NULL);
struct tm * ptm = localtime(&c_tim);
- strftime(zTimeBuf, AO_NAME_SIZE, TIME_FMT, ptm );
+ strftime(tm_nm_buf, AO_NAME_SIZE, TIME_FMT, ptm );
}
if (HAVE_GENSHELL_OPT(SCRIPT))
@@ -329,41 +372,42 @@ emit_usage(tOptions * pOpts)
if ((script_leader == NULL) && (shell_prog != NULL))
printf(SHELL_MAGIC, shell_prog);
- printf(PREAMBLE_FMT, START_MARK, out_nm, zTimeBuf);
+ printf(PREAMBLE_FMT, START_MARK, out_nm, tm_nm_buf);
}
- printf(END_PRE_FMT, pOpts->pzPROGNAME);
+ 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 = zTimeBuf;
- char const * 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++ = (char)tolower(*pz++)) == NUL)
break;
}
- pp = (char **)(void *)&(pOpts->pzProgPath);
- *pp = zTimeBuf;
- pp = (char **)(void *)&(pOpts->pzProgName);
- *pp = zTimeBuf;
+ pp = (char **)(void *)&(opts->pzProgPath);
+ *pp = tm_nm_buf;
+ pp = (char **)(void *)&(opts->pzProgName);
+ *pp = tm_nm_buf;
}
- text_to_var(pOpts, TT_LONGUSAGE, NULL);
- text_to_var(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) {
- text_to_var(pOpts, TT_VERSION, pOptDesc);
+ text_to_var(opts, TT_VERSION, pOptDesc);
break;
}
@@ -374,249 +418,289 @@ emit_usage(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
-emit_setup(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[32];
+ 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 = MULTI_DEF_FMT;
- else pzFmt = SGL_DEF_FMT;
+ 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))(OPTPROC_EMIT_SHELL, 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_STR : FALSE_STR;
+ def_val = (od->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;
+ 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
-emit_action(tOptions * pOpts, tOptDesc* pOptDesc)
+emit_action(tOptions * opts, tOptDesc * od)
{
- if (pOptDesc->pOptProc == optionPrintVersion)
- printf(zTextExit, pOpts->pzPROGNAME, VER_STR);
+ 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, NO_LOAD_WARN);
- printf(zCmdFmt, YES_NEED_OPT_ARG);
+ 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, NO_SAVE_OPTS);
- printf(zCmdFmt, OK_NEED_OPT_ARG);
+ if (od->pOptProc == NULL) {
+ printf(LVL3_CMD, NO_SAVE_OPTS);
+ printf(LVL3_CMD, OK_NEED_OPT_ARG);
} else
- printf(zTextExit, pOpts->pzPROGNAME, LONG_USE_STR);
+ printf(ECHO_N_EXIT, opts->pzPROGNAME, LONG_USE_STR);
} else {
- if (pOptDesc->optMaxCt == 1)
- printf(SGL_ARG_FMT, 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(MULTI_ARG_FMT, 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);
}
-
static void
-emit_inaction(tOptions * pOpts, tOptDesc* pOptDesc)
+emit_inaction(tOptions * opts, tOptDesc * od)
{
- if (pOptDesc->pOptProc == optionLoadOpt) {
- printf(zCmdFmt, NO_SUPPRESS_LOAD);
+ if (od->pOptProc == optionLoadOpt) {
+ printf(LVL3_CMD, NO_SUPPRESS_LOAD);
- } else if (pOptDesc->optMaxCt == 1)
- printf(NO_SGL_ARG_FMT, 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(NO_MULTI_ARG_FMT, pOpts->pzPROGNAME,
- pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx);
+ printf(NO_MULTI_ARG_FMT, opts->pzPROGNAME,
+ od->pz_NAME, od->pz_DisablePfx);
- printf(zCmdFmt, NO_ARG_NEEDED);
+ 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 * 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);
- 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 (IS_GRAPHIC_CHAR(pOptDesc->optValue)) {
- printf(zOptionFlag, pOptDesc->optValue);
- emit_action(pOpts, pOptDesc);
- }
+ printf(zOptionFlag, od->optValue);
+ emit_action(opts, od);
}
- printf(UNK_OPT_FMT, FLAG_STR, 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
-emit_match_expr(char const * 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;
- }
+ char name_bf[32];
+ unsigned int min_match_ct = 2;
+ unsigned int max_match_ct = strlen(name) - 1;
- /*
- * 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 (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;
}
- 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);
@@ -627,88 +711,113 @@ emitLong(tOptions * pOpts)
/*
* Documentation & compiled-out options
*/
- if (SKIP_OPT(pOD))
+ if (SKIP_OPT(od))
continue;
- emit_match_expr(pOD->pz_Name, pOD, pOpts);
- emit_action(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) {
- emit_match_expr(pOD->pz_DisableName, pOD, pOpts);
- emit_inaction(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(UNK_OPT_FMT, OPTION_STR, pOpts->pzPROGNAME);
+ printf(UNK_OPT_FMT, OPTION_STR, opts->pzPROGNAME);
}
-
-static void
-open_out(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((void*)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, "f 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 = NUL;
- fclose(fp);
- pzScan = strstr(pzData, START_MARK);
- if (pzScan == NULL) {
- script_trailer = 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, END_MARK);
- if (pzScan == NULL) {
- script_trailer = 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;
}
@@ -716,23 +825,20 @@ open_out(char const * pzFile)
* Check to see if the data contains our marker.
* If it does, then we will skip over it
*/
- script_trailer = pzScan + END_MARK_LEN;
- script_leader = pzData;
+ script_trailer = scn + END_MARK_LEN;
+ script_leader = txt;
} while (false);
- if (freopen(pzFile, "w" FOPEN_BINARY_FLAG, stdout) != stdout) {
- fprintf(stderr, zFreopenFail, errno, strerror(errno));
- exit(EXIT_FAILURE);
- }
+ 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
@@ -742,17 +848,17 @@ open_out(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(HAVE_WORKING_FORK)
- optionUsage(pOpts, exitCode);
+ optionUsage(opts, exit_cd);
#else
/*
* IF not EXIT_SUCCESS,
* THEN emit the short form of usage.
*/
- if (exitCode != EXIT_SUCCESS)
- optionUsage(pOpts, exitCode);
+ if (exit_cd != EXIT_SUCCESS)
+ optionUsage(opts, exit_cd);
fflush(stderr);
fflush(stdout);
if (ferror(stdout) || ferror(stderr))
@@ -765,12 +871,12 @@ genshelloptUsage(tOptions * pOpts, int exitCode)
*/
switch (fork()) {
case -1:
- optionUsage(pOpts, EXIT_FAILURE);
+ optionUsage(opts, EXIT_FAILURE);
/* NOTREACHED */
case 0:
pagerState = PAGER_STATE_CHILD;
- optionUsage(pOpts, EXIT_SUCCESS);
+ optionUsage(opts, EXIT_SUCCESS);
/* NOTREACHED */
_exit(EXIT_FAILURE);
@@ -791,7 +897,7 @@ genshelloptUsage(tOptions * pOpts, int exitCode)
AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "prog name");
*pp = pz;
while (*pz != NUL) {
- *pz = tolower(*pz);
+ *pz = (char)tolower(*pz);
pz++;
}
}
@@ -820,16 +926,15 @@ genshelloptUsage(tOptions * pOpts, int exitCode)
}
fflush(stdout);
- if (ferror(stdout)) {
- fputs(zOutputFail, stderr);
- exit(EXIT_FAILURE);
- }
+ if (ferror(stdout))
+ fserr_exit(opts->pzProgName, zwriting, zstdout_name);
exit(EXIT_SUCCESS);
#endif
}
-/*
+/** @}
+ *
* Local Variables:
* mode: C
* c-file-style: "stroustrup"