PageRenderTime 88ms CodeModel.GetById 12ms app.highlight 68ms RepoModel.GetById 1ms app.codeStats 1ms

/contrib/ntp/sntp/libopts/makeshell.c

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