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