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