refactored optionsfrom as in an object-oriented way using the options_t class. Elimin...
[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) 2007-2008 Andreas Steffen
10 *
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This library is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Library General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
17 *
18 * This library is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
21 * License for more details.
22 *
23 * RCSID $Id$
24 */
25
26 #include <stdio.h>
27 #include <errno.h>
28
29 #include <library.h>
30 #include <debug.h>
31 #include <utils/lexparser.h>
32
33 #include "optionsfrom.h"
34
35 #define MAX_USES 20 /* loop-detection limit */
36 #define MORE_ARGS 10 /* first guess at how many arguments we'll need */
37
38 /*
39 * Defined in header.
40 */
41
42 typedef struct private_options_t private_options_t;
43
44 /**
45 * Private data of a options_t object.
46 */
47 struct private_options_t {
48 /**
49 * Public interface
50 */
51 options_t public;
52
53 /**
54 * reallocated argv array
55 */
56 char **newargv;
57
58 /**
59 * number of free arguments in newargv
60 */
61 int room;
62
63 /**
64 * number of included option files
65 */
66 int nuses;
67
68 /**
69 * allocated space for option files
70 */
71 char *buffers[MAX_USES];
72 };
73
74 /**
75 * Defined in header
76 */
77 bool from(private_options_t *this, char *filename, int *argcp, char **argvp[],
78 int optind)
79 {
80 int newargc;
81 int next; /* place for next argument */
82 char **newargv;
83 size_t bytes;
84 chunk_t src, line, token;
85 bool good = TRUE;
86 int linepos = 0;
87 FILE *fd;
88
89 /* avoid endless loops with recursive --optionsfrom arguments */
90 this->nuses++;
91 if (this->nuses >= MAX_USES)
92 {
93 DBG1("optionsfrom called %d times by \"%s\" - looping?", this->nuses + 1, (*argvp)[0]);
94 return FALSE;
95 }
96
97 fd = fopen(filename, "r");
98 if (fd == NULL)
99 {
100 DBG1("optionsfrom: unable to open file '%s': %s",
101 filename, strerror(errno));
102 return FALSE;
103 }
104
105 /* determine the file size */
106 fseek(fd, 0, SEEK_END);
107 src.len = ftell(fd);
108 rewind(fd);
109
110 /* allocate one byte more just in case of a missing final newline */
111 src.ptr = this->buffers[this->nuses] = malloc(src.len + 1);
112
113 /* read the whole file into a chunk */
114 bytes = fread(src.ptr, 1, src.len, fd);
115 fclose(fd);
116
117 if (this->room)
118 {
119 newargc = *argcp;
120 newargv = malloc((newargc + 1 + this->room) * sizeof(char *));
121 }
122 else
123 {
124 newargc = *argcp + MORE_ARGS;
125 this->room = MORE_ARGS;
126 newargv = malloc((newargc + 1) * sizeof(char *));
127 }
128 memcpy(newargv, *argvp, optind * sizeof(char *));
129 next = optind;
130 newargv[next] = NULL;
131
132 while (fetchline(&src, &line) && good)
133 {
134 linepos++;
135 while (eat_whitespace(&line))
136 {
137 if (*line.ptr == '"'|| *line.ptr == '\'')
138 {
139 char delimiter = *line.ptr;
140
141 line.ptr++;
142 line.len--;
143 if (!extract_token(&token, delimiter, &line))
144 {
145 DBG1("optionsfrom: missing terminator at %s:%d",
146 filename, linepos);
147 good = FALSE;
148 break;
149 }
150 }
151 else
152 {
153 if (!extract_token(&token, ' ', &line))
154 {
155 /* last token in a line */
156 token = line;
157 line.len = 0;
158 }
159 }
160
161 /* do we have to allocate more memory for additional arguments? */
162 if (this->room == 0)
163 {
164 newargc += MORE_ARGS;
165 newargv = realloc(newargv, (newargc + 1) * sizeof(char *));
166 this->room = MORE_ARGS;
167 }
168
169 /* terminate the token by replacing the delimiter with a null character */
170 *(token.ptr + token.len) = '\0';
171
172 /* assign the token to the next argument */
173 newargv[next] = token.ptr;
174 next++;
175 this->room--;
176 }
177 }
178
179 /* assign newargv to argv */
180 if (good)
181 {
182 memcpy(newargv + next, *argvp + optind, (*argcp + 1 - optind) * sizeof(char *));
183 *argcp += next - optind;
184 *argvp = newargv;
185 }
186
187 /* keep a pointer to the latest newargv and free any earlier version */
188 free(this->newargv);
189 this->newargv = newargv;
190
191 return good;
192 }
193
194 /**
195 * Defined in header
196 */
197 void destroy(private_options_t *this)
198 {
199 while (this->nuses >= 0)
200 {
201 free(this->buffers[this->nuses--]);
202 }
203 free(this->newargv);
204 free(this);
205 }
206
207 /*
208 * Defined in header
209 */
210 options_t *options_create(void)
211 {
212 private_options_t *this = malloc_thing(private_options_t);
213
214 /* initialize */
215 this->newargv = NULL;
216 this->room = 0;
217 this->nuses = -1;
218 memset(this->buffers, '\0', MAX_USES);
219
220 /* public functions */
221 this->public.from = (bool (*) (options_t*,char*,int*,char***,int))from;
222 this->public.destroy = (void (*) (options_t*))destroy;
223
224 return &this->public;
225 }