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