3 * $Id: putshell.c,v 4.18 2007/02/04 17:44:12 bkorb Exp $
4 * Time-stamp: "2007-01-13 10:29:39 bkorb"
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.
12 * Automated Options copyright 1992-2007 Bruce Korb
14 * Automated Options is free software.
15 * You may redistribute it and/or modify it under the terms of the
16 * GNU General Public License, as published by the Free Software
17 * Foundation; either version 2, or (at your option) any later version.
19 * Automated Options is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Automated Options. See the file "COPYING". If not,
26 * write to: The Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor,
28 * Boston, MA 02110-1301, USA.
30 * As a special exception, Bruce Korb gives permission for additional
31 * uses of the text contained in his release of AutoOpts.
33 * The exception is that, if you link the AutoOpts library with other
34 * files to produce an executable, this does not by itself cause the
35 * resulting executable to be covered by the GNU General Public License.
36 * Your use of that executable is in no way restricted on account of
37 * linking the AutoOpts library code into it.
39 * This exception does not however invalidate any other reasons why
40 * the executable file might be covered by the GNU General Public License.
42 * This exception applies only to the code released by Bruce Korb under
43 * the name AutoOpts. If you copy code from other sources under the
44 * General Public License into a copy of AutoOpts, as the General Public
45 * License permits, the exception does not apply to the code that you add
46 * in this way. To avoid misleading anyone as to the status of such
47 * modified files, you must delete this exception notice from them.
49 * If you write modifications of your own for AutoOpts, it is your choice
50 * whether to permit this exception to apply to your modifications.
51 * If you do not wish that, delete this exception notice.
54 /* = = = START-STATIC-FORWARD = = = */
55 /* static forward declarations maintained by :mkfwd */
57 putQuotedStr( tCC* pzStr );
58 /* = = = END-STATIC-FORWARD = = = */
61 * Make sure embedded single quotes come out okay. The initial quote has
62 * been emitted and the closing quote will be upon return.
65 putQuotedStr( tCC* pzStr )
68 * Handle empty strings to make the rest of the logic simpler.
70 if ((pzStr == NULL) || (*pzStr == NUL)) {
71 fputs( "''", stdout );
76 * Emit any single quotes/apostrophes at the start of the string and
77 * bail if that is all we need to do.
79 while (*pzStr == '\'') {
80 fputs( "\\'", stdout );
87 * Start the single quote string
89 fputc( '\'', stdout );
91 tCC* pz = strchr( pzStr, '\'' );
96 * Emit the string up to the single quote (apostrophe) we just found.
98 (void)fwrite( pzStr, (size_t)(pz - pzStr), (size_t)1, stdout );
99 fputc( '\'', stdout );
103 * Emit an escaped apostrophe for every one we find.
104 * If that ends the string, do not re-open the single quotes.
106 while (*++pzStr == '\'') fputs( "\\'", stdout );
110 fputc( '\'', stdout );
114 * If we broke out of the loop, we must still emit the remaining text
115 * and then close the single quote string.
117 fputs( pzStr, stdout );
118 fputc( '\'', stdout );
122 /*=export_func optionPutShell
123 * what: write a portable shell script to parse options
125 * arg: tOptions*, pOpts, the program options descriptor
126 * doc: This routine will emit portable shell script text for parsing
127 * the options described in the option definitions.
130 optionPutShell( tOptions* pOpts )
133 tSCC zOptCtFmt[] = "OPTION_CT=%d\nexport OPTION_CT\n";
134 tSCC zOptNumFmt[] = "%1$s_%2$s=%3$d # 0x%3$X\nexport %1$s_%2$s\n";
135 tSCC zOptDisabl[] = "%1$s_%2$s=%3$s\nexport %1$s_%2$s\n";
136 tSCC zOptValFmt[] = "%s_%s=";
137 tSCC zOptEnd[] = "\nexport %s_%s\n";
138 tSCC zFullOptFmt[]= "%1$s_%2$s='%3$s'\nexport %1$s_%2$s\n";
139 tSCC zEquivMode[] = "%1$s_%2$s_MODE='%3$s'\nexport %1$s_%2$s_MODE\n";
141 printf( zOptCtFmt, pOpts->curOptIdx-1 );
144 tOptDesc* pOD = pOpts->pOptDesc + optIx;
150 * Equivalence classes are hard to deal with. Where the
151 * option data wind up kind of squishes around. For the purposes
152 * of emitting shell state, they are not recommended, but we'll
153 * do something. I guess we'll emit the equivalenced-to option
154 * at the point in time when the base option is found.
156 if (pOD->optEquivIndex != NO_EQUIVALENT)
157 continue; /* equivalence to a different option */
160 * Equivalenced to a different option. Process the current option
161 * as the equivalenced-to option. Keep the persistent state bits,
162 * but copy over the set-state bits.
164 if (pOD->optActualIndex != optIx) {
165 tOptDesc* p = pOpts->pOptDesc + pOD->optActualIndex;
166 p->optArg = pOD->optArg;
167 p->fOptState &= OPTST_PERSISTENT_MASK;
168 p->fOptState |= pOD->fOptState & ~OPTST_PERSISTENT_MASK;
169 printf( zEquivMode, pOpts->pzPROGNAME, pOD->pz_NAME, p->pz_NAME );
174 * If the argument type is a set membership bitmask, then we always
175 * emit the thing. We do this because it will always have some sort
176 * of bitmask value and we need to emit the bit values.
178 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) {
181 printf( zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
182 (int)(uintptr_t)(pOD->optCookie) );
183 pOD->optCookie = (void*)(uintptr_t)~0UL;
184 (*(pOD->pOptProc))( (tOptions*)2UL, pOD );
187 * We are building the typeset list. The list returned starts with
188 * 'none + ' for use by option saving stuff. We must ignore that.
190 pz = pOD->optArg.argString + 7;
192 printf( "typeset -x -i %s_", pOD->pz_NAME );
193 pz += strspn( pz, " +\t\n\f" );
196 if (islower( ch )) fputc( toupper( ch ), stdout );
197 else if (isalnum( ch )) fputc( ch, stdout );
198 else if (isspace( ch )
199 || (ch == '+')) goto name_done;
200 else if (ch == NUL) { pz--; goto name_done; }
201 else fputc( '_', stdout );
203 printf( "=%1$lu # 0x%1$lX\n", (unsigned long)val );
207 AGFREE(pOD->optArg.argString);
208 pOD->optArg.argString = NULL;
209 pOD->fOptState &= ~OPTST_ALLOC_ARG;
214 * IF the option was either specified or it wakes up enabled,
215 * then we will emit information. Otherwise, skip it.
216 * The idea is that if someone defines an option to initialize
217 * enabled, we should tell our shell script that it is enabled.
219 if (UNUSED_OPT( pOD ) && DISABLED_OPT( pOD ))
223 * Handle stacked arguments
225 if ( (pOD->fOptState & OPTST_STACKED)
226 && (pOD->optCookie != NULL) ) {
227 tSCC zOptCookieCt[] = "%1$s_%2$s_CT=%3$d\nexport %1$s_%2$s_CT\n";
229 tArgList* pAL = (tArgList*)pOD->optCookie;
230 tCC** ppz = pAL->apzArgs;
233 printf( zOptCookieCt, pOpts->pzPROGNAME, pOD->pz_NAME, ct );
236 tSCC numarg_z[] = "%s_%s_%d=";
237 tSCC end_z[] = "\nexport %s_%s_%d\n";
239 printf( numarg_z, pOpts->pzPROGNAME, pOD->pz_NAME,
241 putQuotedStr( *(ppz++) );
242 printf( end_z, pOpts->pzPROGNAME, pOD->pz_NAME,
248 * If the argument has been disabled,
249 * Then set its value to the disablement string
251 else if ((pOD->fOptState & OPTST_DISABLED) != 0)
252 printf( zOptDisabl, pOpts->pzPROGNAME, pOD->pz_NAME,
253 (pOD->pz_DisablePfx != NULL)
254 ? pOD->pz_DisablePfx : "false" );
257 * If the argument type is numeric, the last arg pointer
258 * is really the VALUE of the string that was pointed to.
260 else if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC)
261 printf( zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
262 (int)pOD->optArg.argInt );
265 * If the argument type is an enumeration, then it is much
266 * like a text value, except we call the callback function
267 * to emit the value corresponding to the "optArg" number.
269 else if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_ENUMERATION) {
270 printf( zOptValFmt, pOpts->pzPROGNAME, pOD->pz_NAME );
271 fputc( '\'', stdout );
272 (*(pOD->pOptProc))( (tOptions*)1UL, pOD );
273 fputc( '\'', stdout );
274 printf( zOptEnd, pOpts->pzPROGNAME, pOD->pz_NAME );
278 * If the argument type is numeric, the last arg pointer
279 * is really the VALUE of the string that was pointed to.
281 else if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_BOOLEAN)
282 printf( zFullOptFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
283 (pOD->optArg.argBool == 0) ? "false" : "true" );
286 * IF the option has an empty value,
287 * THEN we set the argument to the occurrence count.
289 else if ( (pOD->optArg.argString == NULL)
290 || (pOD->optArg.argString[0] == NUL) )
292 printf( zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME,
296 * This option has a text value
299 printf( zOptValFmt, pOpts->pzPROGNAME, pOD->pz_NAME );
300 putQuotedStr( pOD->optArg.argString );
301 printf( zOptEnd, pOpts->pzPROGNAME, pOD->pz_NAME );
303 } while (++optIx < pOpts->presetOptCt );
305 if ( ((pOpts->fOptSet & OPTPROC_REORDER) != 0)
306 && (pOpts->curOptIdx < pOpts->origArgCt)) {
307 fputs( "set --", stdout );
308 for (optIx = pOpts->curOptIdx; optIx < pOpts->origArgCt; optIx++) {
309 char* pzArg = pOpts->origArgVect[ optIx ];
310 if (strchr( pzArg, '\'' ) == NULL)
311 printf( " '%s'", pzArg );
313 fputs( " '", stdout );
315 char ch = *(pzArg++);
317 case '\'': fputs( "'\\''", stdout ); break;
318 case NUL: goto arg_done;
319 default: fputc( ch, stdout ); break;
322 fputc( '\'', stdout );
325 fputs( "\nOPTION_CT=0\n", stdout );
332 * c-file-style: "stroustrup"
333 * indent-tabs-mode: nil
335 * end of autoopts/putshell.c */