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