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