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