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 */
41static void
42doPrognameEnv(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
111static void
112do_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 */
184static void
185env_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