xref: /netbsd-src/external/bsd/ntp/dist/sntp/libopts/restore.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: restore.c,v 1.4 2016/01/08 21:35:41 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-2015 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