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