Return to makeshell.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / sntp / libopts |
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 */