xref: /netbsd-src/external/bsd/ntp/dist/sntp/libopts/restore.c (revision 7788a0781fe6ff2cce37368b4578a7ade0850cb1)
1 /*	$NetBSD: restore.c,v 1.1.1.2 2012/01/31 21:27:49 kardel Exp $	*/
2 
3 
4 /*
5  * \file restore.c
6  *
7  * Time-stamp:      "2010-08-22 11:04:00 bkorb"
8  *
9  *  This module's routines will save the current option state to memory
10  *  and restore it.  If saved prior to the initial optionProcess call,
11  *  then the initial state will be restored.
12  *
13  *  This file is part of AutoOpts, a companion to AutoGen.
14  *  AutoOpts is free software.
15  *  AutoOpts is Copyright (c) 1992-2011 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 md5sums:
28  *
29  *  43b91e8ca915626ed3818ffb1b71248b pkg/libopts/COPYING.gplv3
30  *  06a1a2e4760c90ea5e1dad8dfaac4d39 pkg/libopts/COPYING.lgplv3
31  *  66a5cedaf62c4b2637025f049f9b826f pkg/libopts/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) + (pOpts->optCt * sizeof(tOptDesc));
103         p = AGALOC(sz, "saved option state");
104         if (p == NULL) {
105             tCC* pzName = pOpts->pzProgName;
106             if (pzName == NULL) {
107                 pzName = pOpts->pzPROGNAME;
108                 if (pzName == NULL)
109                     pzName = zNil;
110             }
111             fprintf(stderr, zCantSave, pzName, sz);
112             exit(EXIT_FAILURE);
113         }
114 
115         pOpts->pSavedState = p;
116     }
117 
118     memcpy(p, pOpts, sizeof(*p));
119     memcpy(p + 1, pOpts->pOptDesc, p->optCt * sizeof(tOptDesc));
120 
121     fixupSavedOptionArgs(pOpts);
122 }
123 
124 
125 /*=export_func optionRestore
126  *
127  * what:  restore option state from memory copy
128  * arg:   tOptions*, pOpts, program options descriptor
129  *
130  * doc:  Copy back the option state from saved memory.
131  *       The allocated memory is left intact, so this routine can be
132  *       called repeatedly without having to call optionSaveState again.
133  *       If you are restoring a state that was saved before the first call
134  *       to optionProcess(3AO), then you may change the contents of the
135  *       argc/argv parameters to optionProcess.
136  *
137  * err:  If you have not called @code{optionSaveState} before, a diagnostic is
138  *       printed to @code{stderr} and exit is called.
139 =*/
140 void
141 optionRestore(tOptions* pOpts)
142 {
143     tOptions* p = (tOptions*)pOpts->pSavedState;
144 
145     if (p == NULL) {
146         tCC* pzName = pOpts->pzProgName;
147         if (pzName == NULL) {
148             pzName = pOpts->pzPROGNAME;
149             if (pzName == NULL)
150                 pzName = zNil;
151         }
152         fprintf(stderr, zNoState, pzName);
153         exit(EXIT_FAILURE);
154     }
155 
156     pOpts->pSavedState = NULL;
157     optionFree(pOpts);
158 
159     memcpy(pOpts, p, sizeof(*p));
160     memcpy(pOpts->pOptDesc, p+1, p->optCt * sizeof(tOptDesc));
161     pOpts->pSavedState = p;
162 
163     fixupSavedOptionArgs(pOpts);
164 }
165 
166 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
167 
168 /*=export_func optionFree
169  *
170  * what:  free allocated option processing memory
171  * arg:   tOptions*, pOpts, program options descriptor
172  *
173  * doc:   AutoOpts sometimes allocates memory and puts pointers to it in the
174  *        option state structures.  This routine deallocates all such memory.
175  *
176  * err:   As long as memory has not been corrupted,
177  *        this routine is always successful.
178 =*/
179 void
180 optionFree(tOptions* pOpts)
181 {
182  free_saved_state:
183     {
184         tOptDesc* p = pOpts->pOptDesc;
185         int ct = pOpts->optCt;
186         do  {
187             if (p->fOptState & OPTST_ALLOC_ARG) {
188                 AGFREE(p->optArg.argString);
189                 p->optArg.argString = NULL;
190                 p->fOptState &= ~OPTST_ALLOC_ARG;
191             }
192 
193             switch (OPTST_GET_ARGTYPE(p->fOptState)) {
194             case OPARG_TYPE_STRING:
195 #ifdef WITH_LIBREGEX
196                 if (  (p->fOptState & OPTST_STACKED)
197                    && (p->optCookie != NULL)) {
198                     p->optArg.argString = ".*";
199                     optionUnstackArg(pOpts, p);
200                 }
201 #else
202                 /* leak memory */;
203 #endif
204                 break;
205 
206             case OPARG_TYPE_HIERARCHY:
207                 if (p->optCookie != NULL)
208                     unload_arg_list(p->optCookie);
209                 break;
210             }
211 
212             p->optCookie = NULL;
213         } while (p++, --ct > 0);
214     }
215     if (pOpts->pSavedState != NULL) {
216         tOptions * p = (tOptions*)pOpts->pSavedState;
217         memcpy(pOpts, p, sizeof(*p));
218         memcpy(pOpts->pOptDesc, p+1, p->optCt * sizeof(tOptDesc));
219         AGFREE(pOpts->pSavedState);
220         pOpts->pSavedState = NULL;
221         goto free_saved_state;
222     }
223 }
224 /*
225  * Local Variables:
226  * mode: C
227  * c-file-style: "stroustrup"
228  * indent-tabs-mode: nil
229  * End:
230  * end of autoopts/restore.c */
231