whack uses optionsfrom from libstrongswan
[strongswan.git] / src / libfreeswan / optionsfrom.c
1 /*
2 * pick up more options from a file, in the middle of an option scan
3 * Copyright (C) 1998, 1999 Henry Spencer.
4 *
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Library General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 * License for more details.
14 */
15 #include "internal.h"
16 #include "freeswan.h"
17
18 #include <stdio.h>
19
20 #define MAX 100 /* loop-detection limit */
21
22 /* internal work area */
23 struct work {
24 # define LOTS 1024
25 char buf[LOTS];
26 char *line;
27 char *pending;
28 };
29
30 static const char *dowork(const char *, int *, char ***, int);
31 static const char *getanarg(FILE *, struct work *, char **);
32 static char *getline(FILE *, char *, size_t);
33
34 /*
35 - optionsfrom - add some options, taken from a file, to argc/argv
36 * If errsto is non-NULL, does not return in event of error.
37 */
38 const char * /* NULL for success, else string literal */
39 optionsfrom(filename, argcp, argvp, optind, errsto)
40 const char *filename;
41 int *argcp; /* pointer to argc */
42 char ***argvp; /* pointer to argv */
43 int optind; /* current optind, number of next argument */
44 FILE *errsto; /* where to report errors (NULL means return) */
45 {
46 const char *e;
47 static int nuses = 0;
48
49 if (errsto != NULL) {
50 nuses++;
51 if (nuses >= MAX) {
52 fprintf(errsto,
53 "%s: optionsfrom called %d times, looping?\n",
54 (*argvp)[0], nuses);
55 exit(2);
56 }
57 } else
58 nuses = 0;
59
60 e = dowork(filename, argcp, argvp, optind);
61 if (e != NULL && errsto != NULL) {
62 fprintf(errsto, "%s: optionsfrom failed: %s\n", (*argvp)[0], e);
63 exit(2);
64 }
65 return e;
66 }
67
68 /*
69 - dowork - do all the real work of optionsfrom
70 * Does not alter the existing arguments, but does relocate and alter
71 * the argv pointer vector.
72 */
73 static const char * /* NULL for success, else string literal */
74 dowork(filename, argcp, argvp, optind)
75 const char *filename;
76 int *argcp; /* pointer to argc */
77 char ***argvp; /* pointer to argv */
78 int optind; /* current optind, number of next argument */
79 {
80 char **newargv;
81 char **tmp;
82 int newargc;
83 int next; /* place for next argument */
84 int room; /* how many more new arguments we can hold */
85 # define SOME 10 /* first guess at how many we'll need */
86 FILE *f;
87 int i;
88 const char *p;
89 struct work wa; /* for getanarg() */
90
91 f = fopen(filename, "r");
92 if (f == NULL)
93 return "unable to open file";
94
95 newargc = *argcp + SOME;
96 newargv = malloc((newargc+1) * sizeof(char *));
97 if (newargv == NULL)
98 return "unable to allocate memory";
99 memcpy(newargv, *argvp, optind * sizeof(char *));
100 room = SOME;
101 next = optind;
102
103 newargv[next] = NULL;
104 wa.pending = NULL;
105 while ((p = getanarg(f, &wa, &newargv[next])) == NULL) {
106 if (room == 0) {
107 newargc += SOME;
108 tmp = realloc(newargv, (newargc+1) * sizeof(char *));
109 if (tmp == NULL) {
110 p = "out of space for new argv";
111 break; /* NOTE BREAK OUT */
112 }
113 newargv = tmp;
114 room += SOME;
115 }
116 next++;
117 room--;
118 }
119 if (p != NULL && !feof(f)) { /* error of some kind */
120 for (i = optind+1; i <= next; i++)
121 if (newargv[i] != NULL)
122 free(newargv[i]);
123 free(newargv);
124 fclose(f);
125 return p;
126 }
127
128 fclose(f);
129 memcpy(newargv + next, *argvp + optind,
130 (*argcp+1-optind) * sizeof(char *));
131 *argcp += next - optind;
132 *argvp = newargv;
133 return NULL;
134 }
135
136 /*
137 - getanarg - get a malloced argument from the file
138 */
139 static const char * /* NULL for success, else string literal */
140 getanarg(f, w, linep)
141 FILE *f;
142 struct work *w;
143 char **linep; /* where to store pointer if successful */
144 {
145 size_t len;
146 char *p;
147 char *endp;
148
149 while (w->pending == NULL) { /* no pending line */
150 if ((w->line = getline(f, w->buf, sizeof(w->buf))) == NULL)
151 return "error in line read"; /* caller checks EOF */
152 if (w->line[0] != '#' &&
153 *(w->line + strspn(w->line, " \t")) != '\0')
154 w->pending = w->line;
155 }
156
157 if (w->pending == w->line && w->line[0] != '-') {
158 /* fresh plain line */
159 w->pending = NULL;
160 p = w->line;
161 endp = p + strlen(p);
162 if (*p == '"' && endp > p+1 && *(endp-1) == '"') {
163 p++;
164 endp--;
165 *endp = '\0';
166 }
167 if (w->line == w->buf) {
168 *linep = malloc(endp - p + 1);
169 if (*linep == NULL)
170 return "out of memory for new line";
171 strcpy(*linep, p);
172 } else /* getline already malloced it */
173 *linep = p;
174 return NULL;
175 }
176
177 /* chip off a piece of a pending line */
178 p = w->pending;
179 p += strspn(p, " \t");
180 endp = p + strcspn(p, " \t");
181 len = endp - p;
182 if (*endp != '\0') {
183 *endp++ = '\0';
184 endp += strspn(endp, " \t");
185 }
186 /* endp now points to next real character, or to line-end NUL */
187 *linep = malloc(len + 1);
188 if (*linep == NULL) {
189 if (w->line != w->buf)
190 free(w->line);
191 return "out of memory for new argument";
192 }
193 strcpy(*linep, p);
194 if (*endp == '\0') {
195 w->pending = NULL;
196 if (w->line != w->buf)
197 free(w->line);
198 } else
199 w->pending = endp;
200 return NULL;
201 }
202
203 /*
204 - getline - read a line from the file, trim newline off
205 */
206 static char * /* pointer to line, NULL for eof/error */
207 getline(f, buf, bufsize)
208 FILE *f;
209 char *buf; /* buffer to use, if convenient */
210 size_t bufsize; /* size of buf */
211 {
212 size_t len;
213
214 if (fgets(buf, bufsize, f) == NULL)
215 return NULL;
216 len = strlen(buf);
217
218 if (len < bufsize-1 || buf[bufsize-1] == '\n') {
219 /* it fit */
220 buf[len-1] = '\0';
221 return buf;
222 }
223
224 /* oh crud, buffer overflow */
225 /* for now, to hell with it */
226 return NULL;
227 }
228
229
230
231 #ifdef TEST
232
233 #include <getopt.h>
234
235 char usage[] = "Usage: tester [--foo] [--bar] [--optionsfrom file] arg ...";
236 struct option opts[] = {
237 "foo", 0, NULL, 'f',
238 "bar", 0, NULL, 'b',
239 "builtin", 0, NULL, 'B',
240 "optionsfrom", 1, NULL, '+',
241 "help", 0, NULL, 'h',
242 "version", 0, NULL, 'v',
243 0, 0, NULL, 0,
244 };
245
246 int
247 main(argc, argv)
248 int argc;
249 char *argv[];
250 {
251 int opt;
252 extern char *optarg;
253 extern int optind;
254 int errflg = 0;
255 const char *p;
256 int i;
257 FILE *errs = NULL;
258
259 while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
260 switch (opt) {
261 case 'f':
262 case 'b':
263 break;
264 case 'B':
265 errs = stderr;
266 break;
267 case '+': /* optionsfrom */
268 p = optionsfrom(optarg, &argc, &argv, optind, errs);
269 if (p != NULL) {
270 fprintf(stderr, "%s: optionsfrom error: %s\n",
271 argv[0], p);
272 exit(1);
273 }
274 break;
275 case 'h': /* help */
276 printf("%s\n", usage);
277 exit(0);
278 break;
279 case 'v': /* version */
280 printf("1\n");
281 exit(0);
282 break;
283 case '?':
284 default:
285 errflg = 1;
286 break;
287 }
288 if (errflg) {
289 fprintf(stderr, "%s\n", usage);
290 exit(2);
291 }
292
293 for (i = 1; i < argc; i++)
294 printf("%d: `%s'\n", i, argv[i]);
295 exit(0);
296 }
297
298
299 #endif /* TEST */