1 2 /** 3 * \file environment.c 4 * 5 * This file contains all of the routines that must be linked into 6 * an executable to use the generated option processing. The optional 7 * routines are in separately compiled modules so that they will not 8 * necessarily be linked in. 9 * 10 * @addtogroup autoopts 11 * @{ 12 */ 13 /* 14 * This file is part of AutoOpts, a companion to AutoGen. 15 * AutoOpts is free software. 16 * AutoOpts is Copyright (C) 1992-2015 by Bruce Korb - all rights reserved 17 * 18 * AutoOpts is available under any one of two licenses. The license 19 * in use must be one of these two and the choice is under the control 20 * of the user of the license. 21 * 22 * The GNU Lesser General Public License, version 3 or later 23 * See the files "COPYING.lgplv3" and "COPYING.gplv3" 24 * 25 * The Modified Berkeley Software Distribution License 26 * See the file "COPYING.mbsd" 27 * 28 * These files have the following sha256 sums: 29 * 30 * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 31 * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 32 * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 33 */ 34 35 /* = = = START-STATIC-FORWARD = = = */ 36 static void 37 do_env_opt(tOptState * os, char * env_name, 38 tOptions * pOpts, teEnvPresetType type); 39 /* = = = END-STATIC-FORWARD = = = */ 40 41 /* 42 * doPrognameEnv - check for preset values from the ${PROGNAME} 43 * environment variable. This is accomplished by parsing the text into 44 * tokens, temporarily replacing the arg vector and calling 45 * immediate_opts and/or regular_opts. 46 */ 47 LOCAL void 48 doPrognameEnv(tOptions * pOpts, teEnvPresetType type) 49 { 50 char const * env_opts = getenv(pOpts->pzPROGNAME); 51 token_list_t * pTL; 52 int sv_argc; 53 proc_state_mask_t sv_flag; 54 char ** sv_argv; 55 56 /* 57 * No such beast? Then bail now. 58 */ 59 if (env_opts == NULL) 60 return; 61 62 /* 63 * Tokenize the string. If there's nothing of interest, we'll bail 64 * here immediately. 65 */ 66 pTL = ao_string_tokenize(env_opts); 67 if (pTL == NULL) 68 return; 69 70 /* 71 * Substitute our $PROGNAME argument list for the real one 72 */ 73 sv_argc = (int)pOpts->origArgCt; 74 sv_argv = pOpts->origArgVect; 75 sv_flag = pOpts->fOptSet; 76 77 /* 78 * We add a bogus pointer to the start of the list. The program name 79 * has already been pulled from "argv", so it won't get dereferenced. 80 * The option scanning code will skip the "program name" at the start 81 * of this list of tokens, so we accommodate this way .... 82 */ 83 { 84 uintptr_t v = (uintptr_t)(pTL->tkn_list); 85 pOpts->origArgVect = VOIDP(v - sizeof(char *)); 86 } 87 pOpts->origArgCt = (unsigned int)pTL->tkn_ct + 1; 88 pOpts->fOptSet &= ~OPTPROC_ERRSTOP; 89 90 pOpts->curOptIdx = 1; 91 pOpts->pzCurOpt = NULL; 92 93 switch (type) { 94 case ENV_IMM: 95 (void)immediate_opts(pOpts); 96 break; 97 98 case ENV_ALL: 99 (void)immediate_opts(pOpts); 100 pOpts->curOptIdx = 1; 101 pOpts->pzCurOpt = NULL; 102 /* FALLTHROUGH */ 103 104 case ENV_NON_IMM: 105 (void)regular_opts(pOpts); 106 } 107 108 /* 109 * Free up the temporary arg vector and restore the original program args. 110 */ 111 free(pTL); 112 pOpts->origArgVect = sv_argv; 113 pOpts->origArgCt = (unsigned int)sv_argc; 114 pOpts->fOptSet = sv_flag; 115 } 116 117 static void 118 do_env_opt(tOptState * os, char * env_name, 119 tOptions * pOpts, teEnvPresetType type) 120 { 121 os->pzOptArg = getenv(env_name); 122 if (os->pzOptArg == NULL) 123 return; 124 125 os->flags = OPTST_PRESET | OPTST_ALLOC_ARG | os->pOD->fOptState; 126 os->optType = TOPT_UNDEFINED; 127 128 if ( (os->pOD->pz_DisablePfx != NULL) 129 && (streqvcmp(os->pzOptArg, os->pOD->pz_DisablePfx) == 0)) { 130 os->flags |= OPTST_DISABLED; 131 os->pzOptArg = NULL; 132 handle_opt(pOpts, os); 133 return; 134 } 135 136 switch (type) { 137 case ENV_IMM: 138 /* 139 * Process only immediate actions 140 */ 141 if (DO_IMMEDIATELY(os->flags)) 142 break; 143 return; 144 145 case ENV_NON_IMM: 146 /* 147 * Process only NON immediate actions 148 */ 149 if (DO_NORMALLY(os->flags) || DO_SECOND_TIME(os->flags)) 150 break; 151 return; 152 153 default: /* process everything */ 154 break; 155 } 156 157 /* 158 * Make sure the option value string is persistent and consistent. 159 * 160 * The interpretation of the option value depends 161 * on the type of value argument the option takes 162 */ 163 if (OPTST_GET_ARGTYPE(os->pOD->fOptState) == OPARG_TYPE_NONE) { 164 /* 165 * Ignore any value. 166 */ 167 os->pzOptArg = NULL; 168 169 } else if (os->pzOptArg[0] == NUL) { 170 /* 171 * If the argument is the empty string and the argument is 172 * optional, then treat it as if the option was not specified. 173 */ 174 if ((os->pOD->fOptState & OPTST_ARG_OPTIONAL) == 0) 175 return; 176 os->pzOptArg = NULL; 177 178 } else { 179 AGDUPSTR(os->pzOptArg, os->pzOptArg, "option argument"); 180 os->flags |= OPTST_ALLOC_ARG; 181 } 182 183 handle_opt(pOpts, os); 184 } 185 186 /* 187 * env_presets - check for preset values from the envrionment 188 * This routine should process in all, immediate or normal modes.... 189 */ 190 LOCAL void 191 env_presets(tOptions * pOpts, teEnvPresetType type) 192 { 193 int ct; 194 tOptState st; 195 char * pzFlagName; 196 size_t spaceLeft; 197 char zEnvName[ AO_NAME_SIZE ]; 198 199 /* 200 * Finally, see if we are to look at the environment 201 * variables for initial values. 202 */ 203 if ((pOpts->fOptSet & OPTPROC_ENVIRON) == 0) 204 return; 205 206 doPrognameEnv(pOpts, type); 207 208 ct = pOpts->presetOptCt; 209 st.pOD = pOpts->pOptDesc; 210 211 pzFlagName = zEnvName 212 + snprintf(zEnvName, sizeof(zEnvName), "%s_", pOpts->pzPROGNAME); 213 spaceLeft = AO_NAME_SIZE - (unsigned long)(pzFlagName - zEnvName) - 1; 214 215 for (;ct-- > 0; st.pOD++) { 216 size_t nln; 217 218 /* 219 * If presetting is disallowed, then skip this entry 220 */ 221 if ( ((st.pOD->fOptState & OPTST_NO_INIT) != 0) 222 || (st.pOD->optEquivIndex != NO_EQUIVALENT) ) 223 continue; 224 225 /* 226 * IF there is no such environment variable, 227 * THEN skip this entry, too. 228 */ 229 nln = strlen(st.pOD->pz_NAME) + 1; 230 if (nln <= spaceLeft) { 231 /* 232 * Set up the option state 233 */ 234 memcpy(pzFlagName, st.pOD->pz_NAME, nln); 235 do_env_opt(&st, zEnvName, pOpts, type); 236 } 237 } 238 239 /* 240 * Special handling for ${PROGNAME_LOAD_OPTS} 241 */ 242 if ( (pOpts->specOptIdx.save_opts != NO_EQUIVALENT) 243 && (pOpts->specOptIdx.save_opts != 0)) { 244 size_t nln; 245 st.pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1; 246 247 if (st.pOD->pz_NAME == NULL) 248 return; 249 250 nln = strlen(st.pOD->pz_NAME) + 1; 251 252 if (nln > spaceLeft) 253 return; 254 255 memcpy(pzFlagName, st.pOD->pz_NAME, nln); 256 do_env_opt(&st, zEnvName, pOpts, type); 257 } 258 } 259 260 /** @} 261 * 262 * Local Variables: 263 * mode: C 264 * c-file-style: "stroustrup" 265 * indent-tabs-mode: nil 266 * End: 267 * end of autoopts/environment.c */ 268