Home | History | Annotate | Line # | Download | only in libopts
      1 /*	$NetBSD: env.c,v 1.6 2024/08/18 20:47:24 christos Exp $	*/
      2 
      3 
      4 /**
      5  * \file environment.c
      6  *
      7  *  This file contains all of the routines that must be linked into
      8  *  an executable to use the generated option processing.  The optional
      9  *  routines are in separately compiled modules so that they will not
     10  *  necessarily be linked in.
     11  *
     12  * @addtogroup autoopts
     13  * @{
     14  */
     15 /*
     16  *  This file is part of AutoOpts, a companion to AutoGen.
     17  *  AutoOpts is free software.
     18  *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
     19  *
     20  *  AutoOpts is available under any one of two licenses.  The license
     21  *  in use must be one of these two and the choice is under the control
     22  *  of the user of the license.
     23  *
     24  *   The GNU Lesser General Public License, version 3 or later
     25  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
     26  *
     27  *   The Modified Berkeley Software Distribution License
     28  *      See the file "COPYING.mbsd"
     29  *
     30  *  These files have the following sha256 sums:
     31  *
     32  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
     33  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
     34  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
     35  */
     36 
     37 /*
     38  *  doPrognameEnv - check for preset values from the ${PROGNAME}
     39  *  environment variable.  This is accomplished by parsing the text into
     40  *  tokens, temporarily replacing the arg vector and calling
     41  *  immediate_opts and/or regular_opts.
     42  */
     43 static void
     44 doPrognameEnv(tOptions * pOpts, teEnvPresetType type)
     45 {
     46     char const *        env_opts = getenv(pOpts->pzPROGNAME);
     47     token_list_t *      pTL;
     48     int                 sv_argc;
     49     proc_state_mask_t   sv_flag;
     50     char **             sv_argv;
     51 
     52     /*
     53      *  No such beast?  Then bail now.
     54      */
     55     if (env_opts == NULL)
     56         return;
     57 
     58     /*
     59      *  Tokenize the string.  If there's nothing of interest, we'll bail
     60      *  here immediately.
     61      */
     62     pTL = ao_string_tokenize(env_opts);
     63     if (pTL == NULL)
     64         return;
     65 
     66     /*
     67      *  Substitute our $PROGNAME argument list for the real one
     68      */
     69     sv_argc = (int)pOpts->origArgCt;
     70     sv_argv = pOpts->origArgVect;
     71     sv_flag = pOpts->fOptSet;
     72 
     73     /*
     74      *  We add a bogus pointer to the start of the list.  The program name
     75      *  has already been pulled from "argv", so it won't get dereferenced.
     76      *  The option scanning code will skip the "program name" at the start
     77      *  of this list of tokens, so we accommodate this way ....
     78      */
     79     {
     80         uintptr_t v = (uintptr_t)(pTL->tkn_list);
     81         pOpts->origArgVect = VOIDP(v - sizeof(char *));
     82     }
     83     pOpts->origArgCt   = (unsigned int)pTL->tkn_ct   + 1;
     84     pOpts->fOptSet    &= ~OPTPROC_ERRSTOP;
     85 
     86     pOpts->curOptIdx   = 1;
     87     pOpts->pzCurOpt    = NULL;
     88 
     89     switch (type) {
     90     case ENV_IMM:
     91         (void)immediate_opts(pOpts);
     92         break;
     93 
     94     case ENV_ALL:
     95         (void)immediate_opts(pOpts);
     96         pOpts->curOptIdx = 1;
     97         pOpts->pzCurOpt  = NULL;
     98         /* FALLTHROUGH */
     99 
    100     case ENV_NON_IMM:
    101         (void)regular_opts(pOpts);
    102     }
    103 
    104     /*
    105      *  Free up the temporary arg vector and restore the original program args.
    106      */
    107     free(pTL);
    108     pOpts->origArgVect = sv_argv;
    109     pOpts->origArgCt   = (unsigned int)sv_argc;
    110     pOpts->fOptSet     = sv_flag;
    111 }
    112 
    113 static void
    114 do_env_opt(tOptState * os, char * env_name,
    115             tOptions * pOpts, teEnvPresetType type)
    116 {
    117     os->pzOptArg = getenv(env_name);
    118     if (os->pzOptArg == NULL)
    119         return;
    120 
    121     os->flags   = OPTST_PRESET | OPTST_ALLOC_ARG | os->pOD->fOptState;
    122     os->optType = TOPT_UNDEFINED;
    123 
    124     if (  (os->pOD->pz_DisablePfx != NULL)
    125        && (streqvcmp(os->pzOptArg, os->pOD->pz_DisablePfx) == 0)) {
    126         os->flags |= OPTST_DISABLED;
    127         os->pzOptArg = NULL;
    128         handle_opt(pOpts, os);
    129         return;
    130     }
    131 
    132     switch (type) {
    133     case ENV_IMM:
    134         /*
    135          *  Process only immediate actions
    136          */
    137         if (DO_IMMEDIATELY(os->flags))
    138             break;
    139         return;
    140 
    141     case ENV_NON_IMM:
    142         /*
    143          *  Process only NON immediate actions
    144          */
    145         if (DO_NORMALLY(os->flags) || DO_SECOND_TIME(os->flags))
    146             break;
    147         return;
    148 
    149     default: /* process everything */
    150         break;
    151     }
    152 
    153     /*
    154      *  Make sure the option value string is persistent and consistent.
    155      *
    156      *  The interpretation of the option value depends
    157      *  on the type of value argument the option takes
    158      */
    159     if (OPTST_GET_ARGTYPE(os->pOD->fOptState) == OPARG_TYPE_NONE) {
    160         /*
    161          *  Ignore any value.
    162          */
    163         os->pzOptArg = NULL;
    164 
    165     } else if (os->pzOptArg[0] == NUL) {
    166         /*
    167          * If the argument is the empty string and the argument is
    168          * optional, then treat it as if the option was not specified.
    169          */
    170         if ((os->pOD->fOptState & OPTST_ARG_OPTIONAL) == 0)
    171             return;
    172         os->pzOptArg = NULL;
    173 
    174     } else {
    175         AGDUPSTR(os->pzOptArg, os->pzOptArg, "option argument");
    176         os->flags |= OPTST_ALLOC_ARG;
    177     }
    178 
    179     handle_opt(pOpts, os);
    180 }
    181 
    182 /*
    183  *  env_presets - check for preset values from the envrionment
    184  *  This routine should process in all, immediate or normal modes....
    185  */
    186 static void
    187 env_presets(tOptions * pOpts, teEnvPresetType type)
    188 {
    189     int        ct;
    190     tOptState  st;
    191     char *     pzFlagName;
    192     size_t     spaceLeft;
    193     char       zEnvName[ AO_NAME_SIZE ];
    194 
    195     /*
    196      *  Finally, see if we are to look at the environment
    197      *  variables for initial values.
    198      */
    199     if ((pOpts->fOptSet & OPTPROC_ENVIRON) == 0)
    200         return;
    201 
    202     doPrognameEnv(pOpts, type);
    203 
    204     ct  = pOpts->presetOptCt;
    205     st.pOD = pOpts->pOptDesc;
    206 
    207     pzFlagName = zEnvName
    208         + snprintf(zEnvName, sizeof(zEnvName), "%s_", pOpts->pzPROGNAME);
    209     spaceLeft = AO_NAME_SIZE - (unsigned long)(pzFlagName - zEnvName) - 1;
    210 
    211     for (;ct-- > 0; st.pOD++) {
    212         size_t nln;
    213 
    214         /*
    215          *  If presetting is disallowed, then skip this entry
    216          */
    217         if (  ((st.pOD->fOptState & OPTST_NO_INIT) != 0)
    218            || (st.pOD->optEquivIndex != NO_EQUIVALENT)  )
    219             continue;
    220 
    221         /*
    222          *  IF there is no such environment variable,
    223          *  THEN skip this entry, too.
    224          */
    225         nln = strlen(st.pOD->pz_NAME) + 1;
    226         if (nln <= spaceLeft) {
    227             /*
    228              *  Set up the option state
    229              */
    230             memcpy(pzFlagName, st.pOD->pz_NAME, nln);
    231             do_env_opt(&st, zEnvName, pOpts, type);
    232         }
    233     }
    234 
    235     /*
    236      *  Special handling for ${PROGNAME_LOAD_OPTS}
    237      */
    238     if (  (pOpts->specOptIdx.save_opts != NO_EQUIVALENT)
    239        && (pOpts->specOptIdx.save_opts != 0)) {
    240         size_t nln;
    241         st.pOD = pOpts->pOptDesc + pOpts->specOptIdx.save_opts + 1;
    242 
    243         if (st.pOD->pz_NAME == NULL)
    244             return;
    245 
    246         nln = strlen(st.pOD->pz_NAME) + 1;
    247 
    248         if (nln > spaceLeft)
    249             return;
    250 
    251         memcpy(pzFlagName, st.pOD->pz_NAME, nln);
    252         do_env_opt(&st, zEnvName, pOpts, type);
    253     }
    254 }
    255 
    256 /** @}
    257  *
    258  * Local Variables:
    259  * mode: C
    260  * c-file-style: "stroustrup"
    261  * indent-tabs-mode: nil
    262  * End:
    263  * end of autoopts/environment.c */
    264