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
doPrognameEnv(tOptions * pOpts,teEnvPresetType type)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
do_env_opt(tOptState * os,char * env_name,tOptions * pOpts,teEnvPresetType type)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
env_presets(tOptions * pOpts,teEnvPresetType type)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