Sync usage with man page.
[netbsd-mini2440.git] / dist / ntp / libopts / makeshell.c
blob52533c814090b867d43d3e5226eac45135567f09
1 /* $NetBSD: makeshell.c,v 1.1.1.2 2007/06/24 15:49:25 kardel Exp $ */
4 /*
5 * Id: makeshell.c,v 4.20 2007/02/04 17:44:12 bkorb Exp
6 * Time-stamp: "2007-01-27 06:05:45 bkorb"
8 * This module will interpret the options set in the tOptions
9 * structure and create a Bourne shell script capable of parsing them.
13 * Automated Options copyright 1992-2007 Bruce Korb
15 * Automated Options is free software.
16 * You may redistribute it and/or modify it under the terms of the
17 * GNU General Public License, as published by the Free Software
18 * Foundation; either version 2, or (at your option) any later version.
20 * Automated Options is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with Automated Options. See the file "COPYING". If not,
27 * write to: The Free Software Foundation, Inc.,
28 * 51 Franklin Street, Fifth Floor,
29 * Boston, MA 02110-1301, USA.
31 * As a special exception, Bruce Korb gives permission for additional
32 * uses of the text contained in his release of AutoOpts.
34 * The exception is that, if you link the AutoOpts library with other
35 * files to produce an executable, this does not by itself cause the
36 * resulting executable to be covered by the GNU General Public License.
37 * Your use of that executable is in no way restricted on account of
38 * linking the AutoOpts library code into it.
40 * This exception does not however invalidate any other reasons why
41 * the executable file might be covered by the GNU General Public License.
43 * This exception applies only to the code released by Bruce Korb under
44 * the name AutoOpts. If you copy code from other sources under the
45 * General Public License into a copy of AutoOpts, as the General Public
46 * License permits, the exception does not apply to the code that you add
47 * in this way. To avoid misleading anyone as to the status of such
48 * modified files, you must delete this exception notice from them.
50 * If you write modifications of your own for AutoOpts, it is your choice
51 * whether to permit this exception to apply to your modifications.
52 * If you do not wish that, delete this exception notice.
55 tOptions* pShellParseOptions = NULL;
57 /* * * * * * * * * * * * * * * * * * * * *
59 * Setup Format Strings
61 tSCC zStartMarker[] =
62 "# # # # # # # # # # -- do not modify this marker --\n#\n"
63 "# DO NOT EDIT THIS SECTION";
65 tSCC zPreamble[] =
66 "%s OF %s\n#\n"
67 "# From here to the next `-- do not modify this marker --',\n"
68 "# the text has been generated %s\n";
70 tSCC zEndPreamble[] =
71 "# From the %s option definitions\n#\n";
73 tSCC zMultiDef[] = "\n"
74 "if test -z \"${%1$s_%2$s}\"\n"
75 "then\n"
76 " %1$s_%2$s_CT=0\n"
77 "else\n"
78 " %1$s_%2$s_CT=1\n"
79 " %1$s_%2$s_1=\"${%1$s_%2$s}\"\n"
80 "fi\n"
81 "export %1$s_%2$s_CT";
83 tSCC zSingleDef[] = "\n"
84 "%1$s_%2$s=\"${%1$s_%2$s-'%3$s'}\"\n"
85 "%1$s_%2$s_set=false\n"
86 "export %1$s_%2$s\n";
88 tSCC zSingleNoDef[] = "\n"
89 "%1$s_%2$s=\"${%1$s_%2$s}\"\n"
90 "%1$s_%2$s_set=false\n"
91 "export %1$s_%2$s\n";
93 /* * * * * * * * * * * * * * * * * * * * *
95 * LOOP START
97 * The loop may run in either of two modes:
98 * all options are named options (loop only)
99 * regular, marked option processing.
101 tSCC zLoopCase[] = "\n"
102 "OPT_PROCESS=true\n"
103 "OPT_ARG=\"$1\"\n\n"
104 "while ${OPT_PROCESS} && [ $# -gt 0 ]\ndo\n"
105 " OPT_ELEMENT=''\n"
106 " OPT_ARG_VAL=''\n\n"
108 * 'OPT_ARG' may or may not match the current $1
110 " case \"${OPT_ARG}\" in\n"
111 " -- )\n"
112 " OPT_PROCESS=false\n"
113 " shift\n"
114 " ;;\n\n";
116 tSCC zLoopOnly[] = "\n"
117 "OPT_ARG=\"$1\"\n\n"
118 "while [ $# -gt 0 ]\ndo\n"
119 " OPT_ELEMENT=''\n"
120 " OPT_ARG_VAL=''\n\n"
121 " OPT_ARG=\"${1}\"\n";
123 /* * * * * * * * * * * * * * * *
125 * CASE SELECTORS
127 * If the loop runs as a regular option loop,
128 * then we must have selectors for each acceptable option
129 * type (long option, flag character and non-option)
131 tSCC zLongSelection[] =
132 " --* )\n";
134 tSCC zFlagSelection[] =
135 " -* )\n";
137 tSCC zEndSelection[] =
138 " ;;\n\n";
140 tSCC zNoSelection[] =
141 " * )\n"
142 " OPT_PROCESS=false\n"
143 " ;;\n"
144 " esac\n\n";
146 /* * * * * * * * * * * * * * * *
148 * LOOP END
150 tSCC zLoopEnd[] =
151 " if [ -n \"${OPT_ARG_VAL}\" ]\n"
152 " then\n"
153 " eval %1$s_${OPT_NAME}${OPT_ELEMENT}=\"'${OPT_ARG_VAL}'\"\n"
154 " export %1$s_${OPT_NAME}${OPT_ELEMENT}\n"
155 " fi\n"
156 "done\n\n"
157 "unset OPT_PROCESS || :\n"
158 "unset OPT_ELEMENT || :\n"
159 "unset OPT_ARG || :\n"
160 "unset OPT_ARG_NEEDED || :\n"
161 "unset OPT_NAME || :\n"
162 "unset OPT_CODE || :\n"
163 "unset OPT_ARG_VAL || :\n%2$s";
165 tSCC zTrailerMarker[] = "\n"
166 "# # # # # # # # # #\n#\n"
167 "# END OF AUTOMATED OPTION PROCESSING\n"
168 "#\n# # # # # # # # # # -- do not modify this marker --\n";
170 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
172 * OPTION SELECTION
174 tSCC zOptionCase[] =
175 " case \"${OPT_CODE}\" in\n";
177 tSCC zOptionPartName[] =
178 " '%s' | \\\n";
180 tSCC zOptionFullName[] =
181 " '%s' )\n";
183 tSCC zOptionFlag[] =
184 " '%c' )\n";
186 tSCC zOptionEndSelect[] =
187 " ;;\n\n";
189 tSCC zOptionUnknown[] =
190 " * )\n"
191 " echo Unknown %s: \"${OPT_CODE}\" >&2\n"
192 " echo \"$%s_USAGE_TEXT\"\n"
193 " exit 1\n"
194 " ;;\n"
195 " esac\n\n";
197 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
199 * OPTION PROCESSING
201 * Formats for emitting the text for handling particular options
203 tSCC zTextExit[] =
204 " echo \"$%s_%s_TEXT\"\n"
205 " exit 0\n";
207 tSCC zPagedUsageExit[] =
208 " echo \"$%s_LONGUSAGE_TEXT\" | ${PAGER-more}\n"
209 " exit 0\n";
211 tSCC zCmdFmt[] =
212 " %s\n";
214 tSCC zCountTest[] =
215 " if [ $%1$s_%2$s_CT -ge %3$d ] ; then\n"
216 " echo Error: more than %3$d %2$s options >&2\n"
217 " echo \"$%1$s_USAGE_TEXT\"\n"
218 " exit 1 ; fi\n";
220 tSCC zMultiArg[] =
221 " %1$s_%2$s_CT=`expr ${%1$s_%2$s_CT} + 1`\n"
222 " OPT_ELEMENT=\"_${%1$s_%2$s_CT}\"\n"
223 " OPT_NAME='%2$s'\n";
225 tSCC zSingleArg[] =
226 " if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
227 " echo Error: duplicate %2$s option >&2\n"
228 " echo \"$%1$s_USAGE_TEXT\"\n"
229 " exit 1 ; fi\n"
230 " %1$s_%2$s_set=true\n"
231 " OPT_NAME='%2$s'\n";
233 tSCC zNoMultiArg[] =
234 " %1$s_%2$s_CT=0\n"
235 " OPT_ELEMENT=''\n"
236 " %1$s_%2$s='%3$s'\n"
237 " export %1$s_%2$s\n"
238 " OPT_NAME='%2$s'\n";
240 tSCC zNoSingleArg[] =
241 " if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
242 " echo Error: duplicate %2$s option >&2\n"
243 " echo \"$%1$s_USAGE_TEXT\"\n"
244 " exit 1 ; fi\n"
245 " %1$s_%2$s_set=true\n"
246 " %1$s_%2$s='%3$s'\n"
247 " export %1$s_%2$s\n"
248 " OPT_NAME='%2$s'\n";
250 tSCC zMayArg[] =
251 " eval %1$s_%2$s${OPT_ELEMENT}=true\n"
252 " export %1$s_%2$s${OPT_ELEMENT}\n"
253 " OPT_ARG_NEEDED=OK\n";
255 tSCC zMustArg[] =
256 " OPT_ARG_NEEDED=YES\n";
258 tSCC zCantArg[] =
259 " eval %1$s_%2$s${OPT_ELEMENT}=true\n"
260 " export %1$s_%2$s${OPT_ELEMENT}\n"
261 " OPT_ARG_NEEDED=NO\n";
263 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
265 * LONG OPTION PROCESSING
267 * Formats for emitting the text for handling long option types
269 tSCC zLongOptInit[] =
270 " OPT_CODE=`echo \"X${OPT_ARG}\"|sed 's/^X-*//'`\n"
271 " shift\n"
272 " OPT_ARG=\"$1\"\n\n"
273 " case \"${OPT_CODE}\" in *=* )\n"
274 " OPT_ARG_VAL=`echo \"${OPT_CODE}\"|sed 's/^[^=]*=//'`\n"
275 " OPT_CODE=`echo \"${OPT_CODE}\"|sed 's/=.*$//'` ;; esac\n\n";
277 tSCC zLongOptArg[] =
278 " case \"${OPT_ARG_NEEDED}\" in\n"
279 " NO )\n"
280 " OPT_ARG_VAL=''\n"
281 " ;;\n\n"
282 " YES )\n"
283 " if [ -z \"${OPT_ARG_VAL}\" ]\n"
284 " then\n"
285 " if [ $# -eq 0 ]\n"
286 " then\n"
287 " echo No argument provided for ${OPT_NAME} option >&2\n"
288 " echo \"$%s_USAGE_TEXT\"\n"
289 " exit 1\n"
290 " fi\n\n"
291 " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
292 " shift\n"
293 " OPT_ARG=\"$1\"\n"
294 " fi\n"
295 " ;;\n\n"
296 " OK )\n"
297 " if [ -z \"${OPT_ARG_VAL}\" ] && [ $# -gt 0 ]\n"
298 " then\n"
299 " case \"${OPT_ARG}\" in -* ) ;; * )\n"
300 " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
301 " shift\n"
302 " OPT_ARG=\"$1\" ;; esac\n"
303 " fi\n"
304 " ;;\n"
305 " esac\n";
307 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
309 * FLAG OPTION PROCESSING
311 * Formats for emitting the text for handling flag option types
313 tSCC zFlagOptInit[] =
314 " OPT_CODE=`echo \"X${OPT_ARG}\" | sed 's/X-\\(.\\).*/\\1/'`\n"
315 " OPT_ARG=` echo \"X${OPT_ARG}\" | sed 's/X-.//'`\n\n";
317 tSCC zFlagOptArg[] =
318 " case \"${OPT_ARG_NEEDED}\" in\n"
319 " NO )\n"
320 " if [ -n \"${OPT_ARG}\" ]\n"
321 " then\n"
322 " OPT_ARG=-\"${OPT_ARG}\"\n"
323 " else\n"
324 " shift\n"
325 " OPT_ARG=\"$1\"\n"
326 " fi\n"
327 " ;;\n\n"
328 " YES )\n"
329 " if [ -n \"${OPT_ARG}\" ]\n"
330 " then\n"
331 " OPT_ARG_VAL=\"${OPT_ARG}\"\n\n"
332 " else\n"
333 " if [ $# -eq 0 ]\n"
334 " then\n"
335 " echo No argument provided for ${OPT_NAME} option >&2\n"
336 " echo \"$%s_USAGE_TEXT\"\n"
337 " exit 1\n"
338 " fi\n"
339 " shift\n"
340 " OPT_ARG_VAL=\"$1\"\n"
341 " fi\n\n"
342 " shift\n"
343 " OPT_ARG=\"$1\"\n"
344 " ;;\n\n"
345 " OK )\n"
346 " if [ -n \"${OPT_ARG}\" ]\n"
347 " then\n"
348 " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
349 " shift\n"
350 " OPT_ARG=\"$1\"\n\n"
351 " else\n"
352 " shift\n"
353 " if [ $# -gt 0 ]\n"
354 " then\n"
355 " case \"$1\" in -* ) ;; * )\n"
356 " OPT_ARG_VAL=\"$1\"\n"
357 " shift ;; esac\n"
358 " OPT_ARG=\"$1\"\n"
359 " fi\n"
360 " fi\n"
361 " ;;\n"
362 " esac\n";
364 tSCC* pzShell = NULL;
365 static char* pzLeader = NULL;
366 static char* pzTrailer = NULL;
368 /* = = = START-STATIC-FORWARD = = = */
369 /* static forward declarations maintained by :mkfwd */
370 static void
371 textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD );
373 static void
374 emitUsage( tOptions* pOpts );
376 static void
377 emitSetup( tOptions* pOpts );
379 static void
380 printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc );
382 static void
383 printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc );
385 static void
386 emitFlag( tOptions* pOpts );
388 static void
389 emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts );
391 static void
392 emitLong( tOptions* pOpts );
394 static void
395 openOutput( char const* pzFile );
396 /* = = = END-STATIC-FORWARD = = = */
398 /*=export_func optionParseShell
399 * private:
401 * what: Decipher a boolean value
402 * arg: + tOptions* + pOpts + program options descriptor +
404 * doc:
405 * Emit a shell script that will parse the command line options.
407 void
408 optionParseShell( tOptions* pOpts )
411 * Check for our SHELL option now.
412 * IF the output file contains the "#!" magic marker,
413 * it will override anything we do here.
415 if (HAVE_OPT( SHELL ))
416 pzShell = OPT_ARG( SHELL );
418 else if (! ENABLED_OPT( SHELL ))
419 pzShell = NULL;
421 else if ((pzShell = getenv( "SHELL" )),
422 pzShell == NULL)
424 pzShell = "/bin/sh";
427 * Check for a specified output file
429 if (HAVE_OPT( SCRIPT ))
430 openOutput( OPT_ARG( SCRIPT ));
432 emitUsage( pOpts );
433 emitSetup( pOpts );
436 * There are four modes of option processing.
438 switch (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
439 case OPTPROC_LONGOPT:
440 fputs( zLoopCase, stdout );
442 fputs( zLongSelection, stdout );
443 fputs( zLongOptInit, stdout );
444 emitLong( pOpts );
445 printf( zLongOptArg, pOpts->pzPROGNAME );
446 fputs( zEndSelection, stdout );
448 fputs( zNoSelection, stdout );
449 break;
451 case 0:
452 fputs( zLoopOnly, stdout );
453 fputs( zLongOptInit, stdout );
454 emitLong( pOpts );
455 printf( zLongOptArg, pOpts->pzPROGNAME );
456 break;
458 case OPTPROC_SHORTOPT:
459 fputs( zLoopCase, stdout );
461 fputs( zFlagSelection, stdout );
462 fputs( zFlagOptInit, stdout );
463 emitFlag( pOpts );
464 printf( zFlagOptArg, pOpts->pzPROGNAME );
465 fputs( zEndSelection, stdout );
467 fputs( zNoSelection, stdout );
468 break;
470 case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
471 fputs( zLoopCase, stdout );
473 fputs( zLongSelection, stdout );
474 fputs( zLongOptInit, stdout );
475 emitLong( pOpts );
476 printf( zLongOptArg, pOpts->pzPROGNAME );
477 fputs( zEndSelection, stdout );
479 fputs( zFlagSelection, stdout );
480 fputs( zFlagOptInit, stdout );
481 emitFlag( pOpts );
482 printf( zFlagOptArg, pOpts->pzPROGNAME );
483 fputs( zEndSelection, stdout );
485 fputs( zNoSelection, stdout );
486 break;
489 printf( zLoopEnd, pOpts->pzPROGNAME, zTrailerMarker );
490 if ((pzTrailer != NULL) && (*pzTrailer != '\0'))
491 fputs( pzTrailer, stdout );
492 else if (ENABLED_OPT( SHELL ))
493 printf( "\nenv | grep '^%s_'\n", pOpts->pzPROGNAME );
495 fflush( stdout );
496 fchmod( STDOUT_FILENO, 0755 );
497 fclose( stdout );
501 static void
502 textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD )
504 # define _TT_(n) tSCC z ## n [] = #n;
505 TEXTTO_TABLE
506 # undef _TT_
507 # define _TT_(n) z ## n ,
508 static char const* apzTTNames[] = { TEXTTO_TABLE };
509 # undef _TT_
511 #if defined(__windows__) && !defined(__CYGWIN__)
512 printf( "%1$s_%2$s_TEXT='no %2$s text'\n",
513 pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
514 #else
515 int nlHoldCt = 0;
516 int pipeFd[2];
517 FILE* fp;
519 printf( "%s_%s_TEXT='", pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
520 fflush( stdout );
522 if (pipe( pipeFd ) != 0) {
523 fprintf( stderr, zBadPipe, errno, strerror( errno ));
524 exit( EXIT_FAILURE );
527 switch (fork()) {
528 case -1:
529 fprintf( stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
530 exit( EXIT_FAILURE );
531 break;
533 case 0:
534 dup2( pipeFd[1], STDERR_FILENO );
535 dup2( pipeFd[1], STDOUT_FILENO );
536 close( pipeFd[0] );
538 switch (whichVar) {
539 case TT_LONGUSAGE:
540 (*(pOpts->pUsageProc))( pOpts, EXIT_SUCCESS );
541 /* NOTREACHED */
542 exit( EXIT_FAILURE );
544 case TT_USAGE:
545 (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
546 /* NOTREACHED */
547 exit( EXIT_FAILURE );
549 case TT_VERSION:
550 if (pOD->fOptState & OPTST_ALLOC_ARG) {
551 AGFREE(pOD->optArg.argString);
552 pOD->fOptState &= ~OPTST_ALLOC_ARG;
554 pOD->optArg.argString = "c";
555 optionPrintVersion( pOpts, pOD );
556 /* NOTREACHED */
558 default:
559 exit( EXIT_FAILURE );
562 default:
563 close( pipeFd[1] );
564 fp = fdopen( pipeFd[0], "r" FOPEN_BINARY_FLAG );
567 for (;;) {
568 int ch = fgetc( fp );
569 switch (ch) {
571 case '\n':
572 nlHoldCt++;
573 break;
575 case '\'':
576 while (nlHoldCt > 0) {
577 fputc( '\n', stdout );
578 nlHoldCt--;
580 fputs( "'\\''", stdout );
581 break;
583 case EOF:
584 goto endCharLoop;
586 default:
587 while (nlHoldCt > 0) {
588 fputc( '\n', stdout );
589 nlHoldCt--;
591 fputc( ch, stdout );
592 break;
594 } endCharLoop:;
596 fputs( "'\n\n", stdout );
597 close( pipeFd[0] );
598 #endif
602 static void
603 emitUsage( tOptions* pOpts )
605 char zTimeBuf[ AO_NAME_SIZE ];
608 * First, switch stdout to the output file name.
609 * Then, change the program name to the one defined
610 * by the definitions (rather than the current
611 * executable name). Down case the upper cased name.
613 if (pzLeader != NULL)
614 fputs( pzLeader, stdout );
617 tSCC zStdout[] = "stdout";
618 tCC* pzOutName;
621 time_t curTime = time( NULL );
622 struct tm* pTime = localtime( &curTime );
623 strftime(zTimeBuf, AO_NAME_SIZE, "%A %B %e, %Y at %r %Z", pTime );
626 if (HAVE_OPT( SCRIPT ))
627 pzOutName = OPT_ARG( SCRIPT );
628 else pzOutName = zStdout;
630 if ((pzLeader == NULL) && (pzShell != NULL))
631 printf( "#! %s\n", pzShell );
633 printf( zPreamble, zStartMarker, pzOutName, zTimeBuf );
637 * Get a copy of the original program name in lower case
640 char* pzPN = zTimeBuf;
641 tCC* pz = pOpts->pzPROGNAME;
642 for (;;) {
643 if ((*pzPN++ = tolower( (int)*pz++ )) == '\0')
644 break;
648 printf( zEndPreamble, pOpts->pzPROGNAME );
650 pOpts->pzProgPath = pOpts->pzProgName = zTimeBuf;
651 textToVariable( pOpts, TT_LONGUSAGE, NULL );
652 textToVariable( pOpts, TT_USAGE, NULL );
655 tOptDesc* pOptDesc = pOpts->pOptDesc;
656 int optionCt = pOpts->optCt;
658 for (;;) {
659 if (pOptDesc->pOptProc == optionPrintVersion) {
660 textToVariable( pOpts, TT_VERSION, pOptDesc );
661 break;
664 if (--optionCt <= 0)
665 break;
666 pOptDesc++;
672 static void
673 emitSetup( tOptions* pOpts )
675 tOptDesc* pOptDesc = pOpts->pOptDesc;
676 int optionCt = pOpts->presetOptCt;
677 char const* pzFmt;
678 char const* pzDefault;
680 for (;optionCt > 0; pOptDesc++, --optionCt) {
681 char zVal[16];
684 * Options that are either usage documentation or are compiled out
685 * are not to be processed.
687 if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
688 continue;
690 if (pOptDesc->optMaxCt > 1)
691 pzFmt = zMultiDef;
692 else pzFmt = zSingleDef;
695 * IF this is an enumeration/bitmask option, then convert the value
696 * to a string before printing the default value.
698 switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) {
699 case OPARG_TYPE_ENUMERATION:
700 (*(pOptDesc->pOptProc))( (tOptions*)2UL, pOptDesc );
701 pzDefault = pOptDesc->optArg.argString;
702 break;
705 * Numeric and membership bit options are just printed as a number.
707 case OPARG_TYPE_NUMERIC:
708 snprintf( zVal, sizeof( zVal ), "%d",
709 (int)pOptDesc->optArg.argInt );
710 pzDefault = zVal;
711 break;
713 case OPARG_TYPE_MEMBERSHIP:
714 snprintf( zVal, sizeof( zVal ), "%lu",
715 (unsigned long)pOptDesc->optArg.argIntptr );
716 pzDefault = zVal;
717 break;
719 case OPARG_TYPE_BOOLEAN:
720 pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false";
721 break;
723 default:
724 if (pOptDesc->optArg.argString == NULL) {
725 if (pzFmt == zSingleDef)
726 pzFmt = zSingleNoDef;
727 pzDefault = NULL;
729 else
730 pzDefault = pOptDesc->optArg.argString;
733 printf( pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault );
738 static void
739 printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc )
741 if (pOptDesc->pOptProc == optionPrintVersion)
742 printf( zTextExit, pOpts->pzPROGNAME, "VERSION" );
744 else if (pOptDesc->pOptProc == optionPagedUsage)
745 printf( zPagedUsageExit, pOpts->pzPROGNAME );
747 else if (pOptDesc->pOptProc == optionLoadOpt) {
748 printf( zCmdFmt, "echo 'Warning: Cannot load options files' >&2" );
749 printf( zCmdFmt, "OPT_ARG_NEEDED=YES" );
751 } else if (pOptDesc->pz_NAME == NULL) {
753 if (pOptDesc->pOptProc == NULL) {
754 printf( zCmdFmt, "echo 'Warning: Cannot save options files' "
755 ">&2" );
756 printf( zCmdFmt, "OPT_ARG_NEEDED=OK" );
757 } else
758 printf( zTextExit, pOpts->pzPROGNAME, "LONGUSAGE" );
760 } else {
761 if (pOptDesc->optMaxCt == 1)
762 printf( zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
763 else {
764 if ((unsigned)pOptDesc->optMaxCt < NOLIMIT)
765 printf( zCountTest, pOpts->pzPROGNAME,
766 pOptDesc->pz_NAME, pOptDesc->optMaxCt );
768 printf( zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
772 * Fix up the args.
774 if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
775 printf( zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
777 } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
778 printf( zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
780 } else {
781 fputs( zMustArg, stdout );
784 fputs( zOptionEndSelect, stdout );
788 static void
789 printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc )
791 if (pOptDesc->pOptProc == optionLoadOpt) {
792 printf( zCmdFmt, "echo 'Warning: Cannot suppress the loading of "
793 "options files' >&2" );
795 } else if (pOptDesc->optMaxCt == 1)
796 printf( zNoSingleArg, pOpts->pzPROGNAME,
797 pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
798 else
799 printf( zNoMultiArg, pOpts->pzPROGNAME,
800 pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
802 printf( zCmdFmt, "OPT_ARG_NEEDED=NO" );
803 fputs( zOptionEndSelect, stdout );
807 static void
808 emitFlag( tOptions* pOpts )
810 tOptDesc* pOptDesc = pOpts->pOptDesc;
811 int optionCt = pOpts->optCt;
813 fputs( zOptionCase, stdout );
815 for (;optionCt > 0; pOptDesc++, --optionCt) {
817 if (SKIP_OPT(pOptDesc))
818 continue;
820 if (isprint( pOptDesc->optValue )) {
821 printf( zOptionFlag, pOptDesc->optValue );
822 printOptionAction( pOpts, pOptDesc );
825 printf( zOptionUnknown, "flag", pOpts->pzPROGNAME );
830 * Emit the match text for a long option
832 static void
833 emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts )
835 tOptDesc* pOD = pOpts->pOptDesc;
836 int oCt = pOpts->optCt;
837 int min = 1;
838 char zName[ 256 ];
839 char* pz = zName;
841 for (;;) {
842 int matchCt = 0;
845 * Omit the current option, Documentation opts and compiled out opts.
847 if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
848 if (--oCt <= 0)
849 break;
850 pOD++;
851 continue;
855 * Check each character of the name case insensitively.
856 * They must not be the same. They cannot be, because it would
857 * not compile correctly if they were.
859 while ( toupper( (int)pOD->pz_Name[matchCt] )
860 == toupper( (int)pzMatchName[matchCt] ))
861 matchCt++;
863 if (matchCt > min)
864 min = matchCt;
867 * Check the disablement name, too.
869 if (pOD->pz_DisableName != NULL) {
870 matchCt = 0;
871 while ( toupper( (int)pOD->pz_DisableName[matchCt] )
872 == toupper( (int)pzMatchName[matchCt] ))
873 matchCt++;
874 if (matchCt > min)
875 min = matchCt;
877 if (--oCt <= 0)
878 break;
879 pOD++;
883 * IF the 'min' is all or one short of the name length,
884 * THEN the entire string must be matched.
886 if ( (pzMatchName[min ] == NUL)
887 || (pzMatchName[min+1] == NUL) )
888 printf( zOptionFullName, pzMatchName );
890 else {
891 int matchCt = 0;
892 for (; matchCt <= min; matchCt++)
893 *pz++ = pzMatchName[matchCt];
895 for (;;) {
896 *pz = NUL;
897 printf( zOptionPartName, zName );
898 *pz++ = pzMatchName[matchCt++];
899 if (pzMatchName[matchCt] == NUL) {
900 *pz = NUL;
901 printf( zOptionFullName, zName );
902 break;
910 * Emit GNU-standard long option handling code
912 static void
913 emitLong( tOptions* pOpts )
915 tOptDesc* pOD = pOpts->pOptDesc;
916 int ct = pOpts->optCt;
918 fputs( zOptionCase, stdout );
921 * do each option, ...
923 do {
925 * Documentation & compiled-out options
927 if (SKIP_OPT(pOD))
928 continue;
930 emitMatchExpr( pOD->pz_Name, pOD, pOpts );
931 printOptionAction( pOpts, pOD );
934 * Now, do the same thing for the disablement version of the option.
936 if (pOD->pz_DisableName != NULL) {
937 emitMatchExpr( pOD->pz_DisableName, pOD, pOpts );
938 printOptionInaction( pOpts, pOD );
940 } while (pOD++, --ct > 0);
942 printf( zOptionUnknown, "option", pOpts->pzPROGNAME );
946 static void
947 openOutput( char const* pzFile )
949 FILE* fp;
950 char* pzData = NULL;
951 struct stat stbf;
953 do {
954 char* pzScan;
955 size_t sizeLeft;
958 * IF we cannot stat the file,
959 * THEN assume we are creating a new file.
960 * Skip the loading of the old data.
962 if (stat( pzFile, &stbf ) != 0)
963 break;
966 * The file must be a regular file
968 if (! S_ISREG( stbf.st_mode )) {
969 fprintf( stderr, zNotFile, pzFile );
970 exit( EXIT_FAILURE );
973 pzData = AGALOC(stbf.st_size + 1, "file data");
974 fp = fopen( pzFile, "r" FOPEN_BINARY_FLAG );
976 sizeLeft = (unsigned)stbf.st_size;
977 pzScan = pzData;
980 * Read in all the data as fast as our OS will let us.
982 for (;;) {
983 int inct = fread( (void*)pzScan, (size_t)1, sizeLeft, fp);
984 if (inct == 0)
985 break;
987 pzScan += inct;
988 sizeLeft -= inct;
990 if (sizeLeft == 0)
991 break;
995 * NUL-terminate the leader and look for the trailer
997 *pzScan = '\0';
998 fclose( fp );
999 pzScan = strstr( pzData, zStartMarker );
1000 if (pzScan == NULL) {
1001 pzTrailer = pzData;
1002 break;
1005 *(pzScan++) = NUL;
1006 pzScan = strstr( pzScan, zTrailerMarker );
1007 if (pzScan == NULL) {
1008 pzTrailer = pzData;
1009 break;
1013 * Check to see if the data contains
1014 * our marker. If it does, then we will skip over it
1016 pzTrailer = pzScan + sizeof( zTrailerMarker ) - 1;
1017 pzLeader = pzData;
1018 } while (AG_FALSE);
1020 freopen( pzFile, "w" FOPEN_BINARY_FLAG, stdout );
1024 /*=export_func genshelloptUsage
1025 * private:
1026 * what: The usage function for the genshellopt generated program
1028 * arg: + tOptions* + pOpts + program options descriptor +
1029 * arg: + int + exitCode + usage text type to produce +
1031 * doc:
1032 * This function is used to create the usage strings for the option
1033 * processing shell script code. Two child processes are spawned
1034 * each emitting the usage text in either the short (error exit)
1035 * style or the long style. The generated program will capture this
1036 * and create shell script variables containing the two types of text.
1038 void
1039 genshelloptUsage( tOptions* pOpts, int exitCode )
1041 #if defined(__windows__) && !defined(__CYGWIN__)
1042 optionUsage( pOpts, exitCode );
1043 #else
1045 * IF not EXIT_SUCCESS,
1046 * THEN emit the short form of usage.
1048 if (exitCode != EXIT_SUCCESS)
1049 optionUsage( pOpts, exitCode );
1050 fflush( stderr );
1051 fflush( stdout );
1053 option_usage_fp = stdout;
1056 * First, print our usage
1058 switch (fork()) {
1059 case -1:
1060 optionUsage( pOpts, EXIT_FAILURE );
1061 /*NOTREACHED*/
1062 _exit( EXIT_FAILURE );
1064 case 0:
1065 pagerState = PAGER_STATE_CHILD;
1066 optionUsage( pOpts, EXIT_SUCCESS );
1067 /*NOTREACHED*/
1068 _exit( EXIT_FAILURE );
1070 default:
1072 int sts;
1073 wait( &sts );
1078 * Generate the pzProgName, since optionProcess() normally
1079 * gets it from the command line
1082 char* pz;
1083 AGDUPSTR( pz, pShellParseOptions->pzPROGNAME, "program name" );
1084 pShellParseOptions->pzProgName = pz;
1085 while (*pz != NUL) {
1086 *pz = tolower( (int)*pz );
1087 pz++;
1092 * Separate the makeshell usage from the client usage
1094 fprintf( option_usage_fp, zGenshell, pShellParseOptions->pzProgName );
1095 fflush( option_usage_fp );
1098 * Now, print the client usage.
1100 switch (fork()) {
1101 case 0:
1102 pagerState = PAGER_STATE_CHILD;
1103 /*FALLTHROUGH*/
1104 case -1:
1105 optionUsage( pShellParseOptions, EXIT_FAILURE );
1107 default:
1109 int sts;
1110 wait( &sts );
1114 exit( EXIT_SUCCESS );
1115 #endif
1119 * Local Variables:
1120 * mode: C
1121 * c-file-style: "stroustrup"
1122 * indent-tabs-mode: nil
1123 * End:
1124 * end of autoopts/makeshell.c */