Home | History | Annotate | Line # | Download | only in libopts
      1 /*	$NetBSD: init.c,v 1.10 2024/08/18 20:47:24 christos Exp $	*/
      2 
      3 /**
      4  * \file initialize.c
      5  *
      6  *  initialize the libopts data structures.
      7  *
      8  * @addtogroup autoopts
      9  * @{
     10  */
     11 /*
     12  *  This file is part of AutoOpts, a companion to AutoGen.
     13  *  AutoOpts is free software.
     14  *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
     15  *
     16  *  AutoOpts is available under any one of two licenses.  The license
     17  *  in use must be one of these two and the choice is under the control
     18  *  of the user of the license.
     19  *
     20  *   The GNU Lesser General Public License, version 3 or later
     21  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
     22  *
     23  *   The Modified Berkeley Software Distribution License
     24  *      See the file "COPYING.mbsd"
     25  *
     26  *  These files have the following sha256 sums:
     27  *
     28  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
     29  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
     30  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
     31  */
     32 
     33 /**
     34  *  Make sure the option descriptor is there and that we understand it.
     35  *  This should be called from any user entry point where one needs to
     36  *  worry about validity.  (Some entry points are free to assume that
     37  *  the call is not the first to the library and, thus, that this has
     38  *  already been called.)
     39  *
     40  *  Upon successful completion, pzProgName and pzProgPath are set.
     41  *
     42  *  @param[in,out] opts   program options descriptor
     43  *  @param[in]     pname  name of program, from argv[]
     44  *  @returns SUCCESS or FAILURE
     45  */
     46 static tSuccess
     47 validate_struct(tOptions * opts, char const * pname)
     48 {
     49     if (opts == NULL) {
     50         fputs(zno_opt_arg, stderr);
     51         return FAILURE;
     52     }
     53     print_exit = ((opts->fOptSet & OPTPROC_SHELL_OUTPUT) != 0);
     54 
     55     /*
     56      *  IF the client has enabled translation and the translation procedure
     57      *  is available, then go do it.
     58      */
     59     if (  ((opts->fOptSet & OPTPROC_TRANSLATE) != 0)
     60        && (opts->pTransProc != NULL)
     61        && (option_xlateable_txt.field_ct != 0) ) {
     62         /*
     63          *  If option names are not to be translated at all, then do not do
     64          *  it for configuration parsing either.  (That is the bit that really
     65          *  gets tested anyway.)
     66          */
     67         if ((opts->fOptSet & OPTPROC_NO_XLAT_MASK) == OPTPROC_NXLAT_OPT)
     68             opts->fOptSet |= OPTPROC_NXLAT_OPT_CFG;
     69         opts->pTransProc();
     70     }
     71 
     72     /*
     73      *  IF the struct version is not the current, and also
     74      *     either too large (?!) or too small,
     75      *  THEN emit error message and fail-exit
     76      */
     77     if (  ( opts->structVersion  != OPTIONS_STRUCT_VERSION  )
     78        && (  (opts->structVersion > OPTIONS_STRUCT_VERSION  )
     79           || (opts->structVersion < OPTIONS_MINIMUM_VERSION )
     80        )  )  {
     81         fprintf(stderr, zwrong_ver, pname, NUM_TO_VER(opts->structVersion));
     82         if (opts->structVersion > OPTIONS_STRUCT_VERSION )
     83             fputs(ztoo_new, stderr);
     84         else
     85             fputs(ztoo_old, stderr);
     86 
     87         fwrite(ao_ver_string, sizeof(ao_ver_string) - 1, 1, stderr);
     88         return FAILURE;
     89     }
     90 
     91     /*
     92      *  If the program name hasn't been set, then set the name and the path
     93      *  and the set of equivalent characters.
     94      */
     95     if (opts->pzProgName == NULL) {
     96         char const *  pz = strrchr(pname, DIRCH);
     97         char const ** pp =
     98             (char const **)__UNCONST(&(opts->pzProgName));
     99 
    100         if (pz != NULL)
    101             *pp = pz+1;
    102         else
    103             *pp = pname;
    104 
    105         pz = pathfind(getenv("PATH"), pname, "rx");
    106         if (pz != NULL)
    107             pname = VOIDP(pz);
    108 
    109         pp  = (char const **)VOIDP(&(opts->pzProgPath));
    110         *pp = pname;
    111 
    112         /*
    113          *  when comparing long names, these are equivalent
    114          */
    115         strequate(zSepChars);
    116     }
    117 
    118     return SUCCESS;
    119 }
    120 
    121 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    122  *
    123  *  DO PRESETS
    124  *
    125  *  The next several routines do the immediate action pass on the command
    126  *  line options, then the environment variables, then the config files in
    127  *  reverse order.  Once done with that, the order is reversed and all
    128  *  the config files and environment variables are processed again, this
    129  *  time only processing the non-immediate action options.  do_presets()
    130  *  will then return for optionProcess() to do the final pass on the command
    131  *  line arguments.
    132  */
    133 
    134 /**
    135  *  scan the command line for immediate action options.
    136  *  This is only called the first time through.
    137  *  While this procedure is active, the OPTPROC_IMMEDIATE is true.
    138  *
    139  *  @param pOpts   program options descriptor
    140  *  @returns SUCCESS or FAILURE
    141  */
    142 static tSuccess
    143 immediate_opts(tOptions * opts)
    144 {
    145     tSuccess  res;
    146 
    147     opts->fOptSet  |= OPTPROC_IMMEDIATE;
    148     opts->curOptIdx = 1;     /* start by skipping program name */
    149     opts->pzCurOpt  = NULL;
    150 
    151     /*
    152      *  Examine all the options from the start.  We process any options that
    153      *  are marked for immediate processing.
    154      */
    155     for (;;) {
    156         tOptState opt_st = OPTSTATE_INITIALIZER(PRESET);
    157 
    158         res = next_opt(opts, &opt_st);
    159         switch (res) {
    160         case FAILURE: goto   failed_option;
    161         case PROBLEM: res = SUCCESS; goto leave;
    162         case SUCCESS: break;
    163         }
    164 
    165         /*
    166          *  IF this is an immediate-attribute option, then do it.
    167          */
    168         if (! DO_IMMEDIATELY(opt_st.flags))
    169             continue;
    170 
    171         if (! SUCCESSFUL(handle_opt(opts, &opt_st)))
    172             break;
    173     } failed_option:;
    174 
    175     if ((opts->fOptSet & OPTPROC_ERRSTOP) != 0)
    176         (*opts->pUsageProc)(opts, EXIT_FAILURE);
    177 
    178  leave:
    179 
    180     opts->fOptSet &= ~OPTPROC_IMMEDIATE;
    181     return res;
    182 }
    183 
    184 /**
    185  *  check for preset values from a config files or envrionment variables
    186  *
    187  * @param[in,out] opts  the structure with the option names to check
    188  */
    189 static tSuccess
    190 do_presets(tOptions * opts)
    191 {
    192     tOptDesc * od = NULL;
    193 
    194     if (! SUCCESSFUL(immediate_opts(opts)))
    195         return FAILURE;
    196 
    197     /*
    198      *  IF this option set has a --save-opts option, then it also
    199      *  has a --load-opts option.  See if a command line option has disabled
    200      *  option presetting.
    201      */
    202     if (  (opts->specOptIdx.save_opts != NO_EQUIVALENT)
    203        && (opts->specOptIdx.save_opts != 0)) {
    204         od = opts->pOptDesc + opts->specOptIdx.save_opts + 1;
    205         if (DISABLED_OPT(od))
    206             return SUCCESS;
    207     }
    208 
    209     /*
    210      *  Until we return from this procedure, disable non-presettable opts
    211      */
    212     opts->fOptSet |= OPTPROC_PRESETTING;
    213     /*
    214      *  IF there are no config files,
    215      *  THEN do any environment presets and leave.
    216      */
    217     if (opts->papzHomeList == NULL) {
    218         env_presets(opts, ENV_ALL);
    219     }
    220     else {
    221         env_presets(opts, ENV_IMM);
    222 
    223         /*
    224          *  Check to see if environment variables have disabled presetting.
    225          */
    226         if ((od != NULL) && ! DISABLED_OPT(od))
    227             intern_file_load(opts);
    228 
    229         /*
    230          *  ${PROGRAM_LOAD_OPTS} value of "no" cannot disable other environment
    231          *  variable options.  Only the loading of .rc files.
    232          */
    233         env_presets(opts, ENV_NON_IMM);
    234     }
    235     opts->fOptSet &= ~OPTPROC_PRESETTING;
    236 
    237     return SUCCESS;
    238 }
    239 
    240 /**
    241  * AutoOpts initialization
    242  *
    243  * @param[in,out] opts  the structure to initialize
    244  * @param[in]     a_ct  program argument count
    245  * @param[in]     a_v   program argument vector
    246  */
    247 static bool
    248 ao_initialize(tOptions * opts, int a_ct, char ** a_v)
    249 {
    250     if ((opts->fOptSet & OPTPROC_INITDONE) != 0)
    251         return true;
    252 
    253     opts->origArgCt   = (unsigned int)a_ct;
    254     opts->origArgVect = a_v;
    255     opts->fOptSet    |= OPTPROC_INITDONE;
    256 
    257     if (HAS_pzPkgDataDir(opts))
    258         program_pkgdatadir = opts->pzPkgDataDir;
    259 
    260     if (! SUCCESSFUL(do_presets(opts)))
    261         return false;
    262 
    263     /*
    264      *  IF option name conversion was suppressed but it is not suppressed
    265      *  for the command line, then it's time to translate option names.
    266      *  Usage text will not get retranslated.
    267      */
    268     if (  ((opts->fOptSet & OPTPROC_TRANSLATE) != 0)
    269        && (opts->pTransProc != NULL)
    270        && ((opts->fOptSet & OPTPROC_NO_XLAT_MASK) == OPTPROC_NXLAT_OPT_CFG)
    271        )  {
    272         opts->fOptSet &= ~OPTPROC_NXLAT_OPT_CFG;
    273         (*opts->pTransProc)();
    274     }
    275 
    276     if ((opts->fOptSet & OPTPROC_REORDER) != 0)
    277         optionSort(opts);
    278 
    279     opts->curOptIdx   = 1;
    280     opts->pzCurOpt    = NULL;
    281     return true;
    282 }
    283 
    284 /** @}
    285  *
    286  * Local Variables:
    287  * mode: C
    288  * c-file-style: "stroustrup"
    289  * indent-tabs-mode: nil
    290  * End:
    291  * end of autoopts/initialize.c */
    292