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