Annotation of embedaddon/ntp/sntp/libopts/makeshell.c, revision 1.1.1.1

1.1       misho       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>