1/*	$NetBSD: environment.c,v 1.1.1.2 2012/01/31 21:27:53 kardel Exp $	*/
2
3
4/**
5 * \file environment.c
6 *
7 * Time-stamp:      "2011-04-06 09:35:55 bkorb"
8 *
9 *  This file contains all of the routines that must be linked into
10 *  an executable to use the generated option processing.  The optional
11 *  routines are in separately compiled modules so that they will not
12 *  necessarily be linked in.
13 *
14 *  This file is part of AutoOpts, a companion to AutoGen.
15 *  AutoOpts is free software.
16 *  AutoOpts is Copyright (c) 1992-2011 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 md5sums:
29 *
30 *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
31 *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
32 *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/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 *  doImmediateOpts and/or doRegularOpts.
46 */
47LOCAL void
48doPrognameEnv(tOptions* pOpts, teEnvPresetType type)
49{
50    char const*   pczOptStr = getenv(pOpts->pzPROGNAME);
51    token_list_t* pTL;
52    int           sv_argc;
53    tAoUI         sv_flag;
54    char**        sv_argv;
55
56    /*
57     *  No such beast?  Then bail now.
58     */
59    if (pczOptStr == 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(pczOptStr);
67    if (pTL == NULL)
68        return;
69
70    /*
71     *  Substitute our $PROGNAME argument list for the real one
72     */
73    sv_argc = 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    pOpts->origArgVect = (char**)(pTL->tkn_list - 1);
84    pOpts->origArgCt   = pTL->tkn_ct   + 1;
85    pOpts->fOptSet    &= ~OPTPROC_ERRSTOP;
86
87    pOpts->curOptIdx   = 1;
88    pOpts->pzCurOpt    = NULL;
89
90    switch (type) {
91    case ENV_IMM:
92        (void)doImmediateOpts(pOpts);
93        break;
94
95    case ENV_ALL:
96        (void)doImmediateOpts(pOpts);
97        pOpts->curOptIdx = 1;
98        pOpts->pzCurOpt  = NULL;
99        /* FALLTHROUGH */
100
101    case ENV_NON_IMM:
102        (void)doRegularOpts(pOpts);
103    }
104
105    /*
106     *  Free up the temporary arg vector and restore the original program args.
107     */
108    free(pTL);
109    pOpts->origArgVect = sv_argv;
110    pOpts->origArgCt   = sv_argc;
111    pOpts->fOptSet     = sv_flag;
112}
113
114static void
115do_env_opt(tOptState * os, char * env_name,
116            tOptions* pOpts, teEnvPresetType type)
117{
118    os->pzOptArg = getenv(env_name);
119    if (os->pzOptArg == NULL)
120        return;
121
122    os->flags   = OPTST_PRESET | OPTST_ALLOC_ARG | os->pOD->fOptState;
123    os->optType = TOPT_UNDEFINED;
124
125    if (  (os->pOD->pz_DisablePfx != NULL)
126       && (streqvcmp(os->pzOptArg, os->pOD->pz_DisablePfx) == 0)) {
127        os->flags |= OPTST_DISABLED;
128        os->pzOptArg = NULL;
129    }
130
131    switch (type) {
132    case ENV_IMM:
133        /*
134         *  Process only immediate actions
135         */
136        if (DO_IMMEDIATELY(os->flags))
137            break;
138        return;
139
140    case ENV_NON_IMM:
141        /*
142         *  Process only NON immediate actions
143         */
144        if (DO_NORMALLY(os->flags) || DO_SECOND_TIME(os->flags))
145            break;
146        return;
147
148    default: /* process everything */
149        break;
150    }
151
152    /*
153     *  Make sure the option value string is persistent and consistent.
154     *
155     *  The interpretation of the option value depends
156     *  on the type of value argument the option takes
157     */
158    if (OPTST_GET_ARGTYPE(os->pOD->fOptState) == OPARG_TYPE_NONE) {
159        /*
160         *  Ignore any value.
161         */
162        os->pzOptArg = NULL;
163
164    } else if (os->pzOptArg[0] == NUL) {
165        /*
166         * If the argument is the empty string and the argument is
167         * optional, then treat it as if the option was not specified.
168         */
169        if ((os->pOD->fOptState & OPTST_ARG_OPTIONAL) == 0)
170            return;
171        os->pzOptArg = NULL;
172
173    } else {
174        AGDUPSTR(os->pzOptArg, os->pzOptArg, "option argument");
175        os->flags |= OPTST_ALLOC_ARG;
176    }
177
178    handle_opt(pOpts, os);
179}
180
181/*
182 *  doEnvPresets - check for preset values from the envrionment
183 *  This routine should process in all, immediate or normal modes....
184 */
185LOCAL void
186doEnvPresets(tOptions* pOpts, teEnvPresetType type)
187{
188    int        ct;
189    tOptState  st;
190    char*      pzFlagName;
191    size_t     spaceLeft;
192    char       zEnvName[ AO_NAME_SIZE ];
193
194    /*
195     *  Finally, see if we are to look at the environment
196     *  variables for initial values.
197     */
198    if ((pOpts->fOptSet & OPTPROC_ENVIRON) == 0)
199        return;
200
201    doPrognameEnv(pOpts, type);
202
203    ct  = pOpts->presetOptCt;
204    st.pOD = pOpts->pOptDesc;
205
206    pzFlagName = zEnvName
207        + snprintf(zEnvName, sizeof(zEnvName), "%s_", pOpts->pzPROGNAME);
208    spaceLeft = AO_NAME_SIZE - (pzFlagName - zEnvName) - 1;
209
210    for (;ct-- > 0; st.pOD++) {
211        size_t nln;
212
213        /*
214         *  If presetting is disallowed, then skip this entry
215         */
216        if (  ((st.pOD->fOptState & OPTST_NO_INIT) != 0)
217           || (st.pOD->optEquivIndex != NO_EQUIVALENT)  )
218            continue;
219
220        /*
221         *  IF there is no such environment variable,
222         *  THEN skip this entry, too.
223         */
224        nln = strlen(st.pOD->pz_NAME) + 1;
225        if (nln <= spaceLeft) {
226            /*
227             *  Set up the option state
228             */
229            memcpy(pzFlagName, st.pOD->pz_NAME, nln);
230            do_env_opt(&st, zEnvName, pOpts, type);
231        }
232    }
233
234    /*
235     *  Special handling for ${PROGNAME_LOAD_OPTS}
236     */
237    if (  (pOpts->specOptIdx.save_opts != NO_EQUIVALENT)
238       && (pOpts->specOptIdx.save_opts != 0)) {
239        size_t nln;
240        st.pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1;
241
242        if (st.pOD->pz_NAME == NULL)
243            return;
244
245        nln = strlen(st.pOD->pz_NAME) + 1;
246
247        if (nln > spaceLeft)
248            return;
249
250        memcpy(pzFlagName, st.pOD->pz_NAME, nln);
251        do_env_opt(&st, zEnvName, pOpts, type);
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