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