1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099 |
- /*
- * $Id: makeshell.c,v 4.22 2007/07/04 21:36:37 bkorb Exp $
- * Time-stamp: "2007-07-04 10:22:32 bkorb"
- *
- * This module will interpret the options set in the tOptions
- * structure and create a Bourne shell script capable of parsing them.
- *
- * This file is part of AutoOpts, a companion to AutoGen.
- * AutoOpts is free software.
- * AutoOpts is copyright (c) 1992-2007 by Bruce Korb - all rights reserved
- *
- * AutoOpts is available under any one of two licenses. The license
- * in use must be one of these two and the choice is under the control
- * of the user of the license.
- *
- * The GNU Lesser General Public License, version 3 or later
- * See the files "COPYING.lgplv3" and "COPYING.gplv3"
- *
- * The Modified Berkeley Software Distribution License
- * See the file "COPYING.mbsd"
- *
- * These files have the following md5sums:
- *
- * 239588c55c22c60ffe159946a760a33e pkg/libopts/COPYING.gplv3
- * fa82ca978890795162346e661b47161a pkg/libopts/COPYING.lgplv3
- * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
- */
- 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
- *
- * 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";
- /* * * * * * * * * * * * * * * *
- *
- * CASE SELECTORS
- *
- * 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";
- /* * * * * * * * * * * * * * * *
- *
- * 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";
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * OPTION SELECTION
- */
- tSCC zOptionCase[] =
- " case \"${OPT_CODE}\" in\n";
- tSCC zOptionPartName[] =
- " '%s' | \\\n";
- tSCC zOptionFullName[] =
- " '%s' )\n";
- tSCC zOptionFlag[] =
- " '%c' )\n";
- 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";
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * 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;
- /* = = = START-STATIC-FORWARD = = = */
- /* static forward declarations maintained by :mkfwd */
- static void
- textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD );
- static void
- emitUsage( tOptions* pOpts );
- static void
- emitSetup( tOptions* pOpts );
- static void
- printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc );
- static void
- printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc );
- static void
- emitFlag( tOptions* pOpts );
- static void
- emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts );
- static void
- emitLong( tOptions* pOpts );
- static void
- openOutput( char const* pzFile );
- /* = = = END-STATIC-FORWARD = = = */
- /*=export_func optionParseShell
- * private:
- *
- * what: Decipher a boolean value
- * arg: + tOptions* + pOpts + program options descriptor +
- *
- * doc:
- * Emit a shell script that will parse the command line options.
- =*/
- void
- optionParseShell( tOptions* pOpts )
- {
- /*
- * Check for our SHELL option now.
- * IF the output file contains the "#!" magic marker,
- * it will override anything we do here.
- */
- if (HAVE_OPT( SHELL ))
- pzShell = OPT_ARG( SHELL );
- else if (! ENABLED_OPT( SHELL ))
- pzShell = NULL;
- else if ((pzShell = getenv( "SHELL" )),
- pzShell == NULL)
- pzShell = "/bin/sh";
- /*
- * Check for a specified output file
- */
- if (HAVE_OPT( SCRIPT ))
- openOutput( OPT_ARG( SCRIPT ));
- emitUsage( pOpts );
- emitSetup( pOpts );
- /*
- * There are four modes of option processing.
- */
- switch (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
- case OPTPROC_LONGOPT:
- fputs( zLoopCase, stdout );
- fputs( zLongSelection, stdout );
- fputs( zLongOptInit, stdout );
- emitLong( pOpts );
- printf( zLongOptArg, pOpts->pzPROGNAME );
- fputs( zEndSelection, stdout );
- fputs( zNoSelection, stdout );
- break;
- case 0:
- fputs( zLoopOnly, stdout );
- fputs( zLongOptInit, stdout );
- emitLong( pOpts );
- printf( zLongOptArg, pOpts->pzPROGNAME );
- break;
- case OPTPROC_SHORTOPT:
- fputs( zLoopCase, stdout );
- fputs( zFlagSelection, stdout );
- fputs( zFlagOptInit, stdout );
- emitFlag( pOpts );
- printf( zFlagOptArg, pOpts->pzPROGNAME );
- fputs( zEndSelection, stdout );
- fputs( zNoSelection, stdout );
- break;
- case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
- fputs( zLoopCase, stdout );
- fputs( zLongSelection, stdout );
- fputs( zLongOptInit, stdout );
- emitLong( pOpts );
- printf( zLongOptArg, pOpts->pzPROGNAME );
- fputs( zEndSelection, stdout );
- fputs( zFlagSelection, stdout );
- fputs( zFlagOptInit, stdout );
- emitFlag( pOpts );
- printf( zFlagOptArg, pOpts->pzPROGNAME );
- fputs( zEndSelection, stdout );
- fputs( zNoSelection, 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 );
- fflush( stdout );
- fchmod( STDOUT_FILENO, 0755 );
- fclose( stdout );
- }
- static void
- textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD )
- {
- # define _TT_(n) tSCC z ## n [] = #n;
- TEXTTO_TABLE
- # undef _TT_
- # define _TT_(n) z ## n ,
- static char const* apzTTNames[] = { TEXTTO_TABLE };
- # undef _TT_
- #if defined(__windows__) && !defined(__CYGWIN__)
- printf( "%1$s_%2$s_TEXT='no %2$s text'\n",
- pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
- #else
- int nlHoldCt = 0;
- int pipeFd[2];
- FILE* fp;
- printf( "%s_%s_TEXT='", pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
- fflush( stdout );
- if (pipe( pipeFd ) != 0) {
- fprintf( stderr, zBadPipe, errno, strerror( errno ));
- exit( EXIT_FAILURE );
- }
- switch (fork()) {
- case -1:
- fprintf( stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
- exit( EXIT_FAILURE );
- break;
- case 0:
- dup2( pipeFd[1], STDERR_FILENO );
- dup2( pipeFd[1], STDOUT_FILENO );
- close( pipeFd[0] );
- switch (whichVar) {
- case TT_LONGUSAGE:
- (*(pOpts->pUsageProc))( pOpts, EXIT_SUCCESS );
- /* NOTREACHED */
- exit( EXIT_FAILURE );
- case TT_USAGE:
- (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
- /* NOTREACHED */
- exit( EXIT_FAILURE );
- case TT_VERSION:
- if (pOD->fOptState & OPTST_ALLOC_ARG) {
- AGFREE(pOD->optArg.argString);
- pOD->fOptState &= ~OPTST_ALLOC_ARG;
- }
- pOD->optArg.argString = "c";
- optionPrintVersion( pOpts, pOD );
- /* NOTREACHED */
- default:
- exit( EXIT_FAILURE );
- }
- default:
- close( pipeFd[1] );
- fp = fdopen( pipeFd[0], "r" FOPEN_BINARY_FLAG );
- }
- 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] );
- #endif
- }
- static void
- emitUsage( tOptions* pOpts )
- {
- char zTimeBuf[ AO_NAME_SIZE ];
- /*
- * First, switch stdout to the output file name.
- * Then, change the program name to the one defined
- * by the definitions (rather than the current
- * executable name). Down case the upper cased name.
- */
- if (pzLeader != NULL)
- fputs( pzLeader, stdout );
- {
- tSCC zStdout[] = "stdout";
- tCC* pzOutName;
- {
- time_t curTime = time( NULL );
- struct tm* pTime = localtime( &curTime );
- strftime(zTimeBuf, AO_NAME_SIZE, "%A %B %e, %Y at %r %Z", pTime );
- }
- if (HAVE_OPT( SCRIPT ))
- pzOutName = OPT_ARG( SCRIPT );
- else pzOutName = zStdout;
- if ((pzLeader == NULL) && (pzShell != NULL))
- printf( "#! %s\n", pzShell );
- printf( zPreamble, zStartMarker, pzOutName, zTimeBuf );
- }
- /*
- * Get a copy of the original program name in lower case
- */
- {
- char* pzPN = zTimeBuf;
- tCC* pz = pOpts->pzPROGNAME;
- for (;;) {
- if ((*pzPN++ = tolower( *pz++ )) == '\0')
- break;
- }
- }
- printf( zEndPreamble, pOpts->pzPROGNAME );
- pOpts->pzProgPath = pOpts->pzProgName = zTimeBuf;
- textToVariable( pOpts, TT_LONGUSAGE, NULL );
- textToVariable( pOpts, TT_USAGE, NULL );
- {
- tOptDesc* pOptDesc = pOpts->pOptDesc;
- int optionCt = pOpts->optCt;
- for (;;) {
- if (pOptDesc->pOptProc == optionPrintVersion) {
- textToVariable( pOpts, TT_VERSION, pOptDesc );
- break;
- }
- if (--optionCt <= 0)
- break;
- pOptDesc++;
- }
- }
- }
- static void
- emitSetup( tOptions* pOpts )
- {
- tOptDesc* pOptDesc = pOpts->pOptDesc;
- int optionCt = pOpts->presetOptCt;
- char const* pzFmt;
- char const* pzDefault;
- for (;optionCt > 0; pOptDesc++, --optionCt) {
- char zVal[16];
- /*
- * Options that are either usage documentation or are compiled out
- * are not to be processed.
- */
- if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
- continue;
- if (pOptDesc->optMaxCt > 1)
- pzFmt = zMultiDef;
- else pzFmt = zSingleDef;
- /*
- * IF this is an enumeration/bitmask option, then convert the value
- * to a string before printing the default value.
- */
- switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) {
- case OPARG_TYPE_ENUMERATION:
- (*(pOptDesc->pOptProc))( (tOptions*)2UL, pOptDesc );
- pzDefault = pOptDesc->optArg.argString;
- break;
- /*
- * Numeric and membership bit options are just printed as a number.
- */
- case OPARG_TYPE_NUMERIC:
- snprintf( zVal, sizeof( zVal ), "%d",
- (int)pOptDesc->optArg.argInt );
- pzDefault = zVal;
- break;
- case OPARG_TYPE_MEMBERSHIP:
- snprintf( zVal, sizeof( zVal ), "%lu",
- (unsigned long)pOptDesc->optArg.argIntptr );
- pzDefault = zVal;
- break;
- case OPARG_TYPE_BOOLEAN:
- pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false";
- break;
- default:
- if (pOptDesc->optArg.argString == NULL) {
- if (pzFmt == zSingleDef)
- pzFmt = zSingleNoDef;
- pzDefault = NULL;
- }
- else
- pzDefault = pOptDesc->optArg.argString;
- }
- printf( pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault );
- }
- }
- static void
- printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc )
- {
- if (pOptDesc->pOptProc == optionPrintVersion)
- printf( zTextExit, pOpts->pzPROGNAME, "VERSION" );
- else if (pOptDesc->pOptProc == optionPagedUsage)
- printf( zPagedUsageExit, pOpts->pzPROGNAME );
- else if (pOptDesc->pOptProc == optionLoadOpt) {
- printf( zCmdFmt, "echo 'Warning: Cannot load options files' >&2" );
- printf( zCmdFmt, "OPT_ARG_NEEDED=YES" );
- } else if (pOptDesc->pz_NAME == NULL) {
- if (pOptDesc->pOptProc == NULL) {
- printf( zCmdFmt, "echo 'Warning: Cannot save options files' "
- ">&2" );
- printf( zCmdFmt, "OPT_ARG_NEEDED=OK" );
- } else
- printf( zTextExit, pOpts->pzPROGNAME, "LONGUSAGE" );
- } else {
- if (pOptDesc->optMaxCt == 1)
- printf( zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
- else {
- if ((unsigned)pOptDesc->optMaxCt < NOLIMIT)
- printf( zCountTest, pOpts->pzPROGNAME,
- pOptDesc->pz_NAME, pOptDesc->optMaxCt );
- printf( zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
- }
- /*
- * Fix up the args.
- */
- if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
- printf( zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
- } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
- printf( zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
- } else {
- fputs( zMustArg, stdout );
- }
- }
- fputs( zOptionEndSelect, stdout );
- }
- static void
- printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc )
- {
- if (pOptDesc->pOptProc == optionLoadOpt) {
- printf( zCmdFmt, "echo 'Warning: Cannot suppress the loading of "
- "options files' >&2" );
- } else if (pOptDesc->optMaxCt == 1)
- printf( zNoSingleArg, pOpts->pzPROGNAME,
- pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
- else
- printf( zNoMultiArg, pOpts->pzPROGNAME,
- pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
- printf( zCmdFmt, "OPT_ARG_NEEDED=NO" );
- fputs( zOptionEndSelect, stdout );
- }
- static void
- emitFlag( tOptions* pOpts )
- {
- tOptDesc* pOptDesc = pOpts->pOptDesc;
- int optionCt = pOpts->optCt;
- fputs( zOptionCase, stdout );
- for (;optionCt > 0; pOptDesc++, --optionCt) {
- if (SKIP_OPT(pOptDesc))
- continue;
- if (isprint( pOptDesc->optValue )) {
- printf( zOptionFlag, pOptDesc->optValue );
- printOptionAction( pOpts, pOptDesc );
- }
- }
- printf( zOptionUnknown, "flag", pOpts->pzPROGNAME );
- }
- /*
- * Emit the match text for a long option
- */
- static void
- emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts )
- {
- tOptDesc* pOD = pOpts->pOptDesc;
- int oCt = pOpts->optCt;
- int min = 1;
- char zName[ 256 ];
- char* pz = zName;
- for (;;) {
- int matchCt = 0;
- /*
- * Omit the current option, Documentation opts and compiled out opts.
- */
- if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
- if (--oCt <= 0)
- break;
- pOD++;
- continue;
- }
- /*
- * Check each character of the name case insensitively.
- * They must not be the same. They cannot be, because it would
- * not compile correctly if they were.
- */
- while ( toupper( pOD->pz_Name[matchCt] )
- == toupper( pzMatchName[matchCt] ))
- matchCt++;
- if (matchCt > min)
- min = matchCt;
- /*
- * Check the disablement name, too.
- */
- if (pOD->pz_DisableName != NULL) {
- matchCt = 0;
- while ( toupper( pOD->pz_DisableName[matchCt] )
- == toupper( pzMatchName[matchCt] ))
- matchCt++;
- if (matchCt > min)
- min = matchCt;
- }
- if (--oCt <= 0)
- break;
- pOD++;
- }
- /*
- * IF the 'min' is all or one short of the name length,
- * THEN the entire string must be matched.
- */
- if ( (pzMatchName[min ] == NUL)
- || (pzMatchName[min+1] == NUL) )
- printf( zOptionFullName, pzMatchName );
- else {
- int matchCt = 0;
- for (; matchCt <= min; matchCt++)
- *pz++ = pzMatchName[matchCt];
- for (;;) {
- *pz = NUL;
- printf( zOptionPartName, zName );
- *pz++ = pzMatchName[matchCt++];
- if (pzMatchName[matchCt] == NUL) {
- *pz = NUL;
- printf( zOptionFullName, zName );
- break;
- }
- }
- }
- }
- /*
- * Emit GNU-standard long option handling code
- */
- static void
- emitLong( tOptions* pOpts )
- {
- tOptDesc* pOD = pOpts->pOptDesc;
- int ct = pOpts->optCt;
- fputs( zOptionCase, stdout );
- /*
- * do each option, ...
- */
- do {
- /*
- * Documentation & compiled-out options
- */
- if (SKIP_OPT(pOD))
- continue;
- emitMatchExpr( pOD->pz_Name, pOD, pOpts );
- printOptionAction( pOpts, pOD );
- /*
- * 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 );
- }
- } while (pOD++, --ct > 0);
- printf( zOptionUnknown, "option", pOpts->pzPROGNAME );
- }
- static void
- openOutput( char const* pzFile )
- {
- FILE* fp;
- char* pzData = NULL;
- struct stat stbf;
- do {
- char* pzScan;
- size_t sizeLeft;
- /*
- * 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)
- break;
- /*
- * The file must be a regular file
- */
- if (! S_ISREG( stbf.st_mode )) {
- fprintf( stderr, zNotFile, pzFile );
- exit( EXIT_FAILURE );
- }
- pzData = AGALOC(stbf.st_size + 1, "file data");
- fp = fopen( pzFile, "r" FOPEN_BINARY_FLAG );
- sizeLeft = (unsigned)stbf.st_size;
- pzScan = pzData;
- /*
- * 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;
- pzScan += inct;
- sizeLeft -= inct;
- if (sizeLeft == 0)
- break;
- }
- /*
- * NUL-terminate the leader and look for the trailer
- */
- *pzScan = '\0';
- fclose( fp );
- pzScan = strstr( pzData, zStartMarker );
- if (pzScan == NULL) {
- pzTrailer = pzData;
- break;
- }
- *(pzScan++) = NUL;
- pzScan = strstr( pzScan, zTrailerMarker );
- if (pzScan == NULL) {
- pzTrailer = pzData;
- break;
- }
- /*
- * 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);
- freopen( pzFile, "w" FOPEN_BINARY_FLAG, stdout );
- }
- /*=export_func genshelloptUsage
- * private:
- * what: The usage function for the genshellopt generated program
- *
- * arg: + tOptions* + pOpts + program options descriptor +
- * arg: + int + exitCode + usage text type to produce +
- *
- * doc:
- * This function is used to create the usage strings for the option
- * processing shell script code. Two child processes are spawned
- * each emitting the usage text in either the short (error exit)
- * style or the long style. The generated program will capture this
- * and create shell script variables containing the two types of text.
- =*/
- void
- genshelloptUsage( tOptions* pOpts, int exitCode )
- {
- #if defined(__windows__) && !defined(__CYGWIN__)
- optionUsage( pOpts, exitCode );
- #else
- /*
- * IF not EXIT_SUCCESS,
- * THEN emit the short form of usage.
- */
- if (exitCode != EXIT_SUCCESS)
- optionUsage( pOpts, exitCode );
- fflush( stderr );
- fflush( stdout );
- option_usage_fp = stdout;
- /*
- * First, print our usage
- */
- switch (fork()) {
- case -1:
- optionUsage( pOpts, EXIT_FAILURE );
- /*NOTREACHED*/
- _exit( EXIT_FAILURE );
- case 0:
- pagerState = PAGER_STATE_CHILD;
- optionUsage( pOpts, EXIT_SUCCESS );
- /*NOTREACHED*/
- _exit( EXIT_FAILURE );
- default:
- {
- int sts;
- wait( &sts );
- }
- }
- /*
- * Generate the pzProgName, since optionProcess() normally
- * gets it from the command line
- */
- {
- char* pz;
- AGDUPSTR( pz, pShellParseOptions->pzPROGNAME, "program name" );
- pShellParseOptions->pzProgName = pz;
- while (*pz != NUL) {
- *pz = tolower( *pz );
- pz++;
- }
- }
- /*
- * Separate the makeshell usage from the client usage
- */
- fprintf( option_usage_fp, zGenshell, pShellParseOptions->pzProgName );
- fflush( option_usage_fp );
- /*
- * Now, print the client usage.
- */
- switch (fork()) {
- case 0:
- pagerState = PAGER_STATE_CHILD;
- /*FALLTHROUGH*/
- case -1:
- optionUsage( pShellParseOptions, EXIT_FAILURE );
- default:
- {
- int sts;
- wait( &sts );
- }
- }
- exit( EXIT_SUCCESS );
- #endif
- }
- /*
- * Local Variables:
- * mode: C
- * c-file-style: "stroustrup"
- * indent-tabs-mode: nil
- * End:
- * end of autoopts/makeshell.c */
|