File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / sntp / libopts / makeshell.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 7 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    1: 
    2: /**
    3:  * \file makeshell.c
    4:  *
    5:  * Time-stamp:      "2011-04-20 11:06:57 bkorb"
    6:  *
    7:  *  This module will interpret the options set in the tOptions
    8:  *  structure and create a Bourne shell script capable of parsing them.
    9:  *
   10:  *  This file is part of AutoOpts, a companion to AutoGen.
   11:  *  AutoOpts is free software.
   12:  *  AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
   13:  *
   14:  *  AutoOpts is available under any one of two licenses.  The license
   15:  *  in use must be one of these two and the choice is under the control
   16:  *  of the user of the license.
   17:  *
   18:  *   The GNU Lesser General Public License, version 3 or later
   19:  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
   20:  *
   21:  *   The Modified Berkeley Software Distribution License
   22:  *      See the file "COPYING.mbsd"
   23:  *
   24:  *  These files have the following md5sums:
   25:  *
   26:  *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
   27:  *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
   28:  *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
   29:  */
   30: 
   31: tOptions * optionParseShellOptions = NULL;
   32: 
   33: /* * * * * * * * * * * * * * * * * * * * *
   34:  *
   35:  *  Setup Format Strings
   36:  */
   37: static char const zStartMarker[] =
   38: "# # # # # # # # # # -- do not modify this marker --\n#\n"
   39: "#  DO NOT EDIT THIS SECTION";
   40: 
   41: static char const zPreamble[] =
   42: "%s OF %s\n#\n"
   43: "#  From here to the next `-- do not modify this marker --',\n"
   44: "#  the text has been generated %s\n";
   45: 
   46: static char const zEndPreamble[] =
   47: "#  From the %s option definitions\n#\n";
   48: 
   49: static char const zMultiDef[] = "\n"
   50: "if test -z \"${%1$s_%2$s}\"\n"
   51: "then\n"
   52: "  %1$s_%2$s_CT=0\n"
   53: "else\n"
   54: "  %1$s_%2$s_CT=1\n"
   55: "  %1$s_%2$s_1=\"${%1$s_%2$s}\"\n"
   56: "fi\n"
   57: "export %1$s_%2$s_CT";
   58: 
   59: static char const zSingleDef[] = "\n"
   60: "%1$s_%2$s=\"${%1$s_%2$s-'%3$s'}\"\n"
   61: "%1$s_%2$s_set=false\n"
   62: "export %1$s_%2$s\n";
   63: 
   64: static char const zSingleNoDef[] = "\n"
   65: "%1$s_%2$s=\"${%1$s_%2$s}\"\n"
   66: "%1$s_%2$s_set=false\n"
   67: "export %1$s_%2$s\n";
   68: 
   69: /* * * * * * * * * * * * * * * * * * * * *
   70:  *
   71:  *  LOOP START
   72:  *
   73:  *  The loop may run in either of two modes:
   74:  *  all options are named options (loop only)
   75:  *  regular, marked option processing.
   76:  */
   77: static char const zLoopCase[] = "\n"
   78: "OPT_PROCESS=true\n"
   79: "OPT_ARG=\"$1\"\n\n"
   80: "while ${OPT_PROCESS} && [ $# -gt 0 ]\ndo\n"
   81: "    OPT_ELEMENT=''\n"
   82: "    OPT_ARG_VAL=''\n\n"
   83:      /*
   84:       *  'OPT_ARG' may or may not match the current $1
   85:       */
   86: "    case \"${OPT_ARG}\" in\n"
   87: "    -- )\n"
   88: "        OPT_PROCESS=false\n"
   89: "        shift\n"
   90: "        ;;\n\n";
   91: 
   92: static char const zLoopOnly[] = "\n"
   93: "OPT_ARG=\"$1\"\n\n"
   94: "while [ $# -gt 0 ]\ndo\n"
   95: "    OPT_ELEMENT=''\n"
   96: "    OPT_ARG_VAL=''\n\n"
   97: "    OPT_ARG=\"${1}\"\n";
   98: 
   99: /* * * * * * * * * * * * * * * *
  100:  *
  101:  *  CASE SELECTORS
  102:  *
  103:  *  If the loop runs as a regular option loop,
  104:  *  then we must have selectors for each acceptable option
  105:  *  type (long option, flag character and non-option)
  106:  */
  107: static char const zLongSelection[] =
  108: "    --* )\n";
  109: 
  110: static char const zFlagSelection[] =
  111: "    -* )\n";
  112: 
  113: static char const zEndSelection[] =
  114: "        ;;\n\n";
  115: 
  116: static char const zNoSelection[] =
  117: "    * )\n"
  118: "         OPT_PROCESS=false\n"
  119: "         ;;\n"
  120: "    esac\n\n";
  121: 
  122: /* * * * * * * * * * * * * * * *
  123:  *
  124:  *  LOOP END
  125:  */
  126: static char const zLoopEnd[] =
  127: "    if [ -n \"${OPT_ARG_VAL}\" ]\n"
  128: "    then\n"
  129: "        eval %1$s_${OPT_NAME}${OPT_ELEMENT}=\"'${OPT_ARG_VAL}'\"\n"
  130: "        export %1$s_${OPT_NAME}${OPT_ELEMENT}\n"
  131: "    fi\n"
  132: "done\n\n"
  133: "unset OPT_PROCESS || :\n"
  134: "unset OPT_ELEMENT || :\n"
  135: "unset OPT_ARG || :\n"
  136: "unset OPT_ARG_NEEDED || :\n"
  137: "unset OPT_NAME || :\n"
  138: "unset OPT_CODE || :\n"
  139: "unset OPT_ARG_VAL || :\n%2$s";
  140: 
  141: static char const zTrailerMarker[] = "\n"
  142: "# # # # # # # # # #\n#\n"
  143: "#  END OF AUTOMATED OPTION PROCESSING\n"
  144: "#\n# # # # # # # # # # -- do not modify this marker --\n";
  145: 
  146: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  147:  *
  148:  *  OPTION SELECTION
  149:  */
  150: static char const zOptionCase[] =
  151: "        case \"${OPT_CODE}\" in\n";
  152: 
  153: static char const zOptionPartName[] =
  154: "        '%s' | \\\n";
  155: 
  156: static char const zOptionFullName[] =
  157: "        '%s' )\n";
  158: 
  159: static char const zOptionFlag[] =
  160: "        '%c' )\n";
  161: 
  162: static char const zOptionEndSelect[] =
  163: "            ;;\n\n";
  164: 
  165: static char const zOptionUnknown[] =
  166: "        * )\n"
  167: "            echo Unknown %s: \"${OPT_CODE}\" >&2\n"
  168: "            echo \"$%s_USAGE_TEXT\"\n"
  169: "            exit 1\n"
  170: "            ;;\n"
  171: "        esac\n\n";
  172: 
  173: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  174:  *
  175:  *  OPTION PROCESSING
  176:  *
  177:  *  Formats for emitting the text for handling particular options
  178:  */
  179: static char const zTextExit[] =
  180: "            echo \"$%s_%s_TEXT\"\n"
  181: "            exit 0\n";
  182: 
  183: static char const zPagedUsageExit[] =
  184: "            echo \"$%s_LONGUSAGE_TEXT\" | ${PAGER-more}\n"
  185: "            exit 0\n";
  186: 
  187: static char const zCmdFmt[] =
  188: "            %s\n";
  189: 
  190: static char const zCountTest[] =
  191: "            if [ $%1$s_%2$s_CT -ge %3$d ] ; then\n"
  192: "                echo Error:  more than %3$d %2$s options >&2\n"
  193: "                echo \"$%1$s_USAGE_TEXT\"\n"
  194: "                exit 1 ; fi\n";
  195: 
  196: static char const zMultiArg[] =
  197: "            %1$s_%2$s_CT=`expr ${%1$s_%2$s_CT} + 1`\n"
  198: "            OPT_ELEMENT=\"_${%1$s_%2$s_CT}\"\n"
  199: "            OPT_NAME='%2$s'\n";
  200: 
  201: static char const zSingleArg[] =
  202: "            if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
  203: "                echo Error:  duplicate %2$s option >&2\n"
  204: "                echo \"$%1$s_USAGE_TEXT\"\n"
  205: "                exit 1 ; fi\n"
  206: "            %1$s_%2$s_set=true\n"
  207: "            OPT_NAME='%2$s'\n";
  208: 
  209: static char const zNoMultiArg[] =
  210: "            %1$s_%2$s_CT=0\n"
  211: "            OPT_ELEMENT=''\n"
  212: "            %1$s_%2$s='%3$s'\n"
  213: "            export %1$s_%2$s\n"
  214: "            OPT_NAME='%2$s'\n";
  215: 
  216: static char const zNoSingleArg[] =
  217: "            if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
  218: "                echo Error:  duplicate %2$s option >&2\n"
  219: "                echo \"$%1$s_USAGE_TEXT\"\n"
  220: "                exit 1 ; fi\n"
  221: "            %1$s_%2$s_set=true\n"
  222: "            %1$s_%2$s='%3$s'\n"
  223: "            export %1$s_%2$s\n"
  224: "            OPT_NAME='%2$s'\n";
  225: 
  226: static char const zMayArg[]  =
  227: "            eval %1$s_%2$s${OPT_ELEMENT}=true\n"
  228: "            export %1$s_%2$s${OPT_ELEMENT}\n"
  229: "            OPT_ARG_NEEDED=OK\n";
  230: 
  231: static char const zMustArg[] =
  232: "            OPT_ARG_NEEDED=YES\n";
  233: 
  234: static char const zCantArg[] =
  235: "            eval %1$s_%2$s${OPT_ELEMENT}=true\n"
  236: "            export %1$s_%2$s${OPT_ELEMENT}\n"
  237: "            OPT_ARG_NEEDED=NO\n";
  238: 
  239: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  240:  *
  241:  *  LONG OPTION PROCESSING
  242:  *
  243:  *  Formats for emitting the text for handling long option types
  244:  */
  245: static char const zLongOptInit[] =
  246: "        OPT_CODE=`echo \"X${OPT_ARG}\"|sed 's/^X-*//'`\n"
  247: "        shift\n"
  248: "        OPT_ARG=\"$1\"\n\n"
  249: "        case \"${OPT_CODE}\" in *=* )\n"
  250: "            OPT_ARG_VAL=`echo \"${OPT_CODE}\"|sed 's/^[^=]*=//'`\n"
  251: "            OPT_CODE=`echo \"${OPT_CODE}\"|sed 's/=.*$//'` ;; esac\n\n";
  252: 
  253: static char const zLongOptArg[] =
  254: "        case \"${OPT_ARG_NEEDED}\" in\n"
  255: "        NO )\n"
  256: "            OPT_ARG_VAL=''\n"
  257: "            ;;\n\n"
  258: "        YES )\n"
  259: "            if [ -z \"${OPT_ARG_VAL}\" ]\n"
  260: "            then\n"
  261: "                if [ $# -eq 0 ]\n"
  262: "                then\n"
  263: "                    echo No argument provided for ${OPT_NAME} option >&2\n"
  264: "                    echo \"$%s_USAGE_TEXT\"\n"
  265: "                    exit 1\n"
  266: "                fi\n\n"
  267: "                OPT_ARG_VAL=\"${OPT_ARG}\"\n"
  268: "                shift\n"
  269: "                OPT_ARG=\"$1\"\n"
  270: "            fi\n"
  271: "            ;;\n\n"
  272: "        OK )\n"
  273: "            if [ -z \"${OPT_ARG_VAL}\" ] && [ $# -gt 0 ]\n"
  274: "            then\n"
  275: "                case \"${OPT_ARG}\" in -* ) ;; * )\n"
  276: "                    OPT_ARG_VAL=\"${OPT_ARG}\"\n"
  277: "                    shift\n"
  278: "                    OPT_ARG=\"$1\" ;; esac\n"
  279: "            fi\n"
  280: "            ;;\n"
  281: "        esac\n";
  282: 
  283: /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  284:  *
  285:  *  FLAG OPTION PROCESSING
  286:  *
  287:  *  Formats for emitting the text for handling flag option types
  288:  */
  289: static char const zFlagOptInit[] =
  290: "        OPT_CODE=`echo \"X${OPT_ARG}\" | sed 's/X-\\(.\\).*/\\1/'`\n"
  291: "        OPT_ARG=` echo \"X${OPT_ARG}\" | sed 's/X-.//'`\n\n";
  292: 
  293: static char const zFlagOptArg[] =
  294: "        case \"${OPT_ARG_NEEDED}\" in\n"
  295: "        NO )\n"
  296: "            if [ -n \"${OPT_ARG}\" ]\n"
  297: "            then\n"
  298: "                OPT_ARG=-\"${OPT_ARG}\"\n"
  299: "            else\n"
  300: "                shift\n"
  301: "                OPT_ARG=\"$1\"\n"
  302: "            fi\n"
  303: "            ;;\n\n"
  304: "        YES )\n"
  305: "            if [ -n \"${OPT_ARG}\" ]\n"
  306: "            then\n"
  307: "                OPT_ARG_VAL=\"${OPT_ARG}\"\n\n"
  308: "            else\n"
  309: "                if [ $# -eq 0 ]\n"
  310: "                then\n"
  311: "                    echo No argument provided for ${OPT_NAME} option >&2\n"
  312: "                    echo \"$%s_USAGE_TEXT\"\n"
  313: "                    exit 1\n"
  314: "                fi\n"
  315: "                shift\n"
  316: "                OPT_ARG_VAL=\"$1\"\n"
  317: "            fi\n\n"
  318: "            shift\n"
  319: "            OPT_ARG=\"$1\"\n"
  320: "            ;;\n\n"
  321: "        OK )\n"
  322: "            if [ -n \"${OPT_ARG}\" ]\n"
  323: "            then\n"
  324: "                OPT_ARG_VAL=\"${OPT_ARG}\"\n"
  325: "                shift\n"
  326: "                OPT_ARG=\"$1\"\n\n"
  327: "            else\n"
  328: "                shift\n"
  329: "                if [ $# -gt 0 ]\n"
  330: "                then\n"
  331: "                    case \"$1\" in -* ) ;; * )\n"
  332: "                        OPT_ARG_VAL=\"$1\"\n"
  333: "                        shift ;; esac\n"
  334: "                    OPT_ARG=\"$1\"\n"
  335: "                fi\n"
  336: "            fi\n"
  337: "            ;;\n"
  338: "        esac\n";
  339: 
  340: tSCC* pzShell = NULL;
  341: static char*  pzLeader  = NULL;
  342: static char*  pzTrailer = NULL;
  343: 
  344: /* = = = START-STATIC-FORWARD = = = */
  345: static void
  346: emit_var_text(char const * prog, char const * var, int fdin);
  347: 
  348: static void
  349: textToVariable(tOptions * pOpts, teTextTo whichVar, tOptDesc * pOD);
  350: 
  351: static void
  352: emitUsage(tOptions* pOpts);
  353: 
  354: static void
  355: emitSetup(tOptions* pOpts);
  356: 
  357: static void
  358: printOptionAction(tOptions* pOpts, tOptDesc* pOptDesc);
  359: 
  360: static void
  361: printOptionInaction(tOptions* pOpts, tOptDesc* pOptDesc);
  362: 
  363: static void
  364: emitFlag(tOptions* pOpts);
  365: 
  366: static void
  367: emitMatchExpr(tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts);
  368: 
  369: static void
  370: emitLong(tOptions* pOpts);
  371: 
  372: static void
  373: openOutput(char const* pzFile);
  374: /* = = = END-STATIC-FORWARD = = = */
  375: 
  376: /*=export_func  optionParseShell
  377:  * private:
  378:  *
  379:  * what:  Decipher a boolean value
  380:  * arg:   + tOptions* + pOpts    + program options descriptor +
  381:  *
  382:  * doc:
  383:  *  Emit a shell script that will parse the command line options.
  384: =*/
  385: void
  386: optionParseShell(tOptions* pOpts)
  387: {
  388:     /*
  389:      *  Check for our SHELL option now.
  390:      *  IF the output file contains the "#!" magic marker,
  391:      *  it will override anything we do here.
  392:      */
  393:     if (HAVE_GENSHELL_OPT(SHELL))
  394:         pzShell = GENSHELL_OPT_ARG(SHELL);
  395: 
  396:     else if (! ENABLED_GENSHELL_OPT(SHELL))
  397:         pzShell = NULL;
  398: 
  399:     else if ((pzShell = getenv("SHELL")),
  400:              pzShell == NULL)
  401: 
  402:         pzShell = POSIX_SHELL;
  403: 
  404:     /*
  405:      *  Check for a specified output file
  406:      */
  407:     if (HAVE_GENSHELL_OPT(SCRIPT))
  408:         openOutput(GENSHELL_OPT_ARG(SCRIPT));
  409: 
  410:     emitUsage(pOpts);
  411:     emitSetup(pOpts);
  412: 
  413:     /*
  414:      *  There are four modes of option processing.
  415:      */
  416:     switch (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
  417:     case OPTPROC_LONGOPT:
  418:         fputs(zLoopCase,        stdout);
  419: 
  420:         fputs(zLongSelection,   stdout);
  421:         fputs(zLongOptInit,     stdout);
  422:         emitLong(pOpts);
  423:         printf(zLongOptArg,     pOpts->pzPROGNAME);
  424:         fputs(zEndSelection,    stdout);
  425: 
  426:         fputs(zNoSelection,     stdout);
  427:         break;
  428: 
  429:     case 0:
  430:         fputs(zLoopOnly,        stdout);
  431:         fputs(zLongOptInit,     stdout);
  432:         emitLong(pOpts);
  433:         printf(zLongOptArg,     pOpts->pzPROGNAME);
  434:         break;
  435: 
  436:     case OPTPROC_SHORTOPT:
  437:         fputs(zLoopCase,        stdout);
  438: 
  439:         fputs(zFlagSelection,   stdout);
  440:         fputs(zFlagOptInit,     stdout);
  441:         emitFlag(pOpts);
  442:         printf(zFlagOptArg,     pOpts->pzPROGNAME);
  443:         fputs(zEndSelection,    stdout);
  444: 
  445:         fputs(zNoSelection,     stdout);
  446:         break;
  447: 
  448:     case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
  449:         fputs(zLoopCase,        stdout);
  450: 
  451:         fputs(zLongSelection,   stdout);
  452:         fputs(zLongOptInit,     stdout);
  453:         emitLong(pOpts);
  454:         printf(zLongOptArg,     pOpts->pzPROGNAME);
  455:         fputs(zEndSelection,    stdout);
  456: 
  457:         fputs(zFlagSelection,   stdout);
  458:         fputs(zFlagOptInit,     stdout);
  459:         emitFlag(pOpts);
  460:         printf(zFlagOptArg,     pOpts->pzPROGNAME);
  461:         fputs(zEndSelection,    stdout);
  462: 
  463:         fputs(zNoSelection,     stdout);
  464:         break;
  465:     }
  466: 
  467:     printf(zLoopEnd, pOpts->pzPROGNAME, zTrailerMarker);
  468:     if ((pzTrailer != NULL) && (*pzTrailer != '\0'))
  469:         fputs(pzTrailer, stdout);
  470:     else if (ENABLED_GENSHELL_OPT(SHELL))
  471:         printf("\nenv | grep '^%s_'\n", pOpts->pzPROGNAME);
  472: 
  473:     fflush(stdout);
  474:     fchmod(STDOUT_FILENO, 0755);
  475:     fclose(stdout);
  476:     if (ferror(stdout)) {
  477:         fputs(zOutputFail, stderr);
  478:         exit(EXIT_FAILURE);
  479:     }
  480: }
  481: 
  482: #ifdef HAVE_WORKING_FORK
  483: static void
  484: emit_var_text(char const * prog, char const * var, int fdin)
  485: {
  486:     FILE * fp   = fdopen(fdin, "r" FOPEN_BINARY_FLAG);
  487:     int    nlct = 0; /* defer newlines and skip trailing ones */
  488: 
  489:     printf("%s_%s_TEXT='", prog, var);
  490:     if (fp == NULL)
  491:         goto skip_text;
  492: 
  493:     for (;;) {
  494:         int  ch = fgetc(fp);
  495:         switch (ch) {
  496: 
  497:         case '\n':
  498:             nlct++;
  499:             break;
  500: 
  501:         case '\'':
  502:             while (nlct > 0) {
  503:                 fputc('\n', stdout);
  504:                 nlct--;
  505:             }
  506:             fputs("'\\''", stdout);
  507:             break;
  508: 
  509:         case EOF:
  510:             goto endCharLoop;
  511: 
  512:         default:
  513:             while (nlct > 0) {
  514:                 fputc('\n', stdout);
  515:                 nlct--;
  516:             }
  517:             fputc(ch, stdout);
  518:             break;
  519:         }
  520:     } endCharLoop:;
  521: 
  522:     fclose(fp);
  523: 
  524: skip_text:
  525: 
  526:     fputs("'\n\n", stdout);
  527: }
  528: 
  529: #endif
  530: 
  531: /*
  532:  *  The purpose of this function is to assign "long usage", short usage
  533:  *  and version information to a shell variable.  Rather than wind our
  534:  *  way through all the logic necessary to emit the text directly, we
  535:  *  fork(), have our child process emit the text the normal way and
  536:  *  capture the output in the parent process.
  537:  */
  538: static void
  539: textToVariable(tOptions * pOpts, teTextTo whichVar, tOptDesc * pOD)
  540: {
  541: #   define _TT_(n) static char const z ## n [] = #n;
  542:     TEXTTO_TABLE
  543: #   undef _TT_
  544: #   define _TT_(n) z ## n ,
  545:       static char const * apzTTNames[] = { TEXTTO_TABLE };
  546: #   undef _TT_
  547: 
  548: #if ! defined(HAVE_WORKING_FORK)
  549:     printf("%1$s_%2$s_TEXT='no %2$s text'\n",
  550:            pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
  551: #else
  552:     int  pipeFd[2];
  553: 
  554:     fflush(stdout);
  555:     fflush(stderr);
  556: 
  557:     if (pipe(pipeFd) != 0) {
  558:         fprintf(stderr, zBadPipe, errno, strerror(errno));
  559:         exit(EXIT_FAILURE);
  560:     }
  561: 
  562:     switch (fork()) {
  563:     case -1:
  564:         fprintf(stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
  565:         exit(EXIT_FAILURE);
  566:         break;
  567: 
  568:     case 0:
  569:         /*
  570:          * Send both stderr and stdout to the pipe.  No matter which
  571:          * descriptor is used, we capture the output on the read end.
  572:          */
  573:         dup2(pipeFd[1], STDERR_FILENO);
  574:         dup2(pipeFd[1], STDOUT_FILENO);
  575:         close(pipeFd[0]);
  576: 
  577:         switch (whichVar) {
  578:         case TT_LONGUSAGE:
  579:             (*(pOpts->pUsageProc))(pOpts, EXIT_SUCCESS);
  580:             /* NOTREACHED */
  581: 
  582:         case TT_USAGE:
  583:             (*(pOpts->pUsageProc))(pOpts, EXIT_FAILURE);
  584:             /* NOTREACHED */
  585: 
  586:         case TT_VERSION:
  587:             if (pOD->fOptState & OPTST_ALLOC_ARG) {
  588:                 AGFREE(pOD->optArg.argString);
  589:                 pOD->fOptState &= ~OPTST_ALLOC_ARG;
  590:             }
  591:             pOD->optArg.argString = "c";
  592:             optionPrintVersion(pOpts, pOD);
  593:             /* NOTREACHED */
  594: 
  595:         default:
  596:             exit(EXIT_FAILURE);
  597:         }
  598: 
  599:     default:
  600:         close(pipeFd[1]);
  601:     }
  602: 
  603:     emit_var_text(pOpts->pzPROGNAME, apzTTNames[whichVar], pipeFd[0]);
  604: #endif
  605: }
  606: 
  607: 
  608: static void
  609: emitUsage(tOptions* pOpts)
  610: {
  611:     char zTimeBuf[AO_NAME_SIZE];
  612: 
  613:     /*
  614:      *  First, switch stdout to the output file name.
  615:      *  Then, change the program name to the one defined
  616:      *  by the definitions (rather than the current
  617:      *  executable name).  Down case the upper cased name.
  618:      */
  619:     if (pzLeader != NULL)
  620:         fputs(pzLeader, stdout);
  621: 
  622:     {
  623:         tSCC    zStdout[] = "stdout";
  624:         tCC*    pzOutName;
  625: 
  626:         {
  627:             time_t    curTime = time(NULL);
  628:             struct tm*  pTime = localtime(&curTime);
  629:             strftime(zTimeBuf, AO_NAME_SIZE, "%A %B %e, %Y at %r %Z", pTime );
  630:         }
  631: 
  632:         if (HAVE_GENSHELL_OPT(SCRIPT))
  633:              pzOutName = GENSHELL_OPT_ARG(SCRIPT);
  634:         else pzOutName = zStdout;
  635: 
  636:         if ((pzLeader == NULL) && (pzShell != NULL))
  637:             printf("#! %s\n", pzShell);
  638: 
  639:         printf(zPreamble, zStartMarker, pzOutName, zTimeBuf);
  640:     }
  641: 
  642:     printf(zEndPreamble, pOpts->pzPROGNAME);
  643: 
  644:     /*
  645:      *  Get a copy of the original program name in lower case and
  646:      *  fill in an approximation of the program name from it.
  647:      */
  648:     {
  649:         char *       pzPN = zTimeBuf;
  650:         char const * pz   = pOpts->pzPROGNAME;
  651:         char **      pp;
  652: 
  653:         for (;;) {
  654:             if ((*pzPN++ = tolower(*pz++)) == '\0')
  655:                 break;
  656:         }
  657: 
  658:         pp = (char **)(void *)&(pOpts->pzProgPath);
  659:         *pp = zTimeBuf;
  660:         pp  = (char **)(void *)&(pOpts->pzProgName);
  661:         *pp = zTimeBuf;
  662:     }
  663: 
  664:     textToVariable(pOpts, TT_LONGUSAGE, NULL);
  665:     textToVariable(pOpts, TT_USAGE,     NULL);
  666: 
  667:     {
  668:         tOptDesc* pOptDesc = pOpts->pOptDesc;
  669:         int       optionCt = pOpts->optCt;
  670: 
  671:         for (;;) {
  672:             if (pOptDesc->pOptProc == optionPrintVersion) {
  673:                 textToVariable(pOpts, TT_VERSION, pOptDesc);
  674:                 break;
  675:             }
  676: 
  677:             if (--optionCt <= 0)
  678:                 break;
  679:             pOptDesc++;
  680:         }
  681:     }
  682: }
  683: 
  684: 
  685: static void
  686: emitSetup(tOptions* pOpts)
  687: {
  688:     tOptDesc* pOptDesc = pOpts->pOptDesc;
  689:     int       optionCt = pOpts->presetOptCt;
  690:     char const* pzFmt;
  691:     char const* pzDefault;
  692: 
  693:     for (;optionCt > 0; pOptDesc++, --optionCt) {
  694:         char zVal[16];
  695: 
  696:         /*
  697:          *  Options that are either usage documentation or are compiled out
  698:          *  are not to be processed.
  699:          */
  700:         if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
  701:             continue;
  702: 
  703:         if (pOptDesc->optMaxCt > 1)
  704:              pzFmt = zMultiDef;
  705:         else pzFmt = zSingleDef;
  706: 
  707:         /*
  708:          *  IF this is an enumeration/bitmask option, then convert the value
  709:          *  to a string before printing the default value.
  710:          */
  711:         switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) {
  712:         case OPARG_TYPE_ENUMERATION:
  713:             (*(pOptDesc->pOptProc))(OPTPROC_EMIT_SHELL, pOptDesc );
  714:             pzDefault = pOptDesc->optArg.argString;
  715:             break;
  716: 
  717:         /*
  718:          *  Numeric and membership bit options are just printed as a number.
  719:          */
  720:         case OPARG_TYPE_NUMERIC:
  721:             snprintf(zVal, sizeof(zVal), "%d",
  722:                      (int)pOptDesc->optArg.argInt);
  723:             pzDefault = zVal;
  724:             break;
  725: 
  726:         case OPARG_TYPE_MEMBERSHIP:
  727:             snprintf(zVal, sizeof(zVal), "%lu",
  728:                      (unsigned long)pOptDesc->optArg.argIntptr);
  729:             pzDefault = zVal;
  730:             break;
  731: 
  732:         case OPARG_TYPE_BOOLEAN:
  733:             pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false";
  734:             break;
  735: 
  736:         default:
  737:             if (pOptDesc->optArg.argString == NULL) {
  738:                 if (pzFmt == zSingleDef)
  739:                     pzFmt = zSingleNoDef;
  740:                 pzDefault = NULL;
  741:             }
  742:             else
  743:                 pzDefault = pOptDesc->optArg.argString;
  744:         }
  745: 
  746:         printf(pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault);
  747:     }
  748: }
  749: 
  750: 
  751: static void
  752: printOptionAction(tOptions* pOpts, tOptDesc* pOptDesc)
  753: {
  754:     if (pOptDesc->pOptProc == optionPrintVersion)
  755:         printf(zTextExit, pOpts->pzPROGNAME, "VERSION");
  756: 
  757:     else if (pOptDesc->pOptProc == optionPagedUsage)
  758:         printf(zPagedUsageExit, pOpts->pzPROGNAME);
  759: 
  760:     else if (pOptDesc->pOptProc == optionLoadOpt) {
  761:         printf(zCmdFmt, "echo 'Warning:  Cannot load options files' >&2");
  762:         printf(zCmdFmt, "OPT_ARG_NEEDED=YES");
  763: 
  764:     } else if (pOptDesc->pz_NAME == NULL) {
  765: 
  766:         if (pOptDesc->pOptProc == NULL) {
  767:             printf(zCmdFmt, "echo 'Warning:  Cannot save options files' "
  768:                     ">&2");
  769:             printf(zCmdFmt, "OPT_ARG_NEEDED=OK");
  770:         } else
  771:             printf(zTextExit, pOpts->pzPROGNAME, "LONGUSAGE");
  772: 
  773:     } else {
  774:         if (pOptDesc->optMaxCt == 1)
  775:             printf(zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
  776:         else {
  777:             if ((unsigned)pOptDesc->optMaxCt < NOLIMIT)
  778:                 printf(zCountTest, pOpts->pzPROGNAME,
  779:                        pOptDesc->pz_NAME, pOptDesc->optMaxCt);
  780: 
  781:             printf(zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
  782:         }
  783: 
  784:         /*
  785:          *  Fix up the args.
  786:          */
  787:         if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
  788:             printf(zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME);
  789: 
  790:         } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
  791:             printf(zMayArg,  pOpts->pzPROGNAME, pOptDesc->pz_NAME);
  792: 
  793:         } else {
  794:             fputs(zMustArg, stdout);
  795:         }
  796:     }
  797:     fputs(zOptionEndSelect, stdout);
  798: }
  799: 
  800: 
  801: static void
  802: printOptionInaction(tOptions* pOpts, tOptDesc* pOptDesc)
  803: {
  804:     if (pOptDesc->pOptProc == optionLoadOpt) {
  805:         printf(zCmdFmt, "echo 'Warning:  Cannot suppress the loading of "
  806:                 "options files' >&2");
  807: 
  808:     } else if (pOptDesc->optMaxCt == 1)
  809:         printf(zNoSingleArg, pOpts->pzPROGNAME,
  810:                pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx);
  811:     else
  812:         printf(zNoMultiArg, pOpts->pzPROGNAME,
  813:                pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx);
  814: 
  815:     printf(zCmdFmt, "OPT_ARG_NEEDED=NO");
  816:     fputs(zOptionEndSelect, stdout);
  817: }
  818: 
  819: 
  820: static void
  821: emitFlag(tOptions* pOpts)
  822: {
  823:     tOptDesc* pOptDesc = pOpts->pOptDesc;
  824:     int       optionCt = pOpts->optCt;
  825: 
  826:     fputs(zOptionCase, stdout);
  827: 
  828:     for (;optionCt > 0; pOptDesc++, --optionCt) {
  829: 
  830:         if (SKIP_OPT(pOptDesc))
  831:             continue;
  832: 
  833:         if (IS_GRAPHIC_CHAR(pOptDesc->optValue)) {
  834:             printf(zOptionFlag, pOptDesc->optValue);
  835:             printOptionAction(pOpts, pOptDesc);
  836:         }
  837:     }
  838:     printf(zOptionUnknown, "flag", pOpts->pzPROGNAME);
  839: }
  840: 
  841: 
  842: /*
  843:  *  Emit the match text for a long option
  844:  */
  845: static void
  846: emitMatchExpr(tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts)
  847: {
  848:     tOptDesc* pOD = pOpts->pOptDesc;
  849:     int       oCt = pOpts->optCt;
  850:     int       min = 1;
  851:     char      zName[ 256 ];
  852:     char*     pz  = zName;
  853: 
  854:     for (;;) {
  855:         int matchCt = 0;
  856: 
  857:         /*
  858:          *  Omit the current option, Documentation opts and compiled out opts.
  859:          */
  860:         if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
  861:             if (--oCt <= 0)
  862:                 break;
  863:             pOD++;
  864:             continue;
  865:         }
  866: 
  867:         /*
  868:          *  Check each character of the name case insensitively.
  869:          *  They must not be the same.  They cannot be, because it would
  870:          *  not compile correctly if they were.
  871:          */
  872:         while (  toupper(pOD->pz_Name[matchCt])
  873:               == toupper(pzMatchName[matchCt]))
  874:             matchCt++;
  875: 
  876:         if (matchCt > min)
  877:             min = matchCt;
  878: 
  879:         /*
  880:          *  Check the disablement name, too.
  881:          */
  882:         if (pOD->pz_DisableName != NULL) {
  883:             matchCt = 0;
  884:             while (  toupper(pOD->pz_DisableName[matchCt])
  885:                   == toupper(pzMatchName[matchCt]))
  886:                 matchCt++;
  887:             if (matchCt > min)
  888:                 min = matchCt;
  889:         }
  890:         if (--oCt <= 0)
  891:             break;
  892:         pOD++;
  893:     }
  894: 
  895:     /*
  896:      *  IF the 'min' is all or one short of the name length,
  897:      *  THEN the entire string must be matched.
  898:      */
  899:     if (  (pzMatchName[min  ] == NUL)
  900:        || (pzMatchName[min+1] == NUL) )
  901:         printf(zOptionFullName, pzMatchName);
  902: 
  903:     else {
  904:         int matchCt = 0;
  905:         for (; matchCt <= min; matchCt++)
  906:             *pz++ = pzMatchName[matchCt];
  907: 
  908:         for (;;) {
  909:             *pz = NUL;
  910:             printf(zOptionPartName, zName);
  911:             *pz++ = pzMatchName[matchCt++];
  912:             if (pzMatchName[matchCt] == NUL) {
  913:                 *pz = NUL;
  914:                 printf(zOptionFullName, zName);
  915:                 break;
  916:             }
  917:         }
  918:     }
  919: }
  920: 
  921: 
  922: /*
  923:  *  Emit GNU-standard long option handling code
  924:  */
  925: static void
  926: emitLong(tOptions* pOpts)
  927: {
  928:     tOptDesc* pOD = pOpts->pOptDesc;
  929:     int       ct  = pOpts->optCt;
  930: 
  931:     fputs(zOptionCase, stdout);
  932: 
  933:     /*
  934:      *  do each option, ...
  935:      */
  936:     do  {
  937:         /*
  938:          *  Documentation & compiled-out options
  939:          */
  940:         if (SKIP_OPT(pOD))
  941:             continue;
  942: 
  943:         emitMatchExpr(pOD->pz_Name, pOD, pOpts);
  944:         printOptionAction(pOpts, pOD);
  945: 
  946:         /*
  947:          *  Now, do the same thing for the disablement version of the option.
  948:          */
  949:         if (pOD->pz_DisableName != NULL) {
  950:             emitMatchExpr(pOD->pz_DisableName, pOD, pOpts);
  951:             printOptionInaction(pOpts, pOD);
  952:         }
  953:     } while (pOD++, --ct > 0);
  954: 
  955:     printf(zOptionUnknown, "option", pOpts->pzPROGNAME);
  956: }
  957: 
  958: 
  959: static void
  960: openOutput(char const* pzFile)
  961: {
  962:     FILE* fp;
  963:     char* pzData = NULL;
  964:     struct stat stbf;
  965: 
  966:     do  {
  967:         char*    pzScan;
  968:         size_t sizeLeft;
  969: 
  970:         /*
  971:          *  IF we cannot stat the file,
  972:          *  THEN assume we are creating a new file.
  973:          *       Skip the loading of the old data.
  974:          */
  975:         if (stat(pzFile, &stbf) != 0)
  976:             break;
  977: 
  978:         /*
  979:          *  The file must be a regular file
  980:          */
  981:         if (! S_ISREG(stbf.st_mode)) {
  982:             fprintf(stderr, zNotFile, pzFile);
  983:             exit(EXIT_FAILURE);
  984:         }
  985: 
  986:         pzData = AGALOC(stbf.st_size + 1, "file data");
  987:         fp = fopen(pzFile, "r" FOPEN_BINARY_FLAG);
  988: 
  989:         sizeLeft = (unsigned)stbf.st_size;
  990:         pzScan   = pzData;
  991: 
  992:         /*
  993:          *  Read in all the data as fast as our OS will let us.
  994:          */
  995:         for (;;) {
  996:             int inct = fread((void*)pzScan, (size_t)1, sizeLeft, fp);
  997:             if (inct == 0)
  998:                 break;
  999: 
 1000:             pzScan   += inct;
 1001:             sizeLeft -= inct;
 1002: 
 1003:             if (sizeLeft == 0)
 1004:                 break;
 1005:         }
 1006: 
 1007:         /*
 1008:          *  NUL-terminate the leader and look for the trailer
 1009:          */
 1010:         *pzScan = '\0';
 1011:         fclose(fp);
 1012:         pzScan  = strstr(pzData, zStartMarker);
 1013:         if (pzScan == NULL) {
 1014:             pzTrailer = pzData;
 1015:             break;
 1016:         }
 1017: 
 1018:         *(pzScan++) = NUL;
 1019:         pzScan  = strstr(pzScan, zTrailerMarker);
 1020:         if (pzScan == NULL) {
 1021:             pzTrailer = pzData;
 1022:             break;
 1023:         }
 1024: 
 1025:         /*
 1026:          *  Check to see if the data contains our marker.
 1027:          *  If it does, then we will skip over it
 1028:          */
 1029:         pzTrailer = pzScan + sizeof(zTrailerMarker) - 1;
 1030:         pzLeader  = pzData;
 1031:     } while (AG_FALSE);
 1032: 
 1033:     if (freopen(pzFile, "w" FOPEN_BINARY_FLAG, stdout) != stdout) {
 1034:         fprintf(stderr, zFreopenFail, errno, strerror(errno));
 1035:         exit(EXIT_FAILURE);
 1036:     }
 1037: }
 1038: 
 1039: 
 1040: /*=export_func genshelloptUsage
 1041:  * private:
 1042:  * what: The usage function for the genshellopt generated program
 1043:  *
 1044:  * arg:  + tOptions* + pOpts    + program options descriptor +
 1045:  * arg:  + int       + exitCode + usage text type to produce +
 1046:  *
 1047:  * doc:
 1048:  *  This function is used to create the usage strings for the option
 1049:  *  processing shell script code.  Two child processes are spawned
 1050:  *  each emitting the usage text in either the short (error exit)
 1051:  *  style or the long style.  The generated program will capture this
 1052:  *  and create shell script variables containing the two types of text.
 1053: =*/
 1054: void
 1055: genshelloptUsage(tOptions * pOpts, int exitCode)
 1056: {
 1057: #if ! defined(HAVE_WORKING_FORK)
 1058:     optionUsage(pOpts, exitCode);
 1059: #else
 1060:     /*
 1061:      *  IF not EXIT_SUCCESS,
 1062:      *  THEN emit the short form of usage.
 1063:      */
 1064:     if (exitCode != EXIT_SUCCESS)
 1065:         optionUsage(pOpts, exitCode);
 1066:     fflush(stderr);
 1067:     fflush(stdout);
 1068:     if (ferror(stdout) || ferror(stderr))
 1069:         exit(EXIT_FAILURE);
 1070: 
 1071:     option_usage_fp = stdout;
 1072: 
 1073:     /*
 1074:      *  First, print our usage
 1075:      */
 1076:     switch (fork()) {
 1077:     case -1:
 1078:         optionUsage(pOpts, EXIT_FAILURE);
 1079:         /* NOTREACHED */
 1080: 
 1081:     case 0:
 1082:         pagerState = PAGER_STATE_CHILD;
 1083:         optionUsage(pOpts, EXIT_SUCCESS);
 1084:         /* NOTREACHED */
 1085:         _exit(EXIT_FAILURE);
 1086: 
 1087:     default:
 1088:     {
 1089:         int  sts;
 1090:         wait(&sts);
 1091:     }
 1092:     }
 1093: 
 1094:     /*
 1095:      *  Generate the pzProgName, since optionProcess() normally
 1096:      *  gets it from the command line
 1097:      */
 1098:     {
 1099:         char *  pz;
 1100:         char ** pp = (char **)(void *)&(optionParseShellOptions->pzProgName);
 1101:         AGDUPSTR(pz, optionParseShellOptions->pzPROGNAME, "program name");
 1102:         *pp = pz;
 1103:         while (*pz != NUL) {
 1104:             *pz = tolower(*pz);
 1105:             pz++;
 1106:         }
 1107:     }
 1108: 
 1109:     /*
 1110:      *  Separate the makeshell usage from the client usage
 1111:      */
 1112:     fprintf(option_usage_fp, zGenshell, optionParseShellOptions->pzProgName);
 1113:     fflush(option_usage_fp);
 1114: 
 1115:     /*
 1116:      *  Now, print the client usage.
 1117:      */
 1118:     switch (fork()) {
 1119:     case 0:
 1120:         pagerState = PAGER_STATE_CHILD;
 1121:         /*FALLTHROUGH*/
 1122:     case -1:
 1123:         optionUsage(optionParseShellOptions, EXIT_FAILURE);
 1124: 
 1125:     default:
 1126:     {
 1127:         int  sts;
 1128:         wait(&sts);
 1129:     }
 1130:     }
 1131: 
 1132:     fflush(stdout);
 1133:     if (ferror(stdout)) {
 1134:         fputs(zOutputFail, stderr);
 1135:         exit(EXIT_FAILURE);
 1136:     }
 1137: 
 1138:     exit(EXIT_SUCCESS);
 1139: #endif
 1140: }
 1141: 
 1142: /*
 1143:  * Local Variables:
 1144:  * mode: C
 1145:  * c-file-style: "stroustrup"
 1146:  * indent-tabs-mode: nil
 1147:  * End:
 1148:  * end of autoopts/makeshell.c */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>