5 * This module will interpret the options set in the tOptions
6 * structure and print them to standard out in a fashion that
7 * will allow them to be interpreted by the Bourne or Korn shells.
13 * This file is part of AutoOpts, a companion to AutoGen.
14 * AutoOpts is free software.
15 * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved
17 * AutoOpts is available under any one of two licenses. The license
18 * in use must be one of these two and the choice is under the control
19 * of the user of the license.
21 * The GNU Lesser General Public License, version 3 or later
22 * See the files "COPYING.lgplv3" and "COPYING.gplv3"
24 * The Modified Berkeley Software Distribution License
25 * See the file "COPYING.mbsd"
27 * These files have the following sha256 sums:
29 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3
30 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3
31 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd
34 /* = = = START-STATIC-FORWARD = = = */
36 string_size(char const * scan, size_t nl_len);
39 print_quoted_apostrophes(char const * str);
42 print_quot_str(char const * str);
45 print_enumeration(tOptions * pOpts, tOptDesc * pOD);
48 print_membership(tOptions * pOpts, tOptDesc * pOD);
51 print_stacked_arg(tOptions * pOpts, tOptDesc * pOD);
54 print_reordering(tOptions * opts);
55 /* = = = END-STATIC-FORWARD = = = */
58 * Count the number of bytes required to represent a string as a
61 * @param[in] scan the text to be rewritten as a C program text string.
62 * @param[in] nl_len the number of bytes used for each embedded newline.
64 * @returns the count, including the terminating NUL byte.
67 string_size(char const * scan, size_t nl_len)
70 * Start by counting the start and end quotes, plus the NUL.
76 if ((ch >= ' ') && (ch <= '~')) {
79 * a backslash allowance for double quotes and baskslashes
81 res_ln += ((ch == '"') || (ch == '\\')) ? 2 : 1;
85 * When not a normal character, then count the characters
86 * required to represent whatever it is.
106 res_ln += 4; /* text len for \xNN */
111 /*=export_func optionQuoteString
114 * what: Print a string as quoted text suitable for a C compiler.
115 * arg: + char const * + text + a block of text to quote +
116 * arg: + char const * + nl + line splice text +
118 * ret_type: char const *
119 * ret_desc: the allocated input string as a quoted string
122 * This is for internal use by autogen and autoopts.
123 * It takes an input string and produces text the C compiler can process
124 * to produce an exact copy of the original string.
125 * The caller must deallocate the result. Standard C strings and
126 * K&R strings are distinguished by the "nl" string.
129 optionQuoteString(char const * text, char const * nl)
131 size_t nl_len = strlen(nl);
133 char * res = out = AGALOC(string_size(text, nl_len), "quot str");
137 unsigned char ch = (unsigned char)*text;
138 if ((ch >= ' ') && (ch <= '~')) {
139 if ((ch == '"') || (ch == '\\'))
141 * We must escape these characters in the output string
147 # define add_esc_ch(_ch) { *(out++) = '\\'; *(out++) = (_ch); }
148 case BEL: add_esc_ch('a'); break;
149 case BS: add_esc_ch('b'); break;
150 case HT: add_esc_ch('t'); break;
151 case VT: add_esc_ch('v'); break;
152 case FF: add_esc_ch('f'); break;
153 case CR: add_esc_ch('r'); break;
157 * Place contiguous new-lines on a single line.
158 * The current character is a NL, check the next one.
160 while (*++text == NL)
164 * Insert a splice before starting next line
167 memcpy(out, nl, nl_len);
170 continue; /* text is already at the next character */
178 * End of string. Terminate the quoted output. If necessary,
179 * deallocate the text string. Return the scan resumption point.
187 * sprintf is safe here, because we already computed
188 * the amount of space we will be using.
190 sprintf(out, MK_STR_OCT_FMT, ch);
200 * Print out escaped apostorophes.
202 * @param[in] str the apostrophies to print
205 print_quoted_apostrophes(char const * str)
207 while (*str == APOSTROPHE) {
208 fputs(QUOT_APOS, stdout);
215 * Print a single quote (apostrophe quoted) string.
216 * Other than somersaults for apostrophes, nothing else needs quoting.
218 * @param[in] str the string to print
221 print_quot_str(char const * str)
224 * Handle empty strings to make the rest of the logic simpler.
226 if ((str == NULL) || (*str == NUL)) {
227 fputs(EMPTY_ARG, stdout);
232 * Emit any single quotes/apostrophes at the start of the string and
233 * bail if that is all we need to do.
235 str = print_quoted_apostrophes(str);
240 * Start the single quote string
242 fputc(APOSTROPHE, stdout);
244 char const * pz = strchr(str, APOSTROPHE);
249 * Emit the string up to the single quote (apostrophe) we just found.
251 (void)fwrite(str, (size_t)(pz - str), (size_t)1, stdout);
254 * Close the current string, emit the apostrophes and re-open the
255 * string (IFF there is more text to print).
257 fputc(APOSTROPHE, stdout);
258 str = print_quoted_apostrophes(pz);
262 fputc(APOSTROPHE, stdout);
266 * If we broke out of the loop, we must still emit the remaining text
267 * and then close the single quote string.
270 fputc(APOSTROPHE, stdout);
274 print_enumeration(tOptions * pOpts, tOptDesc * pOD)
276 uintptr_t e_val = pOD->optArg.argEnum;
277 printf(OPT_VAL_FMT, pOpts->pzPROGNAME, pOD->pz_NAME);
280 * Convert value to string, print that and restore numeric value.
282 (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);
283 printf(QUOT_ARG_FMT, pOD->optArg.argString);
284 if (pOD->fOptState & OPTST_ALLOC_ARG)
285 AGFREE(pOD->optArg.argString);
286 pOD->optArg.argEnum = e_val;
288 printf(OPT_END_FMT, pOpts->pzPROGNAME, pOD->pz_NAME);
292 print_membership(tOptions * pOpts, tOptDesc * pOD)
294 char const * svstr = pOD->optArg.argString;
297 printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
298 (int)(uintptr_t)(pOD->optCookie));
299 pOD->optCookie = VOIDP(~0UL);
300 (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);
302 pz = pOD->optArg.argString;
304 printf("readonly %s_", pOD->pz_NAME);
305 pz = SPN_PLUS_N_SPACE_CHARS(pz);
309 if (IS_LOWER_CASE_CHAR(ch)) fputc(toupper(ch), stdout);
310 else if (IS_UPPER_CASE_CHAR(ch)) fputc(ch, stdout);
311 else if (IS_PLUS_N_SPACE_CHAR(ch)) goto name_done;
312 else if (ch == NUL) { pz--; goto name_done; }
313 else fputc('_', stdout);
315 printf(SHOW_VAL_FMT, (unsigned long)val);
319 AGFREE(pOD->optArg.argString);
320 pOD->optArg.argString = svstr;
324 print_stacked_arg(tOptions * pOpts, tOptDesc * pOD)
326 tArgList * pAL = (tArgList *)pOD->optCookie;
327 char const ** ppz = pAL->apzArgs;
330 printf(zOptCookieCt, pOpts->pzPROGNAME, pOD->pz_NAME, ct);
333 printf(ARG_BY_NUM_FMT, pOpts->pzPROGNAME, pOD->pz_NAME,
335 print_quot_str(*(ppz++));
336 printf(EXPORT_ARG_FMT, pOpts->pzPROGNAME, pOD->pz_NAME,
342 * emit the arguments as readily parsed text.
343 * The program options are set by emitting the shell "set" command.
345 * @param[in] opts the program options structure
348 print_reordering(tOptions * opts)
352 fputs(set_dash, stdout);
354 for (ix = opts->curOptIdx;
355 ix < opts->origArgCt;
358 print_quot_str(opts->origArgVect[ ix ]);
360 fputs(init_optct, stdout);
363 /*=export_func optionPutShell
364 * what: write a portable shell script to parse options
366 * arg: tOptions *, pOpts, the program options descriptor
367 * doc: This routine will emit portable shell script text for parsing
368 * the options described in the option definitions.
371 optionPutShell(tOptions * pOpts)
375 printf(zOptCtFmt, pOpts->curOptIdx-1);
378 tOptDesc * pOD = pOpts->pOptDesc + optIx;
380 if ((pOD->fOptState & OPTST_NO_OUTPUT_MASK) != 0)
384 * Equivalence classes are hard to deal with. Where the
385 * option data wind up kind of squishes around. For the purposes
386 * of emitting shell state, they are not recommended, but we'll
387 * do something. I guess we'll emit the equivalenced-to option
388 * at the point in time when the base option is found.
390 if (pOD->optEquivIndex != NO_EQUIVALENT)
391 continue; /* equivalence to a different option */
394 * Equivalenced to a different option. Process the current option
395 * as the equivalenced-to option. Keep the persistent state bits,
396 * but copy over the set-state bits.
398 if (pOD->optActualIndex != optIx) {
399 tOptDesc * p = pOpts->pOptDesc + pOD->optActualIndex;
400 p->optArg = pOD->optArg;
401 p->fOptState &= OPTST_PERSISTENT_MASK;
402 p->fOptState |= pOD->fOptState & ~OPTST_PERSISTENT_MASK;
403 printf(zEquivMode, pOpts->pzPROGNAME, pOD->pz_NAME, p->pz_NAME);
408 * If the argument type is a set membership bitmask, then we always
409 * emit the thing. We do this because it will always have some sort
410 * of bitmask value and we need to emit the bit values.
412 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
413 print_membership(pOpts, pOD);
418 * IF the option was either specified or it wakes up enabled,
419 * then we will emit information. Otherwise, skip it.
420 * The idea is that if someone defines an option to initialize
421 * enabled, we should tell our shell script that it is enabled.
423 if (UNUSED_OPT(pOD) && DISABLED_OPT(pOD))
427 * Handle stacked arguments
429 if ( (pOD->fOptState & OPTST_STACKED)
430 && (pOD->optCookie != NULL) ) {
431 print_stacked_arg(pOpts, pOD);
436 * If the argument has been disabled,
437 * Then set its value to the disablement string
439 if ((pOD->fOptState & OPTST_DISABLED) != 0) {
440 printf(zOptDisabl, pOpts->pzPROGNAME, pOD->pz_NAME,
441 (pOD->pz_DisablePfx != NULL)
442 ? pOD->pz_DisablePfx : "false");
447 * If the argument type is numeric, the last arg pointer
448 * is really the VALUE of the string that was pointed to.
450 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC) {
451 printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
452 (int)pOD->optArg.argInt);
457 * If the argument type is an enumeration, then it is much
458 * like a text value, except we call the callback function
459 * to emit the value corresponding to the "optArg" number.
461 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_ENUMERATION) {
462 print_enumeration(pOpts, pOD);
467 * If the argument type is numeric, the last arg pointer
468 * is really the VALUE of the string that was pointed to.
470 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_BOOLEAN) {
471 printf(zFullOptFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
472 (pOD->optArg.argBool == 0) ? "false" : "true");
477 * IF the option has an empty value,
478 * THEN we set the argument to the occurrence count.
480 if ( (pOD->optArg.argString == NULL)
481 || (pOD->optArg.argString[0] == NUL) ) {
483 printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
489 * This option has a text value
491 printf(OPT_VAL_FMT, pOpts->pzPROGNAME, pOD->pz_NAME);
492 print_quot_str(pOD->optArg.argString);
493 printf(OPT_END_FMT, pOpts->pzPROGNAME, pOD->pz_NAME);
495 } while (++optIx < pOpts->presetOptCt );
497 if ( ((pOpts->fOptSet & OPTPROC_REORDER) != 0)
498 && (pOpts->curOptIdx < pOpts->origArgCt))
499 print_reordering(pOpts);
508 * c-file-style: "stroustrup"
509 * indent-tabs-mode: nil
511 * end of autoopts/putshell.c */