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