Home | History | Annotate | Line # | Download | only in libopts
      1 /*	$NetBSD: restore.c,v 1.6 2024/08/18 20:47:25 christos Exp $	*/
      2 
      3 
      4 /*
      5  * \file restore.c
      6  *
      7  *  This module's routines will save the current option state to memory
      8  *  and restore it.  If saved prior to the initial optionProcess call,
      9  *  then the initial state will be restored.
     10  *
     11  * @addtogroup autoopts
     12  * @{
     13  */
     14 /*
     15  *  This file is part of AutoOpts, a companion to AutoGen.
     16  *  AutoOpts is free software.
     17  *  AutoOpts is Copyright (C) 1992-2018 by Bruce Korb - all rights reserved
     18  *
     19  *  AutoOpts is available under any one of two licenses.  The license
     20  *  in use must be one of these two and the choice is under the control
     21  *  of the user of the license.
     22  *
     23  *   The GNU Lesser General Public License, version 3 or later
     24  *      See the files "COPYING.lgplv3" and "COPYING.gplv3"
     25  *
     26  *   The Modified Berkeley Software Distribution License
     27  *      See the file "COPYING.mbsd"
     28  *
     29  *  These files have the following sha256 sums:
     30  *
     31  *  8584710e9b04216a394078dc156b781d0b47e1729104d666658aecef8ee32e95  COPYING.gplv3
     32  *  4379e7444a0e2ce2b12dd6f5a52a27a4d02d39d247901d3285c88cf0d37f477b  COPYING.lgplv3
     33  *  13aa749a5b0a454917a944ed8fffc530b784f5ead522b1aacaf4ec8aa55a6239  COPYING.mbsd
     34  */
     35 
     36 /*
     37  *  optionFixupSavedOpts  Really, it just wipes out option state for
     38  *  options that are troublesome to copy.  viz., stacked strings and
     39  *  hierarcicaly valued option args.  We do duplicate string args that
     40  *  have been marked as allocated though.
     41  */
     42 static void
     43 fixupSavedOptionArgs(tOptions * pOpts)
     44 {
     45     tOptions * p   = pOpts->pSavedState;
     46     tOptDesc * pOD = pOpts->pOptDesc;
     47     int        ct  = pOpts->optCt;
     48 
     49     /*
     50      *  Make sure that allocated stuff is only referenced in the
     51      *  archived copy of the data.
     52      */
     53     for (; ct-- > 0; pOD++)  {
     54         switch (OPTST_GET_ARGTYPE(pOD->fOptState)) {
     55         case OPARG_TYPE_STRING:
     56             if (pOD->fOptState & OPTST_STACKED) {
     57                 tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc);
     58                 q->optCookie = NULL;
     59             }
     60             if (pOD->fOptState & OPTST_ALLOC_ARG) {
     61                 tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc);
     62                 AGDUPSTR(q->optArg.argString, pOD->optArg.argString, "arg");
     63             }
     64             break;
     65 
     66         case OPARG_TYPE_HIERARCHY:
     67         {
     68             tOptDesc * q = p->pOptDesc + (pOD - pOpts->pOptDesc);
     69             q->optCookie = NULL;
     70         }
     71         }
     72     }
     73 }
     74 
     75 /*=export_func optionSaveState
     76  *
     77  * what:  saves the option state to memory
     78  * arg:   tOptions *, pOpts, program options descriptor
     79  *
     80  * doc:
     81  *
     82  *  This routine will allocate enough memory to save the current option
     83  *  processing state.  If this routine has been called before, that memory
     84  *  will be reused.  You may only save one copy of the option state.  This
     85  *  routine may be called before optionProcess(3AO).  If you do call it
     86  *  before the first call to optionProcess, then you may also change the
     87  *  contents of argc/argv after you call optionRestore(3AO)
     88  *
     89  *  In fact, more strongly put: it is safest to only use this function
     90  *  before having processed any options.  In particular, the saving and
     91  *  restoring of stacked string arguments and hierarchical values is
     92  *  disabled.  The values are not saved.
     93  *
     94  * err:   If it fails to allocate the memory,
     95  *        it will print a message to stderr and exit.
     96  *        Otherwise, it will always succeed.
     97 =*/
     98 void
     99 optionSaveState(tOptions * pOpts)
    100 {
    101     tOptions * p = (tOptions *)pOpts->pSavedState;
    102 
    103     if (p == NULL) {
    104         size_t sz = sizeof(*pOpts)
    105             + ((size_t)pOpts->optCt * sizeof(tOptDesc));
    106         p = AGALOC(sz, "saved option state");
    107 
    108         pOpts->pSavedState = p;
    109     }
    110 
    111     memcpy(p, pOpts, sizeof(*p));
    112     memcpy(p + 1, pOpts->pOptDesc, (size_t)p->optCt * sizeof(tOptDesc));
    113 
    114     fixupSavedOptionArgs(pOpts);
    115 }
    116 
    117 
    118 /*=export_func optionRestore
    119  *
    120  * what:  restore option state from memory copy
    121  * arg:   tOptions *, pOpts, program options descriptor
    122  *
    123  * doc:  Copy back the option state from saved memory.
    124  *       The allocated memory is left intact, so this routine can be
    125  *       called repeatedly without having to call optionSaveState again.
    126  *       If you are restoring a state that was saved before the first call
    127  *       to optionProcess(3AO), then you may change the contents of the
    128  *       argc/argv parameters to optionProcess.
    129  *
    130  * err:  If you have not called @code{optionSaveState} before, a diagnostic is
    131  *       printed to @code{stderr} and exit is called.
    132 =*/
    133 void
    134 optionRestore(tOptions * pOpts)
    135 {
    136     tOptions * p = (tOptions *)pOpts->pSavedState;
    137 
    138     if (p == NULL) {
    139         char const * pzName = pOpts->pzProgName;
    140         if (pzName == NULL) {
    141             pzName = pOpts->pzPROGNAME;
    142             if (pzName == NULL)
    143                 pzName = zNil;
    144         }
    145         fprintf(stderr, zNoState, pzName);
    146         option_exits(EXIT_FAILURE);
    147     }
    148 
    149     pOpts->pSavedState = NULL;
    150     optionFree(pOpts);
    151 
    152     memcpy(pOpts, p, sizeof(*p));
    153     memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc));
    154     pOpts->pSavedState = p;
    155 
    156     fixupSavedOptionArgs(pOpts);
    157 }
    158 
    159 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
    160 
    161 /*=export_func optionFree
    162  *
    163  * what:  free allocated option processing memory
    164  * arg:   tOptions *, pOpts, program options descriptor
    165  *
    166  * doc:   AutoOpts sometimes allocates memory and puts pointers to it in the
    167  *        option state structures.  This routine deallocates all such memory.
    168  *
    169  * err:   As long as memory has not been corrupted,
    170  *        this routine is always successful.
    171 =*/
    172 void
    173 optionFree(tOptions * pOpts)
    174 {
    175  free_saved_state:
    176     {
    177         tOptDesc * p = pOpts->pOptDesc;
    178         int ct = pOpts->optCt;
    179         do  {
    180             if (p->fOptState & OPTST_ALLOC_ARG) {
    181                 AGFREE(p->optArg.argString);
    182                 p->optArg.argString = NULL;
    183                 p->fOptState &= ~OPTST_ALLOC_ARG;
    184             }
    185 
    186             switch (OPTST_GET_ARGTYPE(p->fOptState)) {
    187             case OPARG_TYPE_STRING:
    188 #ifdef WITH_LIBREGEX
    189                 if (  (p->fOptState & OPTST_STACKED)
    190                    && (p->optCookie != NULL)) {
    191                     p->optArg.argString = ".*";
    192                     optionUnstackArg(pOpts, p);
    193                 }
    194 #else
    195                 /* leak memory */;
    196 #endif
    197                 break;
    198 
    199             case OPARG_TYPE_HIERARCHY:
    200                 if (p->optCookie != NULL)
    201                     unload_arg_list(p->optCookie);
    202                 break;
    203             }
    204 
    205             p->optCookie = NULL;
    206         } while (p++, --ct > 0);
    207     }
    208     if (pOpts->pSavedState != NULL) {
    209         tOptions * p = (tOptions *)pOpts->pSavedState;
    210         memcpy(pOpts, p, sizeof(*p));
    211         memcpy(pOpts->pOptDesc, p+1, (size_t)p->optCt * sizeof(tOptDesc));
    212         AGFREE(pOpts->pSavedState);
    213         pOpts->pSavedState = NULL;
    214         goto free_saved_state;
    215     }
    216 }
    217 
    218 /** @}
    219  *
    220  * Local Variables:
    221  * mode: C
    222  * c-file-style: "stroustrup"
    223  * indent-tabs-mode: nil
    224  * End:
    225  * end of autoopts/restore.c */
    226