Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / ntp / dist / sntp / libopts / makeshell.c
blobd7d2fdd945c973c1a0b8ddff29c96790905a7d76
1 /* $NetBSD$ */
4 /*
5 * Id: 7226344c6486a4eda395f893881080b7d80a2003
6 * Time-stamp: "2009-11-01 11:52:37 bkorb"
8 * This module will interpret the options set in the tOptions
9 * structure and create a Bourne shell script capable of parsing them.
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
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.
19 * The GNU Lesser General Public License, version 3 or later
20 * See the files "COPYING.lgplv3" and "COPYING.gplv3"
22 * The Modified Berkeley Software Distribution License
23 * See the file "COPYING.mbsd"
25 * These files have the following md5sums:
27 * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
28 * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
29 * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
32 tOptions* pShellParseOptions = NULL;
34 /* * * * * * * * * * * * * * * * * * * * *
36 * Setup Format Strings
38 static char const zStartMarker[] =
39 "# # # # # # # # # # -- do not modify this marker --\n#\n"
40 "# DO NOT EDIT THIS SECTION";
42 static 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";
47 static char const zEndPreamble[] =
48 "# From the %s option definitions\n#\n";
50 static 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";
60 static 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";
65 static 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";
70 /* * * * * * * * * * * * * * * * * * * * *
72 * LOOP START
74 * The loop may run in either of two modes:
75 * all options are named options (loop only)
76 * regular, marked option processing.
78 static 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"
85 * 'OPT_ARG' may or may not match the current $1
87 " case \"${OPT_ARG}\" in\n"
88 " -- )\n"
89 " OPT_PROCESS=false\n"
90 " shift\n"
91 " ;;\n\n";
93 static 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";
100 /* * * * * * * * * * * * * * * *
102 * CASE SELECTORS
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)
108 static char const zLongSelection[] =
109 " --* )\n";
111 static char const zFlagSelection[] =
112 " -* )\n";
114 static char const zEndSelection[] =
115 " ;;\n\n";
117 static char const zNoSelection[] =
118 " * )\n"
119 " OPT_PROCESS=false\n"
120 " ;;\n"
121 " esac\n\n";
123 /* * * * * * * * * * * * * * * *
125 * LOOP END
127 static 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";
142 static char const zTrailerMarker[] = "\n"
143 "# # # # # # # # # #\n#\n"
144 "# END OF AUTOMATED OPTION PROCESSING\n"
145 "#\n# # # # # # # # # # -- do not modify this marker --\n";
147 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
149 * OPTION SELECTION
151 static char const zOptionCase[] =
152 " case \"${OPT_CODE}\" in\n";
154 static char const zOptionPartName[] =
155 " '%s' | \\\n";
157 static char const zOptionFullName[] =
158 " '%s' )\n";
160 static char const zOptionFlag[] =
161 " '%c' )\n";
163 static char const zOptionEndSelect[] =
164 " ;;\n\n";
166 static 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";
174 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
176 * OPTION PROCESSING
178 * Formats for emitting the text for handling particular options
180 static char const zTextExit[] =
181 " echo \"$%s_%s_TEXT\"\n"
182 " exit 0\n";
184 static char const zPagedUsageExit[] =
185 " echo \"$%s_LONGUSAGE_TEXT\" | ${PAGER-more}\n"
186 " exit 0\n";
188 static char const zCmdFmt[] =
189 " %s\n";
191 static 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";
197 static 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";
202 static 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";
210 static 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";
217 static 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";
227 static 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";
232 static char const zMustArg[] =
233 " OPT_ARG_NEEDED=YES\n";
235 static 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";
240 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
242 * LONG OPTION PROCESSING
244 * Formats for emitting the text for handling long option types
246 static 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";
254 static 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";
284 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
286 * FLAG OPTION PROCESSING
288 * Formats for emitting the text for handling flag option types
290 static 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";
294 static 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";
341 tSCC* pzShell = NULL;
342 static char* pzLeader = NULL;
343 static char* pzTrailer = NULL;
345 /* = = = START-STATIC-FORWARD = = = */
346 /* static forward declarations maintained by mk-fwd */
347 static void
348 textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD );
350 static void
351 emitUsage( tOptions* pOpts );
353 static void
354 emitSetup( tOptions* pOpts );
356 static void
357 printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc );
359 static void
360 printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc );
362 static void
363 emitFlag( tOptions* pOpts );
365 static void
366 emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts );
368 static void
369 emitLong( tOptions* pOpts );
371 static void
372 openOutput( char const* pzFile );
373 /* = = = END-STATIC-FORWARD = = = */
375 /*=export_func optionParseShell
376 * private:
378 * what: Decipher a boolean value
379 * arg: + tOptions* + pOpts + program options descriptor +
381 * doc:
382 * Emit a shell script that will parse the command line options.
384 void
385 optionParseShell( tOptions* pOpts )
388 * Check for our SHELL option now.
389 * IF the output file contains the "#!" magic marker,
390 * it will override anything we do here.
392 if (HAVE_OPT( SHELL ))
393 pzShell = OPT_ARG( SHELL );
395 else if (! ENABLED_OPT( SHELL ))
396 pzShell = NULL;
398 else if ((pzShell = getenv( "SHELL" )),
399 pzShell == NULL)
401 pzShell = "/bin/sh";
404 * Check for a specified output file
406 if (HAVE_OPT( SCRIPT ))
407 openOutput( OPT_ARG( SCRIPT ));
409 emitUsage( pOpts );
410 emitSetup( pOpts );
413 * There are four modes of option processing.
415 switch (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
416 case OPTPROC_LONGOPT:
417 fputs( zLoopCase, stdout );
419 fputs( zLongSelection, stdout );
420 fputs( zLongOptInit, stdout );
421 emitLong( pOpts );
422 printf( zLongOptArg, pOpts->pzPROGNAME );
423 fputs( zEndSelection, stdout );
425 fputs( zNoSelection, stdout );
426 break;
428 case 0:
429 fputs( zLoopOnly, stdout );
430 fputs( zLongOptInit, stdout );
431 emitLong( pOpts );
432 printf( zLongOptArg, pOpts->pzPROGNAME );
433 break;
435 case OPTPROC_SHORTOPT:
436 fputs( zLoopCase, stdout );
438 fputs( zFlagSelection, stdout );
439 fputs( zFlagOptInit, stdout );
440 emitFlag( pOpts );
441 printf( zFlagOptArg, pOpts->pzPROGNAME );
442 fputs( zEndSelection, stdout );
444 fputs( zNoSelection, stdout );
445 break;
447 case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
448 fputs( zLoopCase, stdout );
450 fputs( zLongSelection, stdout );
451 fputs( zLongOptInit, stdout );
452 emitLong( pOpts );
453 printf( zLongOptArg, pOpts->pzPROGNAME );
454 fputs( zEndSelection, stdout );
456 fputs( zFlagSelection, stdout );
457 fputs( zFlagOptInit, stdout );
458 emitFlag( pOpts );
459 printf( zFlagOptArg, pOpts->pzPROGNAME );
460 fputs( zEndSelection, stdout );
462 fputs( zNoSelection, stdout );
463 break;
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 );
472 fflush( stdout );
473 fchmod( STDOUT_FILENO, 0755 );
474 fclose( stdout );
478 static void
479 textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD )
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_
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;
496 printf( "%s_%s_TEXT='", pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
497 fflush( stdout );
499 if (pipe( pipeFd ) != 0) {
500 fprintf( stderr, zBadPipe, errno, strerror( errno ));
501 exit( EXIT_FAILURE );
504 switch (fork()) {
505 case -1:
506 fprintf( stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
507 exit( EXIT_FAILURE );
508 break;
510 case 0:
511 dup2( pipeFd[1], STDERR_FILENO );
512 dup2( pipeFd[1], STDOUT_FILENO );
513 close( pipeFd[0] );
515 switch (whichVar) {
516 case TT_LONGUSAGE:
517 (*(pOpts->pUsageProc))( pOpts, EXIT_SUCCESS );
518 /* NOTREACHED */
519 exit( EXIT_FAILURE );
521 case TT_USAGE:
522 (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
523 /* NOTREACHED */
524 exit( EXIT_FAILURE );
526 case TT_VERSION:
527 if (pOD->fOptState & OPTST_ALLOC_ARG) {
528 AGFREE(pOD->optArg.argString);
529 pOD->fOptState &= ~OPTST_ALLOC_ARG;
531 pOD->optArg.argString = "c";
532 optionPrintVersion( pOpts, pOD );
533 /* NOTREACHED */
535 default:
536 exit( EXIT_FAILURE );
539 default:
540 close( pipeFd[1] );
541 fp = fdopen( pipeFd[0], "r" FOPEN_BINARY_FLAG );
544 for (;;) {
545 int ch = fgetc( fp );
546 switch (ch) {
548 case '\n':
549 nlHoldCt++;
550 break;
552 case '\'':
553 while (nlHoldCt > 0) {
554 fputc( '\n', stdout );
555 nlHoldCt--;
557 fputs( "'\\''", stdout );
558 break;
560 case EOF:
561 goto endCharLoop;
563 default:
564 while (nlHoldCt > 0) {
565 fputc( '\n', stdout );
566 nlHoldCt--;
568 fputc( ch, stdout );
569 break;
571 } endCharLoop:;
573 fputs( "'\n\n", stdout );
574 close( pipeFd[0] );
575 #endif
579 static void
580 emitUsage( tOptions* pOpts )
582 char zTimeBuf[ AO_NAME_SIZE ];
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.
590 if (pzLeader != NULL)
591 fputs( pzLeader, stdout );
594 tSCC zStdout[] = "stdout";
595 tCC* pzOutName;
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 );
603 if (HAVE_OPT( SCRIPT ))
604 pzOutName = OPT_ARG( SCRIPT );
605 else pzOutName = zStdout;
607 if ((pzLeader == NULL) && (pzShell != NULL))
608 printf( "#! %s\n", pzShell );
610 printf( zPreamble, zStartMarker, pzOutName, zTimeBuf );
614 * Get a copy of the original program name in lower case
617 char* pzPN = zTimeBuf;
618 tCC* pz = pOpts->pzPROGNAME;
619 for (;;) {
620 if ((*pzPN++ = tolower( *pz++ )) == '\0')
621 break;
625 printf( zEndPreamble, pOpts->pzPROGNAME );
627 pOpts->pzProgPath = pOpts->pzProgName = zTimeBuf;
628 textToVariable( pOpts, TT_LONGUSAGE, NULL );
629 textToVariable( pOpts, TT_USAGE, NULL );
632 tOptDesc* pOptDesc = pOpts->pOptDesc;
633 int optionCt = pOpts->optCt;
635 for (;;) {
636 if (pOptDesc->pOptProc == optionPrintVersion) {
637 textToVariable( pOpts, TT_VERSION, pOptDesc );
638 break;
641 if (--optionCt <= 0)
642 break;
643 pOptDesc++;
649 static void
650 emitSetup( tOptions* pOpts )
652 tOptDesc* pOptDesc = pOpts->pOptDesc;
653 int optionCt = pOpts->presetOptCt;
654 char const* pzFmt;
655 char const* pzDefault;
657 for (;optionCt > 0; pOptDesc++, --optionCt) {
658 char zVal[16];
661 * Options that are either usage documentation or are compiled out
662 * are not to be processed.
664 if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
665 continue;
667 if (pOptDesc->optMaxCt > 1)
668 pzFmt = zMultiDef;
669 else pzFmt = zSingleDef;
672 * IF this is an enumeration/bitmask option, then convert the value
673 * to a string before printing the default value.
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;
682 * Numeric and membership bit options are just printed as a number.
684 case OPARG_TYPE_NUMERIC:
685 snprintf( zVal, sizeof( zVal ), "%d",
686 (int)pOptDesc->optArg.argInt );
687 pzDefault = zVal;
688 break;
690 case OPARG_TYPE_MEMBERSHIP:
691 snprintf( zVal, sizeof( zVal ), "%lu",
692 (unsigned long)pOptDesc->optArg.argIntptr );
693 pzDefault = zVal;
694 break;
696 case OPARG_TYPE_BOOLEAN:
697 pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false";
698 break;
700 default:
701 if (pOptDesc->optArg.argString == NULL) {
702 if (pzFmt == zSingleDef)
703 pzFmt = zSingleNoDef;
704 pzDefault = NULL;
706 else
707 pzDefault = pOptDesc->optArg.argString;
710 printf( pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault );
715 static void
716 printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc )
718 if (pOptDesc->pOptProc == optionPrintVersion)
719 printf( zTextExit, pOpts->pzPROGNAME, "VERSION" );
721 else if (pOptDesc->pOptProc == optionPagedUsage)
722 printf( zPagedUsageExit, pOpts->pzPROGNAME );
724 else if (pOptDesc->pOptProc == optionLoadOpt) {
725 printf( zCmdFmt, "echo 'Warning: Cannot load options files' >&2" );
726 printf( zCmdFmt, "OPT_ARG_NEEDED=YES" );
728 } else if (pOptDesc->pz_NAME == NULL) {
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" );
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 );
745 printf( zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
749 * Fix up the args.
751 if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
752 printf( zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
754 } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
755 printf( zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
757 } else {
758 fputs( zMustArg, stdout );
761 fputs( zOptionEndSelect, stdout );
765 static void
766 printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc )
768 if (pOptDesc->pOptProc == optionLoadOpt) {
769 printf( zCmdFmt, "echo 'Warning: Cannot suppress the loading of "
770 "options files' >&2" );
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 );
779 printf( zCmdFmt, "OPT_ARG_NEEDED=NO" );
780 fputs( zOptionEndSelect, stdout );
784 static void
785 emitFlag( tOptions* pOpts )
787 tOptDesc* pOptDesc = pOpts->pOptDesc;
788 int optionCt = pOpts->optCt;
790 fputs( zOptionCase, stdout );
792 for (;optionCt > 0; pOptDesc++, --optionCt) {
794 if (SKIP_OPT(pOptDesc))
795 continue;
797 if (IS_GRAPHIC_CHAR(pOptDesc->optValue)) {
798 printf( zOptionFlag, pOptDesc->optValue );
799 printOptionAction( pOpts, pOptDesc );
802 printf( zOptionUnknown, "flag", pOpts->pzPROGNAME );
807 * Emit the match text for a long option
809 static void
810 emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts )
812 tOptDesc* pOD = pOpts->pOptDesc;
813 int oCt = pOpts->optCt;
814 int min = 1;
815 char zName[ 256 ];
816 char* pz = zName;
818 for (;;) {
819 int matchCt = 0;
822 * Omit the current option, Documentation opts and compiled out opts.
824 if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
825 if (--oCt <= 0)
826 break;
827 pOD++;
828 continue;
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.
836 while ( toupper( pOD->pz_Name[matchCt] )
837 == toupper( pzMatchName[matchCt] ))
838 matchCt++;
840 if (matchCt > min)
841 min = matchCt;
844 * Check the disablement name, too.
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;
854 if (--oCt <= 0)
855 break;
856 pOD++;
860 * IF the 'min' is all or one short of the name length,
861 * THEN the entire string must be matched.
863 if ( (pzMatchName[min ] == NUL)
864 || (pzMatchName[min+1] == NUL) )
865 printf( zOptionFullName, pzMatchName );
867 else {
868 int matchCt = 0;
869 for (; matchCt <= min; matchCt++)
870 *pz++ = pzMatchName[matchCt];
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;
887 * Emit GNU-standard long option handling code
889 static void
890 emitLong( tOptions* pOpts )
892 tOptDesc* pOD = pOpts->pOptDesc;
893 int ct = pOpts->optCt;
895 fputs( zOptionCase, stdout );
898 * do each option, ...
900 do {
902 * Documentation & compiled-out options
904 if (SKIP_OPT(pOD))
905 continue;
907 emitMatchExpr( pOD->pz_Name, pOD, pOpts );
908 printOptionAction( pOpts, pOD );
911 * Now, do the same thing for the disablement version of the option.
913 if (pOD->pz_DisableName != NULL) {
914 emitMatchExpr( pOD->pz_DisableName, pOD, pOpts );
915 printOptionInaction( pOpts, pOD );
917 } while (pOD++, --ct > 0);
919 printf( zOptionUnknown, "option", pOpts->pzPROGNAME );
923 static void
924 openOutput( char const* pzFile )
926 FILE* fp;
927 char* pzData = NULL;
928 struct stat stbf;
930 do {
931 char* pzScan;
932 size_t sizeLeft;
935 * IF we cannot stat the file,
936 * THEN assume we are creating a new file.
937 * Skip the loading of the old data.
939 if (stat( pzFile, &stbf ) != 0)
940 break;
943 * The file must be a regular file
945 if (! S_ISREG( stbf.st_mode )) {
946 fprintf( stderr, zNotFile, pzFile );
947 exit( EXIT_FAILURE );
950 pzData = AGALOC(stbf.st_size + 1, "file data");
951 fp = fopen( pzFile, "r" FOPEN_BINARY_FLAG );
953 sizeLeft = (unsigned)stbf.st_size;
954 pzScan = pzData;
957 * Read in all the data as fast as our OS will let us.
959 for (;;) {
960 int inct = fread( (void*)pzScan, (size_t)1, sizeLeft, fp);
961 if (inct == 0)
962 break;
964 pzScan += inct;
965 sizeLeft -= inct;
967 if (sizeLeft == 0)
968 break;
972 * NUL-terminate the leader and look for the trailer
974 *pzScan = '\0';
975 fclose( fp );
976 pzScan = strstr( pzData, zStartMarker );
977 if (pzScan == NULL) {
978 pzTrailer = pzData;
979 break;
982 *(pzScan++) = NUL;
983 pzScan = strstr( pzScan, zTrailerMarker );
984 if (pzScan == NULL) {
985 pzTrailer = pzData;
986 break;
990 * Check to see if the data contains
991 * our marker. If it does, then we will skip over it
993 pzTrailer = pzScan + sizeof( zTrailerMarker ) - 1;
994 pzLeader = pzData;
995 } while (AG_FALSE);
997 freopen( pzFile, "w" FOPEN_BINARY_FLAG, stdout );
1001 /*=export_func genshelloptUsage
1002 * private:
1003 * what: The usage function for the genshellopt generated program
1005 * arg: + tOptions* + pOpts + program options descriptor +
1006 * arg: + int + exitCode + usage text type to produce +
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.
1015 void
1016 genshelloptUsage( tOptions* pOpts, int exitCode )
1018 #if ! defined(HAVE_WORKING_FORK)
1019 optionUsage( pOpts, exitCode );
1020 #else
1022 * IF not EXIT_SUCCESS,
1023 * THEN emit the short form of usage.
1025 if (exitCode != EXIT_SUCCESS)
1026 optionUsage( pOpts, exitCode );
1027 fflush( stderr );
1028 fflush( stdout );
1030 option_usage_fp = stdout;
1033 * First, print our usage
1035 switch (fork()) {
1036 case -1:
1037 optionUsage( pOpts, EXIT_FAILURE );
1038 /* NOTREACHED */
1039 _exit( EXIT_FAILURE );
1041 case 0:
1042 pagerState = PAGER_STATE_CHILD;
1043 optionUsage( pOpts, EXIT_SUCCESS );
1044 /* NOTREACHED */
1045 _exit( EXIT_FAILURE );
1047 default:
1049 int sts;
1050 wait( &sts );
1055 * Generate the pzProgName, since optionProcess() normally
1056 * gets it from the command line
1059 char* pz;
1060 AGDUPSTR( pz, pShellParseOptions->pzPROGNAME, "program name" );
1061 pShellParseOptions->pzProgName = pz;
1062 while (*pz != NUL) {
1063 *pz = tolower( *pz );
1064 pz++;
1069 * Separate the makeshell usage from the client usage
1071 fprintf( option_usage_fp, zGenshell, pShellParseOptions->pzProgName );
1072 fflush( option_usage_fp );
1075 * Now, print the client usage.
1077 switch (fork()) {
1078 case 0:
1079 pagerState = PAGER_STATE_CHILD;
1080 /*FALLTHROUGH*/
1081 case -1:
1082 optionUsage( pShellParseOptions, EXIT_FAILURE );
1084 default:
1086 int sts;
1087 wait( &sts );
1091 exit( EXIT_SUCCESS );
1092 #endif
1096 * Local Variables:
1097 * mode: C
1098 * c-file-style: "stroustrup"
1099 * indent-tabs-mode: nil
1100 * End:
1101 * end of autoopts/makeshell.c */