diff options
Diffstat (limited to 'src/libfreeswan/optionsfrom.c')
-rw-r--r-- | src/libfreeswan/optionsfrom.c | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/src/libfreeswan/optionsfrom.c b/src/libfreeswan/optionsfrom.c new file mode 100644 index 000000000..d96a3124d --- /dev/null +++ b/src/libfreeswan/optionsfrom.c @@ -0,0 +1,301 @@ +/* + * pick up more options from a file, in the middle of an option scan + * Copyright (C) 1998, 1999 Henry Spencer. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + * License for more details. + * + * RCSID $Id: optionsfrom.c,v 1.1 2004/03/15 20:35:26 as Exp $ + */ +#include "internal.h" +#include "freeswan.h" + +#include <stdio.h> + +#define MAX 100 /* loop-detection limit */ + +/* internal work area */ +struct work { +# define LOTS 1024 + char buf[LOTS]; + char *line; + char *pending; +}; + +static const char *dowork(const char *, int *, char ***, int); +static const char *getanarg(FILE *, struct work *, char **); +static char *getline(FILE *, char *, size_t); + +/* + - optionsfrom - add some options, taken from a file, to argc/argv + * If errsto is non-NULL, does not return in event of error. + */ +const char * /* NULL for success, else string literal */ +optionsfrom(filename, argcp, argvp, optind, errsto) +const char *filename; +int *argcp; /* pointer to argc */ +char ***argvp; /* pointer to argv */ +int optind; /* current optind, number of next argument */ +FILE *errsto; /* where to report errors (NULL means return) */ +{ + const char *e; + static int nuses = 0; + + if (errsto != NULL) { + nuses++; + if (nuses >= MAX) { + fprintf(errsto, + "%s: optionsfrom called %d times, looping?\n", + (*argvp)[0], nuses); + exit(2); + } + } else + nuses = 0; + + e = dowork(filename, argcp, argvp, optind); + if (e != NULL && errsto != NULL) { + fprintf(errsto, "%s: optionsfrom failed: %s\n", (*argvp)[0], e); + exit(2); + } + return e; +} + +/* + - dowork - do all the real work of optionsfrom + * Does not alter the existing arguments, but does relocate and alter + * the argv pointer vector. + */ +static const char * /* NULL for success, else string literal */ +dowork(filename, argcp, argvp, optind) +const char *filename; +int *argcp; /* pointer to argc */ +char ***argvp; /* pointer to argv */ +int optind; /* current optind, number of next argument */ +{ + char **newargv; + char **tmp; + int newargc; + int next; /* place for next argument */ + int room; /* how many more new arguments we can hold */ +# define SOME 10 /* first guess at how many we'll need */ + FILE *f; + int i; + const char *p; + struct work wa; /* for getanarg() */ + + f = fopen(filename, "r"); + if (f == NULL) + return "unable to open file"; + + newargc = *argcp + SOME; + newargv = malloc((newargc+1) * sizeof(char *)); + if (newargv == NULL) + return "unable to allocate memory"; + memcpy(newargv, *argvp, optind * sizeof(char *)); + room = SOME; + next = optind; + + newargv[next] = NULL; + wa.pending = NULL; + while ((p = getanarg(f, &wa, &newargv[next])) == NULL) { + if (room == 0) { + newargc += SOME; + tmp = realloc(newargv, (newargc+1) * sizeof(char *)); + if (tmp == NULL) { + p = "out of space for new argv"; + break; /* NOTE BREAK OUT */ + } + newargv = tmp; + room += SOME; + } + next++; + room--; + } + if (p != NULL && !feof(f)) { /* error of some kind */ + for (i = optind+1; i <= next; i++) + if (newargv[i] != NULL) + free(newargv[i]); + free(newargv); + fclose(f); + return p; + } + + fclose(f); + memcpy(newargv + next, *argvp + optind, + (*argcp+1-optind) * sizeof(char *)); + *argcp += next - optind; + *argvp = newargv; + return NULL; +} + +/* + - getanarg - get a malloced argument from the file + */ +static const char * /* NULL for success, else string literal */ +getanarg(f, w, linep) +FILE *f; +struct work *w; +char **linep; /* where to store pointer if successful */ +{ + size_t len; + char *p; + char *endp; + + while (w->pending == NULL) { /* no pending line */ + if ((w->line = getline(f, w->buf, sizeof(w->buf))) == NULL) + return "error in line read"; /* caller checks EOF */ + if (w->line[0] != '#' && + *(w->line + strspn(w->line, " \t")) != '\0') + w->pending = w->line; + } + + if (w->pending == w->line && w->line[0] != '-') { + /* fresh plain line */ + w->pending = NULL; + p = w->line; + endp = p + strlen(p); + if (*p == '"' && endp > p+1 && *(endp-1) == '"') { + p++; + endp--; + *endp = '\0'; + } + if (w->line == w->buf) { + *linep = malloc(endp - p + 1); + if (*linep == NULL) + return "out of memory for new line"; + strcpy(*linep, p); + } else /* getline already malloced it */ + *linep = p; + return NULL; + } + + /* chip off a piece of a pending line */ + p = w->pending; + p += strspn(p, " \t"); + endp = p + strcspn(p, " \t"); + len = endp - p; + if (*endp != '\0') { + *endp++ = '\0'; + endp += strspn(endp, " \t"); + } + /* endp now points to next real character, or to line-end NUL */ + *linep = malloc(len + 1); + if (*linep == NULL) { + if (w->line != w->buf) + free(w->line); + return "out of memory for new argument"; + } + strcpy(*linep, p); + if (*endp == '\0') { + w->pending = NULL; + if (w->line != w->buf) + free(w->line); + } else + w->pending = endp; + return NULL; +} + +/* + - getline - read a line from the file, trim newline off + */ +static char * /* pointer to line, NULL for eof/error */ +getline(f, buf, bufsize) +FILE *f; +char *buf; /* buffer to use, if convenient */ +size_t bufsize; /* size of buf */ +{ + size_t len; + + if (fgets(buf, bufsize, f) == NULL) + return NULL; + len = strlen(buf); + + if (len < bufsize-1 || buf[bufsize-1] == '\n') { + /* it fit */ + buf[len-1] = '\0'; + return buf; + } + + /* oh crud, buffer overflow */ + /* for now, to hell with it */ + return NULL; +} + + + +#ifdef TEST + +#include <getopt.h> + +char usage[] = "Usage: tester [--foo] [--bar] [--optionsfrom file] arg ..."; +struct option opts[] = { + "foo", 0, NULL, 'f', + "bar", 0, NULL, 'b', + "builtin", 0, NULL, 'B', + "optionsfrom", 1, NULL, '+', + "help", 0, NULL, 'h', + "version", 0, NULL, 'v', + 0, 0, NULL, 0, +}; + +int +main(argc, argv) +int argc; +char *argv[]; +{ + int opt; + extern char *optarg; + extern int optind; + int errflg = 0; + const char *p; + int i; + FILE *errs = NULL; + + while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF) + switch (opt) { + case 'f': + case 'b': + break; + case 'B': + errs = stderr; + break; + case '+': /* optionsfrom */ + p = optionsfrom(optarg, &argc, &argv, optind, errs); + if (p != NULL) { + fprintf(stderr, "%s: optionsfrom error: %s\n", + argv[0], p); + exit(1); + } + break; + case 'h': /* help */ + printf("%s\n", usage); + exit(0); + break; + case 'v': /* version */ + printf("1\n"); + exit(0); + break; + case '?': + default: + errflg = 1; + break; + } + if (errflg) { + fprintf(stderr, "%s\n", usage); + exit(2); + } + + for (i = 1; i < argc; i++) + printf("%d: `%s'\n", i, argv[i]); + exit(0); +} + + +#endif /* TEST */ |