added all required includes
[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 #include <utils/lexparser.h>
27
28 #include "optionsfrom.h"
29
30 #define MAX_USES 100 /* loop-detection limit */
31 #define SOME_ARGS 10 /* first guess at how many arguments we'll need */
32
33 /**
34 * parse the options from a file
35 * does not alter the existing arguments, but does relocate and alter
36 * the argv pointer vector.
37 */
38 static err_t parse_options_file(const char *filename, int *argcp, char **argvp[], int optind)
39 {
40 char **newargv;
41 int newargc;
42 int next; /* place for next argument */
43 int room; /* how many more new arguments we can hold */
44 size_t bytes;
45 chunk_t chunk, src, line, token;
46 err_t ugh = NULL;
47
48 FILE *fd = fopen(filename, "r");
49
50 if (fd == NULL)
51 {
52 return "unable to open file";
53 }
54
55 /* determine the file size */
56 fseek(fd, 0, SEEK_END);
57 chunk.len = ftell(fd);
58 rewind(fd);
59
60 /* allocate one byte more just in case of a missing final newline */
61 chunk.ptr = malloc(chunk.len + 1);
62
63 /* read the whole file into a chunk */
64 bytes = fread(chunk.ptr, 1, chunk.len, fd);
65 fclose(fd);
66
67 newargc = *argcp + SOME_ARGS;
68 newargv = malloc((newargc + 1) * sizeof(char *));
69 memcpy(newargv, *argvp, optind * sizeof(char *));
70 room = SOME_ARGS;
71 next = optind;
72 newargv[next] = NULL;
73
74 /* we keep the chunk pointer so that we can still free it */
75 src = chunk;
76
77 while (fetchline(&src, &line) && ugh == NULL)
78 {
79 while (eat_whitespace(&line))
80 {
81 if (*line.ptr == '"'|| *line.ptr == '\'')
82 {
83 char delimiter = *line.ptr;
84
85 line.ptr++;
86 line.len--;
87 if (!extract_token(&token, delimiter, &line))
88 {
89 ugh = "missing terminating delimiter";
90 break;
91 }
92 }
93 else
94 {
95 if (!extract_token(&token, ' ', &line))
96 {
97 /* last token in a line */
98 token = line;
99 line.len = 0;
100 }
101 }
102
103 /* do we have to allocate more memory for additional arguments? */
104 if (room == 0)
105 {
106 newargc += SOME_ARGS;
107 newargv = realloc(newargv, (newargc+1) * sizeof(char *));
108 room = SOME_ARGS;
109 }
110
111 /* terminate the token by replacing the delimiter with a null character */
112 *(token.ptr + token.len) = '\0';
113
114 /* assign the token to the next argument */
115 newargv[next] = token.ptr;
116 next++;
117 room--;
118 }
119 }
120
121 if (ugh) /* error of some kind */
122 {
123 free(chunk.ptr);
124 free(newargv);
125 return ugh;
126 }
127
128 memcpy(newargv + next, *argvp + optind, (*argcp + 1 - optind) * sizeof(char *));
129 *argcp += next - optind;
130 *argvp = newargv;
131 return NULL;
132 }
133
134 /*
135 * Defined in header.
136 */
137 err_t optionsfrom(const char *filename, int *argcp, char **argvp[], int optind, FILE *errfile)
138 {
139 static int nuses = 0;
140 err_t ugh = NULL;
141
142 /* avoid endless loops with recursive --optionsfrom arguments */
143 if (errfile != NULL)
144 {
145 nuses++;
146 if (nuses >= MAX_USES)
147 {
148 fprintf(errfile, "%s: optionsfrom called %d times - looping?\n",
149 (*argvp)[0], nuses);
150 exit(2);
151 }
152 }
153 else
154 {
155 nuses = 0;
156 }
157
158 ugh = parse_options_file(filename, argcp, argvp, optind);
159
160 if (ugh != NULL && errfile != NULL)
161 {
162 fprintf(errfile, "%s: optionsfrom failed: %s\n", (*argvp)[0], ugh);
163 exit(2);
164 }
165 return ugh;
166 }