1:
2: /**
3: * \file putshell.c
4: *
5: * Time-stamp: "2010-09-05 06:10:56 bkorb"
6: *
7: * This module will interpret the options set in the tOptions
8: * structure and print them to standard out in a fashion that
9: * will allow them to be interpreted by the Bourne or Korn shells.
10: *
11: * This file is part of AutoOpts, a companion to AutoGen.
12: * AutoOpts is free software.
13: * AutoOpts is Copyright (c) 1992-2011 by Bruce Korb - all rights reserved
14: *
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.
18: *
19: * The GNU Lesser General Public License, version 3 or later
20: * See the files "COPYING.lgplv3" and "COPYING.gplv3"
21: *
22: * The Modified Berkeley Software Distribution License
23: * See the file "COPYING.mbsd"
24: *
25: * These files have the following md5sums:
26: *
27: * 43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
28: * 06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
29: * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
30: */
31: static char const zOptValFmt[] = "%s_%s=";
32: static char const zOptEnd[] = "\nexport %s_%s\n";
33: static char const zOptNumFmt[] = "%1$s_%2$s=%3$d # 0x%3$X\nexport %1$s_%2$s\n";
34:
35: /* = = = START-STATIC-FORWARD = = = */
36: static void
37: print_quot_str(tCC* pzStr);
38:
39: static void
40: print_enumeration(tOptions * pOpts, tOptDesc * pOD);
41:
42: static void
43: print_membership(tOptions * pOpts, tOptDesc * pOD);
44:
45: static void
46: print_stacked_arg(tOptions * pOpts, tOptDesc * pOD);
47:
48: static void
49: print_reordering(tOptions * pOpts);
50: /* = = = END-STATIC-FORWARD = = = */
51:
52: /*
53: * Make sure embedded single quotes come out okay. The initial quote has
54: * been emitted and the closing quote will be upon return.
55: */
56: static void
57: print_quot_str(tCC* pzStr)
58: {
59: /*
60: * Handle empty strings to make the rest of the logic simpler.
61: */
62: if ((pzStr == NULL) || (*pzStr == NUL)) {
63: fputs("''", stdout);
64: return;
65: }
66:
67: /*
68: * Emit any single quotes/apostrophes at the start of the string and
69: * bail if that is all we need to do.
70: */
71: while (*pzStr == '\'') {
72: fputs("\\'", stdout);
73: pzStr++;
74: }
75: if (*pzStr == NUL)
76: return;
77:
78: /*
79: * Start the single quote string
80: */
81: fputc('\'', stdout);
82: for (;;) {
83: tCC* pz = strchr(pzStr, '\'');
84: if (pz == NULL)
85: break;
86:
87: /*
88: * Emit the string up to the single quote (apostrophe) we just found.
89: */
90: (void)fwrite(pzStr, (size_t)(pz - pzStr), (size_t)1, stdout);
91: fputc('\'', stdout);
92: pzStr = pz;
93:
94: /*
95: * Emit an escaped apostrophe for every one we find.
96: * If that ends the string, do not re-open the single quotes.
97: */
98: while (*++pzStr == '\'') fputs("\\'", stdout);
99: if (*pzStr == NUL)
100: return;
101:
102: fputc('\'', stdout);
103: }
104:
105: /*
106: * If we broke out of the loop, we must still emit the remaining text
107: * and then close the single quote string.
108: */
109: fputs(pzStr, stdout);
110: fputc('\'', stdout);
111: }
112:
113: static void
114: print_enumeration(tOptions * pOpts, tOptDesc * pOD)
115: {
116: uintptr_t e_val = pOD->optArg.argEnum;
117: printf(zOptValFmt, pOpts->pzPROGNAME, pOD->pz_NAME);
118:
119: /*
120: * Convert value to string, print that and restore numeric value.
121: */
122: (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);
123: printf("'%s'", pOD->optArg.argString);
124: if (pOD->fOptState & OPTST_ALLOC_ARG)
125: AGFREE(pOD->optArg.argString);
126: pOD->optArg.argEnum = e_val;
127:
128: printf(zOptEnd, pOpts->pzPROGNAME, pOD->pz_NAME);
129: }
130:
131: static void
132: print_membership(tOptions * pOpts, tOptDesc * pOD)
133: {
134: char const * pz;
135: uintptr_t val = 1;
136: printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
137: (int)(uintptr_t)(pOD->optCookie));
138: pOD->optCookie = (void*)(uintptr_t)~0UL;
139: (*(pOD->pOptProc))(OPTPROC_RETURN_VALNAME, pOD);
140:
141: /*
142: * We are building the typeset list. The list returned starts with
143: * 'none + ' for use by option saving stuff. We must ignore that.
144: */
145: pz = pOD->optArg.argString + 7;
146: while (*pz != NUL) {
147: printf("typeset -x -i %s_", pOD->pz_NAME);
148: while (IS_PLUS_N_SPACE_CHAR(*pz)) pz++;
149:
150: for (;;) {
151: int ch = *(pz++);
152: if (IS_LOWER_CASE_CHAR(ch)) fputc(toupper(ch), stdout);
153: else if (IS_UPPER_CASE_CHAR(ch)) fputc(ch, stdout);
154: else if (IS_PLUS_N_SPACE_CHAR(ch)) goto name_done;
155: else if (ch == NUL) { pz--; goto name_done; }
156: else fputc('_', stdout);
157: } name_done:;
158: printf("=%1$lu # 0x%1$lX\n", (unsigned long)val);
159: val <<= 1;
160: }
161:
162: AGFREE(pOD->optArg.argString);
163: pOD->optArg.argString = NULL;
164: pOD->fOptState &= ~OPTST_ALLOC_ARG;
165: }
166:
167: static void
168: print_stacked_arg(tOptions * pOpts, tOptDesc * pOD)
169: {
170: tSCC zOptCookieCt[] = "%1$s_%2$s_CT=%3$d\nexport %1$s_%2$s_CT\n";
171:
172: tArgList* pAL = (tArgList*)pOD->optCookie;
173: tCC** ppz = pAL->apzArgs;
174: int ct = pAL->useCt;
175:
176: printf(zOptCookieCt, pOpts->pzPROGNAME, pOD->pz_NAME, ct);
177:
178: while (--ct >= 0) {
179: tSCC numarg_z[] = "%s_%s_%d=";
180: tSCC end_z[] = "\nexport %s_%s_%d\n";
181:
182: printf(numarg_z, pOpts->pzPROGNAME, pOD->pz_NAME,
183: pAL->useCt - ct);
184: print_quot_str(*(ppz++));
185: printf(end_z, pOpts->pzPROGNAME, pOD->pz_NAME,
186: pAL->useCt - ct);
187: }
188: }
189:
190: static void
191: print_reordering(tOptions * pOpts)
192: {
193: int optIx;
194:
195: fputs("set --", stdout);
196:
197: for (optIx = pOpts->curOptIdx; optIx < pOpts->origArgCt; optIx++) {
198:
199: char* pzArg = pOpts->origArgVect[ optIx ];
200:
201: if (strchr(pzArg, '\'') == NULL)
202: printf(" '%s'", pzArg);
203:
204: else {
205: fputs(" '", stdout);
206: for (;;) {
207: char ch = *(pzArg++);
208: switch (ch) {
209: case '\'': fputs("'\\''", stdout); break;
210: case NUL: goto arg_done;
211: default: fputc(ch, stdout); break;
212: }
213: } arg_done:;
214: fputc('\'', stdout);
215: }
216: }
217: fputs("\nOPTION_CT=0\n", stdout);
218: }
219:
220: /*=export_func optionPutShell
221: * what: write a portable shell script to parse options
222: * private:
223: * arg: tOptions*, pOpts, the program options descriptor
224: * doc: This routine will emit portable shell script text for parsing
225: * the options described in the option definitions.
226: =*/
227: void
228: optionPutShell(tOptions* pOpts)
229: {
230: int optIx = 0;
231: tSCC zOptCtFmt[] = "OPTION_CT=%d\nexport OPTION_CT\n";
232: tSCC zOptDisabl[] = "%1$s_%2$s=%3$s\nexport %1$s_%2$s\n";
233: tSCC zFullOptFmt[]= "%1$s_%2$s='%3$s'\nexport %1$s_%2$s\n";
234: tSCC zEquivMode[] = "%1$s_%2$s_MODE='%3$s'\nexport %1$s_%2$s_MODE\n";
235:
236: printf(zOptCtFmt, pOpts->curOptIdx-1);
237:
238: do {
239: tOptDesc* pOD = pOpts->pOptDesc + optIx;
240:
241: if (SKIP_OPT(pOD))
242: continue;
243:
244: /*
245: * Equivalence classes are hard to deal with. Where the
246: * option data wind up kind of squishes around. For the purposes
247: * of emitting shell state, they are not recommended, but we'll
248: * do something. I guess we'll emit the equivalenced-to option
249: * at the point in time when the base option is found.
250: */
251: if (pOD->optEquivIndex != NO_EQUIVALENT)
252: continue; /* equivalence to a different option */
253:
254: /*
255: * Equivalenced to a different option. Process the current option
256: * as the equivalenced-to option. Keep the persistent state bits,
257: * but copy over the set-state bits.
258: */
259: if (pOD->optActualIndex != optIx) {
260: tOptDesc* p = pOpts->pOptDesc + pOD->optActualIndex;
261: p->optArg = pOD->optArg;
262: p->fOptState &= OPTST_PERSISTENT_MASK;
263: p->fOptState |= pOD->fOptState & ~OPTST_PERSISTENT_MASK;
264: printf(zEquivMode, pOpts->pzPROGNAME, pOD->pz_NAME, p->pz_NAME);
265: pOD = p;
266: }
267:
268: /*
269: * If the argument type is a set membership bitmask, then we always
270: * emit the thing. We do this because it will always have some sort
271: * of bitmask value and we need to emit the bit values.
272: */
273: if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
274: print_membership(pOpts, pOD);
275: continue;
276: }
277:
278: /*
279: * IF the option was either specified or it wakes up enabled,
280: * then we will emit information. Otherwise, skip it.
281: * The idea is that if someone defines an option to initialize
282: * enabled, we should tell our shell script that it is enabled.
283: */
284: if (UNUSED_OPT(pOD) && DISABLED_OPT(pOD)) {
285: continue;
286: }
287:
288: /*
289: * Handle stacked arguments
290: */
291: if ( (pOD->fOptState & OPTST_STACKED)
292: && (pOD->optCookie != NULL) ) {
293: print_stacked_arg(pOpts, pOD);
294: continue;
295: }
296:
297: /*
298: * If the argument has been disabled,
299: * Then set its value to the disablement string
300: */
301: if ((pOD->fOptState & OPTST_DISABLED) != 0) {
302: printf(zOptDisabl, pOpts->pzPROGNAME, pOD->pz_NAME,
303: (pOD->pz_DisablePfx != NULL)
304: ? pOD->pz_DisablePfx : "false");
305: continue;
306: }
307:
308: /*
309: * If the argument type is numeric, the last arg pointer
310: * is really the VALUE of the string that was pointed to.
311: */
312: if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC) {
313: printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
314: (int)pOD->optArg.argInt);
315: continue;
316: }
317:
318: /*
319: * If the argument type is an enumeration, then it is much
320: * like a text value, except we call the callback function
321: * to emit the value corresponding to the "optArg" number.
322: */
323: if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_ENUMERATION) {
324: print_enumeration(pOpts, pOD);
325: continue;
326: }
327:
328: /*
329: * If the argument type is numeric, the last arg pointer
330: * is really the VALUE of the string that was pointed to.
331: */
332: if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_BOOLEAN) {
333: printf(zFullOptFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
334: (pOD->optArg.argBool == 0) ? "false" : "true");
335: continue;
336: }
337:
338: /*
339: * IF the option has an empty value,
340: * THEN we set the argument to the occurrence count.
341: */
342: if ( (pOD->optArg.argString == NULL)
343: || (pOD->optArg.argString[0] == NUL) ) {
344:
345: printf(zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
346: pOD->optOccCt);
347: continue;
348: }
349:
350: /*
351: * This option has a text value
352: */
353: printf(zOptValFmt, pOpts->pzPROGNAME, pOD->pz_NAME);
354: print_quot_str(pOD->optArg.argString);
355: printf(zOptEnd, pOpts->pzPROGNAME, pOD->pz_NAME);
356:
357: } while (++optIx < pOpts->presetOptCt );
358:
359: if ( ((pOpts->fOptSet & OPTPROC_REORDER) != 0)
360: && (pOpts->curOptIdx < pOpts->origArgCt))
361: print_reordering(pOpts);
362:
363: fflush(stdout);
364: }
365:
366: /*
367: * Local Variables:
368: * mode: C
369: * c-file-style: "stroustrup"
370: * indent-tabs-mode: nil
371: * End:
372: * end of autoopts/putshell.c */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>