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