turns printfs back on
[freebsd-src/fkvm-freebsd.git] / contrib / ntp / libopts / makeshell.c
blob8447d454b0837bfa30c7ad27d6010fd16b560645
2 /*
3 * $Id: makeshell.c,v 4.20 2007/02/04 17:44:12 bkorb Exp $
4 * Time-stamp: "2007-01-27 06:05:45 bkorb"
6 * This module will interpret the options set in the tOptions
7 * structure and create a Bourne shell script capable of parsing them.
8 */
11 * Automated Options copyright 1992-2007 Bruce Korb
13 * Automated Options is free software.
14 * You may redistribute it and/or modify it under the terms of the
15 * GNU General Public License, as published by the Free Software
16 * Foundation; either version 2, or (at your option) any later version.
18 * Automated Options is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with Automated Options. See the file "COPYING". If not,
25 * write to: The Free Software Foundation, Inc.,
26 * 51 Franklin Street, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
29 * As a special exception, Bruce Korb gives permission for additional
30 * uses of the text contained in his release of AutoOpts.
32 * The exception is that, if you link the AutoOpts library with other
33 * files to produce an executable, this does not by itself cause the
34 * resulting executable to be covered by the GNU General Public License.
35 * Your use of that executable is in no way restricted on account of
36 * linking the AutoOpts library code into it.
38 * This exception does not however invalidate any other reasons why
39 * the executable file might be covered by the GNU General Public License.
41 * This exception applies only to the code released by Bruce Korb under
42 * the name AutoOpts. If you copy code from other sources under the
43 * General Public License into a copy of AutoOpts, as the General Public
44 * License permits, the exception does not apply to the code that you add
45 * in this way. To avoid misleading anyone as to the status of such
46 * modified files, you must delete this exception notice from them.
48 * If you write modifications of your own for AutoOpts, it is your choice
49 * whether to permit this exception to apply to your modifications.
50 * If you do not wish that, delete this exception notice.
53 tOptions* pShellParseOptions = NULL;
55 /* * * * * * * * * * * * * * * * * * * * *
57 * Setup Format Strings
59 tSCC zStartMarker[] =
60 "# # # # # # # # # # -- do not modify this marker --\n#\n"
61 "# DO NOT EDIT THIS SECTION";
63 tSCC zPreamble[] =
64 "%s OF %s\n#\n"
65 "# From here to the next `-- do not modify this marker --',\n"
66 "# the text has been generated %s\n";
68 tSCC zEndPreamble[] =
69 "# From the %s option definitions\n#\n";
71 tSCC zMultiDef[] = "\n"
72 "if test -z \"${%1$s_%2$s}\"\n"
73 "then\n"
74 " %1$s_%2$s_CT=0\n"
75 "else\n"
76 " %1$s_%2$s_CT=1\n"
77 " %1$s_%2$s_1=\"${%1$s_%2$s}\"\n"
78 "fi\n"
79 "export %1$s_%2$s_CT";
81 tSCC zSingleDef[] = "\n"
82 "%1$s_%2$s=\"${%1$s_%2$s-'%3$s'}\"\n"
83 "%1$s_%2$s_set=false\n"
84 "export %1$s_%2$s\n";
86 tSCC zSingleNoDef[] = "\n"
87 "%1$s_%2$s=\"${%1$s_%2$s}\"\n"
88 "%1$s_%2$s_set=false\n"
89 "export %1$s_%2$s\n";
91 /* * * * * * * * * * * * * * * * * * * * *
93 * LOOP START
95 * The loop may run in either of two modes:
96 * all options are named options (loop only)
97 * regular, marked option processing.
99 tSCC zLoopCase[] = "\n"
100 "OPT_PROCESS=true\n"
101 "OPT_ARG=\"$1\"\n\n"
102 "while ${OPT_PROCESS} && [ $# -gt 0 ]\ndo\n"
103 " OPT_ELEMENT=''\n"
104 " OPT_ARG_VAL=''\n\n"
106 * 'OPT_ARG' may or may not match the current $1
108 " case \"${OPT_ARG}\" in\n"
109 " -- )\n"
110 " OPT_PROCESS=false\n"
111 " shift\n"
112 " ;;\n\n";
114 tSCC zLoopOnly[] = "\n"
115 "OPT_ARG=\"$1\"\n\n"
116 "while [ $# -gt 0 ]\ndo\n"
117 " OPT_ELEMENT=''\n"
118 " OPT_ARG_VAL=''\n\n"
119 " OPT_ARG=\"${1}\"\n";
121 /* * * * * * * * * * * * * * * *
123 * CASE SELECTORS
125 * If the loop runs as a regular option loop,
126 * then we must have selectors for each acceptable option
127 * type (long option, flag character and non-option)
129 tSCC zLongSelection[] =
130 " --* )\n";
132 tSCC zFlagSelection[] =
133 " -* )\n";
135 tSCC zEndSelection[] =
136 " ;;\n\n";
138 tSCC zNoSelection[] =
139 " * )\n"
140 " OPT_PROCESS=false\n"
141 " ;;\n"
142 " esac\n\n";
144 /* * * * * * * * * * * * * * * *
146 * LOOP END
148 tSCC zLoopEnd[] =
149 " if [ -n \"${OPT_ARG_VAL}\" ]\n"
150 " then\n"
151 " eval %1$s_${OPT_NAME}${OPT_ELEMENT}=\"'${OPT_ARG_VAL}'\"\n"
152 " export %1$s_${OPT_NAME}${OPT_ELEMENT}\n"
153 " fi\n"
154 "done\n\n"
155 "unset OPT_PROCESS || :\n"
156 "unset OPT_ELEMENT || :\n"
157 "unset OPT_ARG || :\n"
158 "unset OPT_ARG_NEEDED || :\n"
159 "unset OPT_NAME || :\n"
160 "unset OPT_CODE || :\n"
161 "unset OPT_ARG_VAL || :\n%2$s";
163 tSCC zTrailerMarker[] = "\n"
164 "# # # # # # # # # #\n#\n"
165 "# END OF AUTOMATED OPTION PROCESSING\n"
166 "#\n# # # # # # # # # # -- do not modify this marker --\n";
168 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
170 * OPTION SELECTION
172 tSCC zOptionCase[] =
173 " case \"${OPT_CODE}\" in\n";
175 tSCC zOptionPartName[] =
176 " '%s' | \\\n";
178 tSCC zOptionFullName[] =
179 " '%s' )\n";
181 tSCC zOptionFlag[] =
182 " '%c' )\n";
184 tSCC zOptionEndSelect[] =
185 " ;;\n\n";
187 tSCC zOptionUnknown[] =
188 " * )\n"
189 " echo Unknown %s: \"${OPT_CODE}\" >&2\n"
190 " echo \"$%s_USAGE_TEXT\"\n"
191 " exit 1\n"
192 " ;;\n"
193 " esac\n\n";
195 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
197 * OPTION PROCESSING
199 * Formats for emitting the text for handling particular options
201 tSCC zTextExit[] =
202 " echo \"$%s_%s_TEXT\"\n"
203 " exit 0\n";
205 tSCC zPagedUsageExit[] =
206 " echo \"$%s_LONGUSAGE_TEXT\" | ${PAGER-more}\n"
207 " exit 0\n";
209 tSCC zCmdFmt[] =
210 " %s\n";
212 tSCC zCountTest[] =
213 " if [ $%1$s_%2$s_CT -ge %3$d ] ; then\n"
214 " echo Error: more than %3$d %2$s options >&2\n"
215 " echo \"$%1$s_USAGE_TEXT\"\n"
216 " exit 1 ; fi\n";
218 tSCC zMultiArg[] =
219 " %1$s_%2$s_CT=`expr ${%1$s_%2$s_CT} + 1`\n"
220 " OPT_ELEMENT=\"_${%1$s_%2$s_CT}\"\n"
221 " OPT_NAME='%2$s'\n";
223 tSCC zSingleArg[] =
224 " if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
225 " echo Error: duplicate %2$s option >&2\n"
226 " echo \"$%1$s_USAGE_TEXT\"\n"
227 " exit 1 ; fi\n"
228 " %1$s_%2$s_set=true\n"
229 " OPT_NAME='%2$s'\n";
231 tSCC zNoMultiArg[] =
232 " %1$s_%2$s_CT=0\n"
233 " OPT_ELEMENT=''\n"
234 " %1$s_%2$s='%3$s'\n"
235 " export %1$s_%2$s\n"
236 " OPT_NAME='%2$s'\n";
238 tSCC zNoSingleArg[] =
239 " if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
240 " echo Error: duplicate %2$s option >&2\n"
241 " echo \"$%1$s_USAGE_TEXT\"\n"
242 " exit 1 ; fi\n"
243 " %1$s_%2$s_set=true\n"
244 " %1$s_%2$s='%3$s'\n"
245 " export %1$s_%2$s\n"
246 " OPT_NAME='%2$s'\n";
248 tSCC zMayArg[] =
249 " eval %1$s_%2$s${OPT_ELEMENT}=true\n"
250 " export %1$s_%2$s${OPT_ELEMENT}\n"
251 " OPT_ARG_NEEDED=OK\n";
253 tSCC zMustArg[] =
254 " OPT_ARG_NEEDED=YES\n";
256 tSCC zCantArg[] =
257 " eval %1$s_%2$s${OPT_ELEMENT}=true\n"
258 " export %1$s_%2$s${OPT_ELEMENT}\n"
259 " OPT_ARG_NEEDED=NO\n";
261 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
263 * LONG OPTION PROCESSING
265 * Formats for emitting the text for handling long option types
267 tSCC zLongOptInit[] =
268 " OPT_CODE=`echo \"X${OPT_ARG}\"|sed 's/^X-*//'`\n"
269 " shift\n"
270 " OPT_ARG=\"$1\"\n\n"
271 " case \"${OPT_CODE}\" in *=* )\n"
272 " OPT_ARG_VAL=`echo \"${OPT_CODE}\"|sed 's/^[^=]*=//'`\n"
273 " OPT_CODE=`echo \"${OPT_CODE}\"|sed 's/=.*$//'` ;; esac\n\n";
275 tSCC zLongOptArg[] =
276 " case \"${OPT_ARG_NEEDED}\" in\n"
277 " NO )\n"
278 " OPT_ARG_VAL=''\n"
279 " ;;\n\n"
280 " YES )\n"
281 " if [ -z \"${OPT_ARG_VAL}\" ]\n"
282 " then\n"
283 " if [ $# -eq 0 ]\n"
284 " then\n"
285 " echo No argument provided for ${OPT_NAME} option >&2\n"
286 " echo \"$%s_USAGE_TEXT\"\n"
287 " exit 1\n"
288 " fi\n\n"
289 " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
290 " shift\n"
291 " OPT_ARG=\"$1\"\n"
292 " fi\n"
293 " ;;\n\n"
294 " OK )\n"
295 " if [ -z \"${OPT_ARG_VAL}\" ] && [ $# -gt 0 ]\n"
296 " then\n"
297 " case \"${OPT_ARG}\" in -* ) ;; * )\n"
298 " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
299 " shift\n"
300 " OPT_ARG=\"$1\" ;; esac\n"
301 " fi\n"
302 " ;;\n"
303 " esac\n";
305 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
307 * FLAG OPTION PROCESSING
309 * Formats for emitting the text for handling flag option types
311 tSCC zFlagOptInit[] =
312 " OPT_CODE=`echo \"X${OPT_ARG}\" | sed 's/X-\\(.\\).*/\\1/'`\n"
313 " OPT_ARG=` echo \"X${OPT_ARG}\" | sed 's/X-.//'`\n\n";
315 tSCC zFlagOptArg[] =
316 " case \"${OPT_ARG_NEEDED}\" in\n"
317 " NO )\n"
318 " if [ -n \"${OPT_ARG}\" ]\n"
319 " then\n"
320 " OPT_ARG=-\"${OPT_ARG}\"\n"
321 " else\n"
322 " shift\n"
323 " OPT_ARG=\"$1\"\n"
324 " fi\n"
325 " ;;\n\n"
326 " YES )\n"
327 " if [ -n \"${OPT_ARG}\" ]\n"
328 " then\n"
329 " OPT_ARG_VAL=\"${OPT_ARG}\"\n\n"
330 " else\n"
331 " if [ $# -eq 0 ]\n"
332 " then\n"
333 " echo No argument provided for ${OPT_NAME} option >&2\n"
334 " echo \"$%s_USAGE_TEXT\"\n"
335 " exit 1\n"
336 " fi\n"
337 " shift\n"
338 " OPT_ARG_VAL=\"$1\"\n"
339 " fi\n\n"
340 " shift\n"
341 " OPT_ARG=\"$1\"\n"
342 " ;;\n\n"
343 " OK )\n"
344 " if [ -n \"${OPT_ARG}\" ]\n"
345 " then\n"
346 " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
347 " shift\n"
348 " OPT_ARG=\"$1\"\n\n"
349 " else\n"
350 " shift\n"
351 " if [ $# -gt 0 ]\n"
352 " then\n"
353 " case \"$1\" in -* ) ;; * )\n"
354 " OPT_ARG_VAL=\"$1\"\n"
355 " shift ;; esac\n"
356 " OPT_ARG=\"$1\"\n"
357 " fi\n"
358 " fi\n"
359 " ;;\n"
360 " esac\n";
362 tSCC* pzShell = NULL;
363 static char* pzLeader = NULL;
364 static char* pzTrailer = NULL;
366 /* = = = START-STATIC-FORWARD = = = */
367 /* static forward declarations maintained by :mkfwd */
368 static void
369 textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD );
371 static void
372 emitUsage( tOptions* pOpts );
374 static void
375 emitSetup( tOptions* pOpts );
377 static void
378 printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc );
380 static void
381 printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc );
383 static void
384 emitFlag( tOptions* pOpts );
386 static void
387 emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts );
389 static void
390 emitLong( tOptions* pOpts );
392 static void
393 openOutput( char const* pzFile );
394 /* = = = END-STATIC-FORWARD = = = */
396 /*=export_func optionParseShell
397 * private:
399 * what: Decipher a boolean value
400 * arg: + tOptions* + pOpts + program options descriptor +
402 * doc:
403 * Emit a shell script that will parse the command line options.
405 void
406 optionParseShell( tOptions* pOpts )
409 * Check for our SHELL option now.
410 * IF the output file contains the "#!" magic marker,
411 * it will override anything we do here.
413 if (HAVE_OPT( SHELL ))
414 pzShell = OPT_ARG( SHELL );
416 else if (! ENABLED_OPT( SHELL ))
417 pzShell = NULL;
419 else if ((pzShell = getenv( "SHELL" )),
420 pzShell == NULL)
422 pzShell = "/bin/sh";
425 * Check for a specified output file
427 if (HAVE_OPT( SCRIPT ))
428 openOutput( OPT_ARG( SCRIPT ));
430 emitUsage( pOpts );
431 emitSetup( pOpts );
434 * There are four modes of option processing.
436 switch (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
437 case OPTPROC_LONGOPT:
438 fputs( zLoopCase, stdout );
440 fputs( zLongSelection, stdout );
441 fputs( zLongOptInit, stdout );
442 emitLong( pOpts );
443 printf( zLongOptArg, pOpts->pzPROGNAME );
444 fputs( zEndSelection, stdout );
446 fputs( zNoSelection, stdout );
447 break;
449 case 0:
450 fputs( zLoopOnly, stdout );
451 fputs( zLongOptInit, stdout );
452 emitLong( pOpts );
453 printf( zLongOptArg, pOpts->pzPROGNAME );
454 break;
456 case OPTPROC_SHORTOPT:
457 fputs( zLoopCase, stdout );
459 fputs( zFlagSelection, stdout );
460 fputs( zFlagOptInit, stdout );
461 emitFlag( pOpts );
462 printf( zFlagOptArg, pOpts->pzPROGNAME );
463 fputs( zEndSelection, stdout );
465 fputs( zNoSelection, stdout );
466 break;
468 case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
469 fputs( zLoopCase, stdout );
471 fputs( zLongSelection, stdout );
472 fputs( zLongOptInit, stdout );
473 emitLong( pOpts );
474 printf( zLongOptArg, pOpts->pzPROGNAME );
475 fputs( zEndSelection, stdout );
477 fputs( zFlagSelection, stdout );
478 fputs( zFlagOptInit, stdout );
479 emitFlag( pOpts );
480 printf( zFlagOptArg, pOpts->pzPROGNAME );
481 fputs( zEndSelection, stdout );
483 fputs( zNoSelection, stdout );
484 break;
487 printf( zLoopEnd, pOpts->pzPROGNAME, zTrailerMarker );
488 if ((pzTrailer != NULL) && (*pzTrailer != '\0'))
489 fputs( pzTrailer, stdout );
490 else if (ENABLED_OPT( SHELL ))
491 printf( "\nenv | grep '^%s_'\n", pOpts->pzPROGNAME );
493 fflush( stdout );
494 fchmod( STDOUT_FILENO, 0755 );
495 fclose( stdout );
499 static void
500 textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD )
502 # define _TT_(n) tSCC z ## n [] = #n;
503 TEXTTO_TABLE
504 # undef _TT_
505 # define _TT_(n) z ## n ,
506 static char const* apzTTNames[] = { TEXTTO_TABLE };
507 # undef _TT_
509 #if defined(__windows__) && !defined(__CYGWIN__)
510 printf( "%1$s_%2$s_TEXT='no %2$s text'\n",
511 pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
512 #else
513 int nlHoldCt = 0;
514 int pipeFd[2];
515 FILE* fp;
517 printf( "%s_%s_TEXT='", pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
518 fflush( stdout );
520 if (pipe( pipeFd ) != 0) {
521 fprintf( stderr, zBadPipe, errno, strerror( errno ));
522 exit( EXIT_FAILURE );
525 switch (fork()) {
526 case -1:
527 fprintf( stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
528 exit( EXIT_FAILURE );
529 break;
531 case 0:
532 dup2( pipeFd[1], STDERR_FILENO );
533 dup2( pipeFd[1], STDOUT_FILENO );
534 close( pipeFd[0] );
536 switch (whichVar) {
537 case TT_LONGUSAGE:
538 (*(pOpts->pUsageProc))( pOpts, EXIT_SUCCESS );
539 /* NOTREACHED */
540 exit( EXIT_FAILURE );
542 case TT_USAGE:
543 (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
544 /* NOTREACHED */
545 exit( EXIT_FAILURE );
547 case TT_VERSION:
548 if (pOD->fOptState & OPTST_ALLOC_ARG) {
549 AGFREE(pOD->optArg.argString);
550 pOD->fOptState &= ~OPTST_ALLOC_ARG;
552 pOD->optArg.argString = "c";
553 optionPrintVersion( pOpts, pOD );
554 /* NOTREACHED */
556 default:
557 exit( EXIT_FAILURE );
560 default:
561 close( pipeFd[1] );
562 fp = fdopen( pipeFd[0], "r" FOPEN_BINARY_FLAG );
565 for (;;) {
566 int ch = fgetc( fp );
567 switch (ch) {
569 case '\n':
570 nlHoldCt++;
571 break;
573 case '\'':
574 while (nlHoldCt > 0) {
575 fputc( '\n', stdout );
576 nlHoldCt--;
578 fputs( "'\\''", stdout );
579 break;
581 case EOF:
582 goto endCharLoop;
584 default:
585 while (nlHoldCt > 0) {
586 fputc( '\n', stdout );
587 nlHoldCt--;
589 fputc( ch, stdout );
590 break;
592 } endCharLoop:;
594 fputs( "'\n\n", stdout );
595 close( pipeFd[0] );
596 #endif
600 static void
601 emitUsage( tOptions* pOpts )
603 char zTimeBuf[ AO_NAME_SIZE ];
606 * First, switch stdout to the output file name.
607 * Then, change the program name to the one defined
608 * by the definitions (rather than the current
609 * executable name). Down case the upper cased name.
611 if (pzLeader != NULL)
612 fputs( pzLeader, stdout );
615 tSCC zStdout[] = "stdout";
616 tCC* pzOutName;
619 time_t curTime = time( NULL );
620 struct tm* pTime = localtime( &curTime );
621 strftime(zTimeBuf, AO_NAME_SIZE, "%A %B %e, %Y at %r %Z", pTime );
624 if (HAVE_OPT( SCRIPT ))
625 pzOutName = OPT_ARG( SCRIPT );
626 else pzOutName = zStdout;
628 if ((pzLeader == NULL) && (pzShell != NULL))
629 printf( "#! %s\n", pzShell );
631 printf( zPreamble, zStartMarker, pzOutName, zTimeBuf );
635 * Get a copy of the original program name in lower case
638 char* pzPN = zTimeBuf;
639 tCC* pz = pOpts->pzPROGNAME;
640 for (;;) {
641 if ((*pzPN++ = tolower( *pz++ )) == '\0')
642 break;
646 printf( zEndPreamble, pOpts->pzPROGNAME );
648 pOpts->pzProgPath = pOpts->pzProgName = zTimeBuf;
649 textToVariable( pOpts, TT_LONGUSAGE, NULL );
650 textToVariable( pOpts, TT_USAGE, NULL );
653 tOptDesc* pOptDesc = pOpts->pOptDesc;
654 int optionCt = pOpts->optCt;
656 for (;;) {
657 if (pOptDesc->pOptProc == optionPrintVersion) {
658 textToVariable( pOpts, TT_VERSION, pOptDesc );
659 break;
662 if (--optionCt <= 0)
663 break;
664 pOptDesc++;
670 static void
671 emitSetup( tOptions* pOpts )
673 tOptDesc* pOptDesc = pOpts->pOptDesc;
674 int optionCt = pOpts->presetOptCt;
675 char const* pzFmt;
676 char const* pzDefault;
678 for (;optionCt > 0; pOptDesc++, --optionCt) {
679 char zVal[16];
682 * Options that are either usage documentation or are compiled out
683 * are not to be processed.
685 if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
686 continue;
688 if (pOptDesc->optMaxCt > 1)
689 pzFmt = zMultiDef;
690 else pzFmt = zSingleDef;
693 * IF this is an enumeration/bitmask option, then convert the value
694 * to a string before printing the default value.
696 switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) {
697 case OPARG_TYPE_ENUMERATION:
698 (*(pOptDesc->pOptProc))( (tOptions*)2UL, pOptDesc );
699 pzDefault = pOptDesc->optArg.argString;
700 break;
703 * Numeric and membership bit options are just printed as a number.
705 case OPARG_TYPE_NUMERIC:
706 snprintf( zVal, sizeof( zVal ), "%d",
707 (int)pOptDesc->optArg.argInt );
708 pzDefault = zVal;
709 break;
711 case OPARG_TYPE_MEMBERSHIP:
712 snprintf( zVal, sizeof( zVal ), "%lu",
713 (unsigned long)pOptDesc->optArg.argIntptr );
714 pzDefault = zVal;
715 break;
717 case OPARG_TYPE_BOOLEAN:
718 pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false";
719 break;
721 default:
722 if (pOptDesc->optArg.argString == NULL) {
723 if (pzFmt == zSingleDef)
724 pzFmt = zSingleNoDef;
725 pzDefault = NULL;
727 else
728 pzDefault = pOptDesc->optArg.argString;
731 printf( pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault );
736 static void
737 printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc )
739 if (pOptDesc->pOptProc == optionPrintVersion)
740 printf( zTextExit, pOpts->pzPROGNAME, "VERSION" );
742 else if (pOptDesc->pOptProc == optionPagedUsage)
743 printf( zPagedUsageExit, pOpts->pzPROGNAME );
745 else if (pOptDesc->pOptProc == optionLoadOpt) {
746 printf( zCmdFmt, "echo 'Warning: Cannot load options files' >&2" );
747 printf( zCmdFmt, "OPT_ARG_NEEDED=YES" );
749 } else if (pOptDesc->pz_NAME == NULL) {
751 if (pOptDesc->pOptProc == NULL) {
752 printf( zCmdFmt, "echo 'Warning: Cannot save options files' "
753 ">&2" );
754 printf( zCmdFmt, "OPT_ARG_NEEDED=OK" );
755 } else
756 printf( zTextExit, pOpts->pzPROGNAME, "LONGUSAGE" );
758 } else {
759 if (pOptDesc->optMaxCt == 1)
760 printf( zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
761 else {
762 if ((unsigned)pOptDesc->optMaxCt < NOLIMIT)
763 printf( zCountTest, pOpts->pzPROGNAME,
764 pOptDesc->pz_NAME, pOptDesc->optMaxCt );
766 printf( zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
770 * Fix up the args.
772 if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
773 printf( zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
775 } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
776 printf( zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
778 } else {
779 fputs( zMustArg, stdout );
782 fputs( zOptionEndSelect, stdout );
786 static void
787 printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc )
789 if (pOptDesc->pOptProc == optionLoadOpt) {
790 printf( zCmdFmt, "echo 'Warning: Cannot suppress the loading of "
791 "options files' >&2" );
793 } else if (pOptDesc->optMaxCt == 1)
794 printf( zNoSingleArg, pOpts->pzPROGNAME,
795 pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
796 else
797 printf( zNoMultiArg, pOpts->pzPROGNAME,
798 pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
800 printf( zCmdFmt, "OPT_ARG_NEEDED=NO" );
801 fputs( zOptionEndSelect, stdout );
805 static void
806 emitFlag( tOptions* pOpts )
808 tOptDesc* pOptDesc = pOpts->pOptDesc;
809 int optionCt = pOpts->optCt;
811 fputs( zOptionCase, stdout );
813 for (;optionCt > 0; pOptDesc++, --optionCt) {
815 if (SKIP_OPT(pOptDesc))
816 continue;
818 if (isprint( pOptDesc->optValue )) {
819 printf( zOptionFlag, pOptDesc->optValue );
820 printOptionAction( pOpts, pOptDesc );
823 printf( zOptionUnknown, "flag", pOpts->pzPROGNAME );
828 * Emit the match text for a long option
830 static void
831 emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts )
833 tOptDesc* pOD = pOpts->pOptDesc;
834 int oCt = pOpts->optCt;
835 int min = 1;
836 char zName[ 256 ];
837 char* pz = zName;
839 for (;;) {
840 int matchCt = 0;
843 * Omit the current option, Documentation opts and compiled out opts.
845 if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
846 if (--oCt <= 0)
847 break;
848 pOD++;
849 continue;
853 * Check each character of the name case insensitively.
854 * They must not be the same. They cannot be, because it would
855 * not compile correctly if they were.
857 while ( toupper( pOD->pz_Name[matchCt] )
858 == toupper( pzMatchName[matchCt] ))
859 matchCt++;
861 if (matchCt > min)
862 min = matchCt;
865 * Check the disablement name, too.
867 if (pOD->pz_DisableName != NULL) {
868 matchCt = 0;
869 while ( toupper( pOD->pz_DisableName[matchCt] )
870 == toupper( pzMatchName[matchCt] ))
871 matchCt++;
872 if (matchCt > min)
873 min = matchCt;
875 if (--oCt <= 0)
876 break;
877 pOD++;
881 * IF the 'min' is all or one short of the name length,
882 * THEN the entire string must be matched.
884 if ( (pzMatchName[min ] == NUL)
885 || (pzMatchName[min+1] == NUL) )
886 printf( zOptionFullName, pzMatchName );
888 else {
889 int matchCt = 0;
890 for (; matchCt <= min; matchCt++)
891 *pz++ = pzMatchName[matchCt];
893 for (;;) {
894 *pz = NUL;
895 printf( zOptionPartName, zName );
896 *pz++ = pzMatchName[matchCt++];
897 if (pzMatchName[matchCt] == NUL) {
898 *pz = NUL;
899 printf( zOptionFullName, zName );
900 break;
908 * Emit GNU-standard long option handling code
910 static void
911 emitLong( tOptions* pOpts )
913 tOptDesc* pOD = pOpts->pOptDesc;
914 int ct = pOpts->optCt;
916 fputs( zOptionCase, stdout );
919 * do each option, ...
921 do {
923 * Documentation & compiled-out options
925 if (SKIP_OPT(pOD))
926 continue;
928 emitMatchExpr( pOD->pz_Name, pOD, pOpts );
929 printOptionAction( pOpts, pOD );
932 * Now, do the same thing for the disablement version of the option.
934 if (pOD->pz_DisableName != NULL) {
935 emitMatchExpr( pOD->pz_DisableName, pOD, pOpts );
936 printOptionInaction( pOpts, pOD );
938 } while (pOD++, --ct > 0);
940 printf( zOptionUnknown, "option", pOpts->pzPROGNAME );
944 static void
945 openOutput( char const* pzFile )
947 FILE* fp;
948 char* pzData = NULL;
949 struct stat stbf;
951 do {
952 char* pzScan;
953 size_t sizeLeft;
956 * IF we cannot stat the file,
957 * THEN assume we are creating a new file.
958 * Skip the loading of the old data.
960 if (stat( pzFile, &stbf ) != 0)
961 break;
964 * The file must be a regular file
966 if (! S_ISREG( stbf.st_mode )) {
967 fprintf( stderr, zNotFile, pzFile );
968 exit( EXIT_FAILURE );
971 pzData = AGALOC(stbf.st_size + 1, "file data");
972 fp = fopen( pzFile, "r" FOPEN_BINARY_FLAG );
974 sizeLeft = (unsigned)stbf.st_size;
975 pzScan = pzData;
978 * Read in all the data as fast as our OS will let us.
980 for (;;) {
981 int inct = fread( (void*)pzScan, (size_t)1, sizeLeft, fp);
982 if (inct == 0)
983 break;
985 pzScan += inct;
986 sizeLeft -= inct;
988 if (sizeLeft == 0)
989 break;
993 * NUL-terminate the leader and look for the trailer
995 *pzScan = '\0';
996 fclose( fp );
997 pzScan = strstr( pzData, zStartMarker );
998 if (pzScan == NULL) {
999 pzTrailer = pzData;
1000 break;
1003 *(pzScan++) = NUL;
1004 pzScan = strstr( pzScan, zTrailerMarker );
1005 if (pzScan == NULL) {
1006 pzTrailer = pzData;
1007 break;
1011 * Check to see if the data contains
1012 * our marker. If it does, then we will skip over it
1014 pzTrailer = pzScan + sizeof( zTrailerMarker ) - 1;
1015 pzLeader = pzData;
1016 } while (AG_FALSE);
1018 freopen( pzFile, "w" FOPEN_BINARY_FLAG, stdout );
1022 /*=export_func genshelloptUsage
1023 * private:
1024 * what: The usage function for the genshellopt generated program
1026 * arg: + tOptions* + pOpts + program options descriptor +
1027 * arg: + int + exitCode + usage text type to produce +
1029 * doc:
1030 * This function is used to create the usage strings for the option
1031 * processing shell script code. Two child processes are spawned
1032 * each emitting the usage text in either the short (error exit)
1033 * style or the long style. The generated program will capture this
1034 * and create shell script variables containing the two types of text.
1036 void
1037 genshelloptUsage( tOptions* pOpts, int exitCode )
1039 #if defined(__windows__) && !defined(__CYGWIN__)
1040 optionUsage( pOpts, exitCode );
1041 #else
1043 * IF not EXIT_SUCCESS,
1044 * THEN emit the short form of usage.
1046 if (exitCode != EXIT_SUCCESS)
1047 optionUsage( pOpts, exitCode );
1048 fflush( stderr );
1049 fflush( stdout );
1051 option_usage_fp = stdout;
1054 * First, print our usage
1056 switch (fork()) {
1057 case -1:
1058 optionUsage( pOpts, EXIT_FAILURE );
1059 /*NOTREACHED*/
1060 _exit( EXIT_FAILURE );
1062 case 0:
1063 pagerState = PAGER_STATE_CHILD;
1064 optionUsage( pOpts, EXIT_SUCCESS );
1065 /*NOTREACHED*/
1066 _exit( EXIT_FAILURE );
1068 default:
1070 int sts;
1071 wait( &sts );
1076 * Generate the pzProgName, since optionProcess() normally
1077 * gets it from the command line
1080 char* pz;
1081 AGDUPSTR( pz, pShellParseOptions->pzPROGNAME, "program name" );
1082 pShellParseOptions->pzProgName = pz;
1083 while (*pz != NUL) {
1084 *pz = tolower( *pz );
1085 pz++;
1090 * Separate the makeshell usage from the client usage
1092 fprintf( option_usage_fp, zGenshell, pShellParseOptions->pzProgName );
1093 fflush( option_usage_fp );
1096 * Now, print the client usage.
1098 switch (fork()) {
1099 case 0:
1100 pagerState = PAGER_STATE_CHILD;
1101 /*FALLTHROUGH*/
1102 case -1:
1103 optionUsage( pShellParseOptions, EXIT_FAILURE );
1105 default:
1107 int sts;
1108 wait( &sts );
1112 exit( EXIT_SUCCESS );
1113 #endif
1117 * Local Variables:
1118 * mode: C
1119 * c-file-style: "stroustrup"
1120 * indent-tabs-mode: nil
1121 * End:
1122 * end of autoopts/makeshell.c */