1 2 /* 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" 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 11 /* 12 * Automated Options copyright 1992-2007 Bruce Korb 13 * 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. 18 * 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. 23 * 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. 29 * 30 * As a special exception, Bruce Korb gives permission for additional 31 * uses of the text contained in his release of AutoOpts. 32 * 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. 38 * 39 * This exception does not however invalidate any other reasons why 40 * the executable file might be covered by the GNU General Public License. 41 * 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. 48 * 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. 52 */ 53 54 /* = = = START-STATIC-FORWARD = = = */ 55 /* static forward declarations maintained by :mkfwd */ 56 static void 57 putQuotedStr( tCC* pzStr ); 58 /* = = = END-STATIC-FORWARD = = = */ 59 60 /* 61 * Make sure embedded single quotes come out okay. The initial quote has 62 * been emitted and the closing quote will be upon return. 63 */ 64 static void 65 putQuotedStr( tCC* pzStr ) 66 { 67 /* 68 * Handle empty strings to make the rest of the logic simpler. 69 */ 70 if ((pzStr == NULL) || (*pzStr == NUL)) { 71 fputs( "''", stdout ); 72 return; 73 } 74 75 /* 76 * Emit any single quotes/apostrophes at the start of the string and 77 * bail if that is all we need to do. 78 */ 79 while (*pzStr == '\'') { 80 fputs( "\\'", stdout ); 81 pzStr++; 82 } 83 if (*pzStr == NUL) 84 return; 85 86 /* 87 * Start the single quote string 88 */ 89 fputc( '\'', stdout ); 90 for (;;) { 91 tCC* pz = strchr( pzStr, '\'' ); 92 if (pz == NULL) 93 break; 94 95 /* 96 * Emit the string up to the single quote (apostrophe) we just found. 97 */ 98 (void)fwrite( pzStr, (size_t)(pz - pzStr), (size_t)1, stdout ); 99 fputc( '\'', stdout ); 100 pzStr = pz; 101 102 /* 103 * Emit an escaped apostrophe for every one we find. 104 * If that ends the string, do not re-open the single quotes. 105 */ 106 while (*++pzStr == '\'') fputs( "\\'", stdout ); 107 if (*pzStr == NUL) 108 return; 109 110 fputc( '\'', stdout ); 111 } 112 113 /* 114 * If we broke out of the loop, we must still emit the remaining text 115 * and then close the single quote string. 116 */ 117 fputs( pzStr, stdout ); 118 fputc( '\'', stdout ); 119 } 120 121 122 /*=export_func optionPutShell 123 * what: write a portable shell script to parse options 124 * private: 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. 128 =*/ 129 void 130 optionPutShell( tOptions* pOpts ) 131 { 132 int optIx = 0; 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"; 140 141 printf( zOptCtFmt, pOpts->curOptIdx-1 ); 142 143 do { 144 tOptDesc* pOD = pOpts->pOptDesc + optIx; 145 146 if (SKIP_OPT(pOD)) 147 continue; 148 149 /* 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. 155 */ 156 if (pOD->optEquivIndex != NO_EQUIVALENT) 157 continue; /* equivalence to a different option */ 158 159 /* 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. 163 */ 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 ); 170 pOD = p; 171 } 172 173 /* 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. 177 */ 178 if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP) { 179 char const * pz; 180 uintptr_t val = 1; 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 ); 185 186 /* 187 * We are building the typeset list. The list returned starts with 188 * 'none + ' for use by option saving stuff. We must ignore that. 189 */ 190 pz = pOD->optArg.argString + 7; 191 while (*pz != NUL) { 192 printf( "typeset -x -i %s_", pOD->pz_NAME ); 193 pz += strspn( pz, " +\t\n\f" ); 194 for (;;) { 195 int ch = *(pz++); 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 ); 202 } name_done:; 203 printf( "=%1$lu # 0x%1$lX\n", (unsigned long)val ); 204 val <<= 1; 205 } 206 207 AGFREE(pOD->optArg.argString); 208 pOD->optArg.argString = NULL; 209 pOD->fOptState &= ~OPTST_ALLOC_ARG; 210 continue; 211 } 212 213 /* 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. 218 */ 219 if (UNUSED_OPT( pOD ) && DISABLED_OPT( pOD )) 220 continue; 221 222 /* 223 * Handle stacked arguments 224 */ 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"; 228 229 tArgList* pAL = (tArgList*)pOD->optCookie; 230 tCC** ppz = pAL->apzArgs; 231 int ct = pAL->useCt; 232 233 printf( zOptCookieCt, pOpts->pzPROGNAME, pOD->pz_NAME, ct ); 234 235 while (--ct >= 0) { 236 tSCC numarg_z[] = "%s_%s_%d="; 237 tSCC end_z[] = "\nexport %s_%s_%d\n"; 238 239 printf( numarg_z, pOpts->pzPROGNAME, pOD->pz_NAME, 240 pAL->useCt - ct ); 241 putQuotedStr( *(ppz++) ); 242 printf( end_z, pOpts->pzPROGNAME, pOD->pz_NAME, 243 pAL->useCt - ct ); 244 } 245 } 246 247 /* 248 * If the argument has been disabled, 249 * Then set its value to the disablement string 250 */ 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" ); 255 256 /* 257 * If the argument type is numeric, the last arg pointer 258 * is really the VALUE of the string that was pointed to. 259 */ 260 else if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_NUMERIC) 261 printf( zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME, 262 (int)pOD->optArg.argInt ); 263 264 /* 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. 268 */ 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 ); 275 } 276 277 /* 278 * If the argument type is numeric, the last arg pointer 279 * is really the VALUE of the string that was pointed to. 280 */ 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" ); 284 285 /* 286 * IF the option has an empty value, 287 * THEN we set the argument to the occurrence count. 288 */ 289 else if ( (pOD->optArg.argString == NULL) 290 || (pOD->optArg.argString[0] == NUL) ) 291 292 printf( zOptNumFmt, pOpts->pzPROGNAME, pOD->pz_NAME, 293 pOD->optOccCt ); 294 295 /* 296 * This option has a text value 297 */ 298 else { 299 printf( zOptValFmt, pOpts->pzPROGNAME, pOD->pz_NAME ); 300 putQuotedStr( pOD->optArg.argString ); 301 printf( zOptEnd, pOpts->pzPROGNAME, pOD->pz_NAME ); 302 } 303 } while (++optIx < pOpts->presetOptCt ); 304 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 ); 312 else { 313 fputs( " '", stdout ); 314 for (;;) { 315 char ch = *(pzArg++); 316 switch (ch) { 317 case '\'': fputs( "'\\''", stdout ); break; 318 case NUL: goto arg_done; 319 default: fputc( ch, stdout ); break; 320 } 321 } arg_done:; 322 fputc( '\'', stdout ); 323 } 324 } 325 fputs( "\nOPTION_CT=0\n", stdout ); 326 } 327 } 328 329 /* 330 * Local Variables: 331 * mode: C 332 * c-file-style: "stroustrup" 333 * indent-tabs-mode: nil 334 * End: 335 * end of autoopts/putshell.c */ 336