093451f887b3799e850610aa1f31a93d803aa8de
[strongswan.git] / src / libstrongswan / utils / optionsfrom.c
1 /**
2 * @file optionsfrom.c
3 *
4 * @brief read command line options from a file
5 *
6 */
7
8 /*
9 * Copyright (C) 1998, 1999 Henry Spencer.
10 *
11 * This library is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Library General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
15 *
16 * This library is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
19 * License for more details.
20 *
21 */
22
23 #include <stdio.h>
24
25 #include <library.h>
26
27 #include "optionsfrom.h"
28
29 #define MAX_USES 100 /* loop-detection limit */
30 #define SOME_ARGS 10 /* first guess at how many arguments we'll need */
31
32 /**
33 * parse the options from a file
34 * does not alter the existing arguments, but does relocate and alter
35 * the argv pointer vector.
36 */
37 static err_t parse_options_file(const char *filename, int *argcp, char **argvp[], int optind)
38 {
39 char **newargv;
40 int newargc;
41 int next; /* place for next argument */
42 int room; /* how many more new arguments we can hold */
43 size_t bytes;
44 chunk_t chunk, src, line, token;
45 err_t ugh = NULL;
46
47 FILE *fd = fopen(filename, "r");
48
49 if (fd == NULL)
50 {
51 return "unable to open file";
52 }
53
54 /* determine the file size */
55 fseek(fd, 0, SEEK_END);
56 chunk.len = ftell(fd);
57 rewind(fd);
58
59 /* allocate one byte more just in case of a missing final newline */
60 chunk.ptr = malloc(chunk.len + 1);
61
62 /* read the whole file into a chunk */
63 bytes = fread(chunk.ptr, 1, chunk.len, fd);
64 fclose(fd);
65
66 newargc = *argcp + SOME_ARGS;
67 newargv = malloc((newargc + 1) * sizeof(char *));
68 memcpy(newargv, *argvp, optind * sizeof(char *));
69 room = SOME_ARGS;
70 next = optind;
71 newargv[next] = NULL;
72
73 /* we keep the chunk pointer so that we can still free it */
74 src = chunk;
75
76 while (fetchline(&src, &line) && ugh == NULL)
77 {
78 while (eat_whitespace(&line))
79 {
80 if (*line.ptr == '"'|| *line.ptr == '\'')
81 {
82 char delimiter = *line.ptr;
83
84 line.ptr++;
85 line.len--;
86 if (!extract_token(&token, delimiter, &line))
87 {
88 ugh = "missing terminating delimiter";
89 break;
90 }
91 }
92 else
93 {
94 if (!extract_token(&token, ' ', &line))
95 {
96 /* last token in a line */
97 token = line;
98 line.len = 0;
99 }
100 }
101
102 /* do we have to allocate more memory for additional arguments? */
103 if (room == 0)
104 {
105 newargc += SOME_ARGS;
106 newargv = realloc(newargv, (newargc+1) * sizeof(char *));
107 room = SOME_ARGS;
108 }
109
110 /* terminate the token by replacing the delimiter with a null character */
111 *(token.ptr + token.len) = '\0';
112
113 /* assign the token to the next argument */
114 newargv[next] = token.ptr;
115 next++;
116 room--;
117 }
118 }
119
120 if (ugh) /* error of some kind */
121 {
122 free(chunk.ptr);
123 free(newargv);
124 return ugh;
125 }
126
127 memcpy(newargv + next, *argvp + optind, (*argcp + 1 - optind) * sizeof(char *));
128 *argcp += next - optind;
129 *argvp = newargv;
130 return NULL;
131 }
132
133 /*
134 * Defined in header.
135 */
136 err_t optionsfrom(const char *filename, int *argcp, char **argvp[], int optind, FILE *errfile)
137 {
138 static int nuses = 0;
139 err_t ugh = NULL;
140
141 /* avoid endless loops with recursive --optionsfrom arguments */
142 if (errfile != NULL)
143 {
144 nuses++;
145 if (nuses >= MAX_USES)
146 {
147 fprintf(errfile, "%s: optionsfrom called %d times - looping?\n",
148 (*argvp)[0], nuses);
149 exit(2);
150 }
151 }
152 else
153 {
154 nuses = 0;
155 }
156
157 ugh = parse_options_file(filename, argcp, argvp, optind);
158
159 if (ugh != NULL && errfile != NULL)
160 {
161 fprintf(errfile, "%s: optionsfrom failed: %s\n", (*argvp)[0], ugh);
162 exit(2);
163 }
164 return ugh;
165 }