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