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