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