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
fixupSavedOptionArgs(tOptions * pOpts)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
optionSaveState(tOptions * pOpts)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
optionRestore(tOptions * pOpts)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
optionFree(tOptions * pOpts)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