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