xref: /freebsd/contrib/ntp/sntp/libopts/env.c (revision bdd1243d)
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
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
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
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