env.c revision 290001
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 = = = */
36static void
37do_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 */
47LOCAL void
48doPrognameEnv(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
117static void
118do_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 */
190LOCAL void
191env_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