OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / lib / 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.4 1999/04/10 23:24:21 henry 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 *my_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 = my_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                  /* my_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  - my_getline - read a line from the file, trim newline off
207  */
208 static char *                   /* pointer to line, NULL for eof/error */
209 my_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 */