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