1*eabc0478Schristos /* $NetBSD: env.c,v 1.6 2024/08/18 20:47:24 christos Exp $ */ 28585484eSchristos 38585484eSchristos 48585484eSchristos /** 58585484eSchristos * \file environment.c 68585484eSchristos * 78585484eSchristos * This file contains all of the routines that must be linked into 88585484eSchristos * an executable to use the generated option processing. The optional 98585484eSchristos * routines are in separately compiled modules so that they will not 108585484eSchristos * necessarily be linked in. 118585484eSchristos * 128585484eSchristos * @addtogroup autoopts 138585484eSchristos * @{ 148585484eSchristos */ 158585484eSchristos /* 168585484eSchristos * This file is part of AutoOpts, a companion to AutoGen. 178585484eSchristos * AutoOpts is free software. 18*eabc0478Schristos * AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved 198585484eSchristos * 208585484eSchristos * AutoOpts is available under any one of two licenses. The license 218585484eSchristos * in use must be one of these two and the choice is under the control 228585484eSchristos * of the user of the license. 238585484eSchristos * 248585484eSchristos * The GNU Lesser General Public License, version 3 or later 258585484eSchristos * See the files "COPYING.lgplv3" and "COPYING.gplv3" 268585484eSchristos * 278585484eSchristos * The Modified Berkeley Software Distribution License 288585484eSchristos * See the file "COPYING.mbsd" 298585484eSchristos * 308585484eSchristos * These files have the following sha256 sums: 318585484eSchristos * 328585484eSchristos * 8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95 COPYING.gplv3 338585484eSchristos * 4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b COPYING.lgplv3 348585484eSchristos * 13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239 COPYING.mbsd 358585484eSchristos */ 368585484eSchristos 378585484eSchristos /* 388585484eSchristos * doPrognameEnv - check for preset values from the ${PROGNAME} 398585484eSchristos * environment variable. This is accomplished by parsing the text into 408585484eSchristos * tokens, temporarily replacing the arg vector and calling 418585484eSchristos * immediate_opts and/or regular_opts. 428585484eSchristos */ 43*eabc0478Schristos static void 448585484eSchristos doPrognameEnv(tOptions * pOpts, teEnvPresetType type) 458585484eSchristos { 468585484eSchristos char const * env_opts = getenv(pOpts->pzPROGNAME); 478585484eSchristos token_list_t * pTL; 488585484eSchristos int sv_argc; 498585484eSchristos proc_state_mask_t sv_flag; 508585484eSchristos char ** sv_argv; 518585484eSchristos 528585484eSchristos /* 538585484eSchristos * No such beast? Then bail now. 548585484eSchristos */ 558585484eSchristos if (env_opts == NULL) 568585484eSchristos return; 578585484eSchristos 588585484eSchristos /* 598585484eSchristos * Tokenize the string. If there's nothing of interest, we'll bail 608585484eSchristos * here immediately. 618585484eSchristos */ 628585484eSchristos pTL = ao_string_tokenize(env_opts); 638585484eSchristos if (pTL == NULL) 648585484eSchristos return; 658585484eSchristos 668585484eSchristos /* 678585484eSchristos * Substitute our $PROGNAME argument list for the real one 688585484eSchristos */ 698585484eSchristos sv_argc = (int)pOpts->origArgCt; 708585484eSchristos sv_argv = pOpts->origArgVect; 718585484eSchristos sv_flag = pOpts->fOptSet; 728585484eSchristos 738585484eSchristos /* 748585484eSchristos * We add a bogus pointer to the start of the list. The program name 758585484eSchristos * has already been pulled from "argv", so it won't get dereferenced. 768585484eSchristos * The option scanning code will skip the "program name" at the start 778585484eSchristos * of this list of tokens, so we accommodate this way .... 788585484eSchristos */ 798585484eSchristos { 808585484eSchristos uintptr_t v = (uintptr_t)(pTL->tkn_list); 815d681e99Schristos pOpts->origArgVect = VOIDP(v - sizeof(char *)); 828585484eSchristos } 838585484eSchristos pOpts->origArgCt = (unsigned int)pTL->tkn_ct + 1; 848585484eSchristos pOpts->fOptSet &= ~OPTPROC_ERRSTOP; 858585484eSchristos 868585484eSchristos pOpts->curOptIdx = 1; 878585484eSchristos pOpts->pzCurOpt = NULL; 888585484eSchristos 898585484eSchristos switch (type) { 908585484eSchristos case ENV_IMM: 918585484eSchristos (void)immediate_opts(pOpts); 928585484eSchristos break; 938585484eSchristos 948585484eSchristos case ENV_ALL: 958585484eSchristos (void)immediate_opts(pOpts); 968585484eSchristos pOpts->curOptIdx = 1; 978585484eSchristos pOpts->pzCurOpt = NULL; 988585484eSchristos /* FALLTHROUGH */ 998585484eSchristos 1008585484eSchristos case ENV_NON_IMM: 1018585484eSchristos (void)regular_opts(pOpts); 1028585484eSchristos } 1038585484eSchristos 1048585484eSchristos /* 1058585484eSchristos * Free up the temporary arg vector and restore the original program args. 1068585484eSchristos */ 1078585484eSchristos free(pTL); 1088585484eSchristos pOpts->origArgVect = sv_argv; 1098585484eSchristos pOpts->origArgCt = (unsigned int)sv_argc; 1108585484eSchristos pOpts->fOptSet = sv_flag; 1118585484eSchristos } 1128585484eSchristos 1138585484eSchristos static void 1148585484eSchristos do_env_opt(tOptState * os, char * env_name, 1158585484eSchristos tOptions * pOpts, teEnvPresetType type) 1168585484eSchristos { 1178585484eSchristos os->pzOptArg = getenv(env_name); 1188585484eSchristos if (os->pzOptArg == NULL) 1198585484eSchristos return; 1208585484eSchristos 1218585484eSchristos os->flags = OPTST_PRESET | OPTST_ALLOC_ARG | os->pOD->fOptState; 1228585484eSchristos os->optType = TOPT_UNDEFINED; 1238585484eSchristos 1248585484eSchristos if ( (os->pOD->pz_DisablePfx != NULL) 1258585484eSchristos && (streqvcmp(os->pzOptArg, os->pOD->pz_DisablePfx) == 0)) { 1268585484eSchristos os->flags |= OPTST_DISABLED; 1278585484eSchristos os->pzOptArg = NULL; 1288585484eSchristos handle_opt(pOpts, os); 1298585484eSchristos return; 1308585484eSchristos } 1318585484eSchristos 1328585484eSchristos switch (type) { 1338585484eSchristos case ENV_IMM: 1348585484eSchristos /* 1358585484eSchristos * Process only immediate actions 1368585484eSchristos */ 1378585484eSchristos if (DO_IMMEDIATELY(os->flags)) 1388585484eSchristos break; 1398585484eSchristos return; 1408585484eSchristos 1418585484eSchristos case ENV_NON_IMM: 1428585484eSchristos /* 1438585484eSchristos * Process only NON immediate actions 1448585484eSchristos */ 1458585484eSchristos if (DO_NORMALLY(os->flags) || DO_SECOND_TIME(os->flags)) 1468585484eSchristos break; 1478585484eSchristos return; 1488585484eSchristos 1498585484eSchristos default: /* process everything */ 1508585484eSchristos break; 1518585484eSchristos } 1528585484eSchristos 1538585484eSchristos /* 1548585484eSchristos * Make sure the option value string is persistent and consistent. 1558585484eSchristos * 1568585484eSchristos * The interpretation of the option value depends 1578585484eSchristos * on the type of value argument the option takes 1588585484eSchristos */ 1598585484eSchristos if (OPTST_GET_ARGTYPE(os->pOD->fOptState) == OPARG_TYPE_NONE) { 1608585484eSchristos /* 1618585484eSchristos * Ignore any value. 1628585484eSchristos */ 1638585484eSchristos os->pzOptArg = NULL; 1648585484eSchristos 1658585484eSchristos } else if (os->pzOptArg[0] == NUL) { 1668585484eSchristos /* 1678585484eSchristos * If the argument is the empty string and the argument is 1688585484eSchristos * optional, then treat it as if the option was not specified. 1698585484eSchristos */ 1708585484eSchristos if ((os->pOD->fOptState & OPTST_ARG_OPTIONAL) == 0) 1718585484eSchristos return; 1728585484eSchristos os->pzOptArg = NULL; 1738585484eSchristos 1748585484eSchristos } else { 1758585484eSchristos AGDUPSTR(os->pzOptArg, os->pzOptArg, "option argument"); 1768585484eSchristos os->flags |= OPTST_ALLOC_ARG; 1778585484eSchristos } 1788585484eSchristos 1798585484eSchristos handle_opt(pOpts, os); 1808585484eSchristos } 1818585484eSchristos 1828585484eSchristos /* 1838585484eSchristos * env_presets - check for preset values from the envrionment 1848585484eSchristos * This routine should process in all, immediate or normal modes.... 1858585484eSchristos */ 186*eabc0478Schristos static void 1878585484eSchristos env_presets(tOptions * pOpts, teEnvPresetType type) 1888585484eSchristos { 1898585484eSchristos int ct; 1908585484eSchristos tOptState st; 1918585484eSchristos char * pzFlagName; 1928585484eSchristos size_t spaceLeft; 1938585484eSchristos char zEnvName[ AO_NAME_SIZE ]; 1948585484eSchristos 1958585484eSchristos /* 1968585484eSchristos * Finally, see if we are to look at the environment 1978585484eSchristos * variables for initial values. 1988585484eSchristos */ 1998585484eSchristos if ((pOpts->fOptSet & OPTPROC_ENVIRON) == 0) 2008585484eSchristos return; 2018585484eSchristos 2028585484eSchristos doPrognameEnv(pOpts, type); 2038585484eSchristos 2048585484eSchristos ct = pOpts->presetOptCt; 2058585484eSchristos st.pOD = pOpts->pOptDesc; 2068585484eSchristos 2078585484eSchristos pzFlagName = zEnvName 2088585484eSchristos + snprintf(zEnvName, sizeof(zEnvName), "%s_", pOpts->pzPROGNAME); 2098585484eSchristos spaceLeft = AO_NAME_SIZE - (unsigned long)(pzFlagName - zEnvName) - 1; 2108585484eSchristos 2118585484eSchristos for (;ct-- > 0; st.pOD++) { 2128585484eSchristos size_t nln; 2138585484eSchristos 2148585484eSchristos /* 2158585484eSchristos * If presetting is disallowed, then skip this entry 2168585484eSchristos */ 2178585484eSchristos if ( ((st.pOD->fOptState & OPTST_NO_INIT) != 0) 2188585484eSchristos || (st.pOD->optEquivIndex != NO_EQUIVALENT) ) 2198585484eSchristos continue; 2208585484eSchristos 2218585484eSchristos /* 2228585484eSchristos * IF there is no such environment variable, 2238585484eSchristos * THEN skip this entry, too. 2248585484eSchristos */ 2258585484eSchristos nln = strlen(st.pOD->pz_NAME) + 1; 2268585484eSchristos if (nln <= spaceLeft) { 2278585484eSchristos /* 2288585484eSchristos * Set up the option state 2298585484eSchristos */ 2308585484eSchristos memcpy(pzFlagName, st.pOD->pz_NAME, nln); 2318585484eSchristos do_env_opt(&st, zEnvName, pOpts, type); 2328585484eSchristos } 2338585484eSchristos } 2348585484eSchristos 2358585484eSchristos /* 2368585484eSchristos * Special handling for ${PROGNAME_LOAD_OPTS} 2378585484eSchristos */ 2388585484eSchristos if ( (pOpts->specOptIdx.save_opts != NO_EQUIVALENT) 2398585484eSchristos && (pOpts->specOptIdx.save_opts != 0)) { 2408585484eSchristos size_t nln; 2418585484eSchristos st.pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1; 2428585484eSchristos 2438585484eSchristos if (st.pOD->pz_NAME == NULL) 2448585484eSchristos return; 2458585484eSchristos 2468585484eSchristos nln = strlen(st.pOD->pz_NAME) + 1; 2478585484eSchristos 2488585484eSchristos if (nln > spaceLeft) 2498585484eSchristos return; 2508585484eSchristos 2518585484eSchristos memcpy(pzFlagName, st.pOD->pz_NAME, nln); 2528585484eSchristos do_env_opt(&st, zEnvName, pOpts, type); 2538585484eSchristos } 2548585484eSchristos } 2558585484eSchristos 2568585484eSchristos /** @} 2578585484eSchristos * 2588585484eSchristos * Local Variables: 2598585484eSchristos * mode: C 2608585484eSchristos * c-file-style: "stroustrup" 2618585484eSchristos * indent-tabs-mode: nil 2628585484eSchristos * End: 2638585484eSchristos * end of autoopts/environment.c */ 264