1 | /* |
2 | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
5 | * |
6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | /* |
10 | * @f monet_options |
11 | * @a N.J. Nes |
12 | * @* A simple option handling library |
13 | * @T |
14 | * The monet server and clients make use of command line options and a (possibly) |
15 | * shared config file. With this library a set (represented by set,setlen) of |
16 | * options is created. An option is stored as name and value strings with a |
17 | * special flag indicating the origin of the options, (builtin, system config |
18 | * file, special config file or command line option). |
19 | * |
20 | */ |
21 | #include "monetdb_config.h" |
22 | #include "monet_options.h" |
23 | #ifndef HAVE_GETOPT_LONG |
24 | # include "monet_getopt.h" |
25 | #else |
26 | # ifdef HAVE_GETOPT_H |
27 | # include "getopt.h" |
28 | # endif |
29 | #endif |
30 | #include <string.h> |
31 | #include <ctype.h> |
32 | |
33 | #ifdef HAVE_UNISTD_H |
34 | #include <unistd.h> |
35 | #endif |
36 | |
37 | #ifndef HAVE_GETOPT_LONG |
38 | # include "getopt.c" |
39 | # include "getopt1.c" |
40 | #endif |
41 | |
42 | #ifdef NATIVE_WIN32 |
43 | #define getpid _getpid |
44 | #endif |
45 | |
46 | /* these two are used of the set parameter passed into functions is NULL */ |
47 | static int default_setlen = 0; |
48 | static opt *default_set = NULL; |
49 | |
50 | static int |
51 | mo_default_set(opt **Set, int setlen) |
52 | { |
53 | if (*Set == NULL) { |
54 | if (default_set == NULL) { |
55 | default_setlen = mo_builtin_settings(&default_set); |
56 | default_setlen = mo_system_config(&default_set, default_setlen); |
57 | } |
58 | *Set = default_set; |
59 | setlen = default_setlen; |
60 | } |
61 | return setlen; |
62 | } |
63 | |
64 | void |
65 | mo_print_options(opt *set, int setlen) |
66 | { |
67 | int i = 0; |
68 | |
69 | setlen = mo_default_set(&set, setlen); |
70 | for (i = 0; i < setlen; i++) { |
71 | if (set[i].kind == opt_builtin) { |
72 | fprintf(stderr, "# builtin opt \t%s = %s\n" , set[i].name, set[i].value); |
73 | } |
74 | } |
75 | for (i = 0; i < setlen; i++) { |
76 | if (set[i].kind == opt_config) { |
77 | fprintf(stderr, "# config opt \t%s = %s\n" , set[i].name, set[i].value); |
78 | } |
79 | } |
80 | for (i = 0; i < setlen; i++) { |
81 | if (set[i].kind == opt_cmdline) { |
82 | fprintf(stderr, "# cmdline opt \t%s = %s\n" , set[i].name, set[i].value); |
83 | } |
84 | } |
85 | } |
86 | |
87 | |
88 | char * |
89 | mo_find_option(opt *set, int setlen, const char *name) |
90 | { |
91 | opt *o = NULL; |
92 | int i; |
93 | |
94 | setlen = mo_default_set(&set, setlen); |
95 | for (i = 0; i < setlen; i++) { |
96 | if (strcmp(set[i].name, name) == 0) |
97 | if (!o || o->kind < set[i].kind) |
98 | o = set + i; |
99 | } |
100 | if (o) |
101 | return o->value; |
102 | return NULL; |
103 | } |
104 | |
105 | static int |
106 | mo_config_file(opt **Set, int setlen, char *file) |
107 | { |
108 | char buf[BUFSIZ]; |
109 | FILE *fd = NULL; |
110 | opt *set; |
111 | |
112 | if (Set == NULL) { |
113 | if (default_set == NULL) { |
114 | set = NULL; |
115 | setlen = mo_default_set(&set, 0); |
116 | } else |
117 | setlen = default_setlen; |
118 | Set = &default_set; |
119 | } |
120 | set = *Set; |
121 | fd = fopen(file, "r" ); |
122 | if (fd == NULL) { |
123 | fprintf(stderr, "Could not open file %s\n" , file); |
124 | return setlen; |
125 | } |
126 | while (fgets(buf, BUFSIZ, fd) != NULL) { |
127 | char *s, *t, *val; |
128 | int quote; |
129 | |
130 | for (s = buf; *s && isspace((unsigned char) *s); s++) |
131 | ; |
132 | if (*s == '#') |
133 | continue; /* commentary */ |
134 | if (*s == 0) |
135 | continue; /* empty line */ |
136 | |
137 | val = strchr(s, '='); |
138 | if (val == NULL) { |
139 | fprintf(stderr, "mo_config_file: syntax error in %s at %s\n" , file, s); |
140 | fclose(fd); |
141 | exit(1); |
142 | } |
143 | *val = 0; |
144 | |
145 | for (t = s; *t && !isspace((unsigned char) *t); t++) |
146 | ; |
147 | *t = 0; |
148 | |
149 | /* skip any leading blanks in the value part */ |
150 | for (val++; *val && isspace((unsigned char) *val); val++) |
151 | ; |
152 | |
153 | /* search to unquoted # */ |
154 | quote = 0; |
155 | for (t = val; *t; t++) { |
156 | if (*t == '"') |
157 | quote = !quote; |
158 | else if (!quote && *t == '#') |
159 | break; |
160 | } |
161 | if (quote) { |
162 | fprintf(stderr, "mo_config_file: wrong number of quotes in %s at %s\n" , file, val); |
163 | fclose(fd); |
164 | exit(1); |
165 | } |
166 | /* remove trailing white space */ |
167 | while (isspace((unsigned char) t[-1])) |
168 | t--; |
169 | *t++ = 0; |
170 | |
171 | /* treat value as empty if it consists only of white space */ |
172 | if (t <= val) |
173 | val = t - 1; |
174 | |
175 | set = (opt *) realloc(set, (setlen + 1) * sizeof(opt)); |
176 | set[setlen].kind = opt_config; |
177 | set[setlen].name = strdup(s); |
178 | set[setlen].value = malloc((size_t) (t - val)); |
179 | for (t = val, s = set[setlen].value; *t; t++) |
180 | if (*t != '"') |
181 | *s++ = *t; |
182 | *s = 0; |
183 | setlen++; |
184 | } |
185 | (void) fclose(fd); |
186 | *Set = set; |
187 | return setlen; |
188 | } |
189 | |
190 | int |
191 | mo_system_config(opt **Set, int setlen) |
192 | { |
193 | char *cfg; |
194 | |
195 | if (Set == NULL) { |
196 | if (default_set == NULL) { |
197 | opt *set = NULL; |
198 | |
199 | setlen = mo_default_set(&set, 0); |
200 | } else |
201 | setlen = default_setlen; |
202 | Set = &default_set; |
203 | } |
204 | cfg = mo_find_option(*Set, setlen, "config" ); |
205 | if (!cfg) |
206 | return setlen; |
207 | setlen = mo_config_file(Set, setlen, cfg); |
208 | free(cfg); |
209 | return setlen; |
210 | } |
211 | |
212 | int |
213 | mo_builtin_settings(opt **Set) |
214 | { |
215 | int i = 0; |
216 | opt *set; |
217 | |
218 | if (Set == NULL) |
219 | return 0; |
220 | |
221 | #define N_OPTIONS 7 /*MUST MATCH # OPTIONS BELOW */ |
222 | set = malloc(sizeof(opt) * N_OPTIONS); |
223 | if (set == NULL) |
224 | return 0; |
225 | |
226 | set[i].kind = opt_builtin; |
227 | set[i].name = strdup("gdk_dbpath" ); |
228 | set[i].value = strdup(LOCALSTATEDIR DIR_SEP_STR "monetdb5" DIR_SEP_STR |
229 | "dbfarm" DIR_SEP_STR "demo" ); |
230 | i++; |
231 | set[i].kind = opt_builtin; |
232 | set[i].name = strdup("mapi_port" ); |
233 | set[i].value = strdup("50000" ); |
234 | i++; |
235 | set[i].kind = opt_builtin; |
236 | set[i].name = strdup("mapi_open" ); |
237 | set[i].value = strdup("false" ); |
238 | i++; |
239 | set[i].kind = opt_builtin; |
240 | set[i].name = strdup("mapi_ipv6" ); |
241 | set[i].value = strdup("false" ); |
242 | i++; |
243 | set[i].kind = opt_builtin; |
244 | set[i].name = strdup("mapi_autosense" ); |
245 | set[i].value = strdup("false" ); |
246 | i++; |
247 | set[i].kind = opt_builtin; |
248 | set[i].name = strdup("sql_optimizer" ); |
249 | set[i].value = strdup("default_pipe" ); |
250 | i++; |
251 | set[i].kind = opt_builtin; |
252 | set[i].name = strdup("sql_debug" ); |
253 | set[i].value = strdup("0" ); |
254 | i++; |
255 | |
256 | assert(i == N_OPTIONS); |
257 | *Set = set; |
258 | return i; |
259 | } |
260 | |
261 | int |
262 | mo_add_option(opt **Set, int setlen, opt_kind kind, const char *name, const char *value) |
263 | { |
264 | opt *set; |
265 | |
266 | if (Set == NULL) { |
267 | if (default_set == NULL) { |
268 | set = NULL; |
269 | setlen = mo_default_set(&set, 0); |
270 | } else |
271 | setlen = default_setlen; |
272 | Set = &default_set; |
273 | } |
274 | set = (opt *) realloc(*Set, (setlen + 1) * sizeof(opt)); |
275 | set[setlen].kind = kind; |
276 | set[setlen].name = strdup(name); |
277 | set[setlen].value = strdup(value); |
278 | *Set = set; |
279 | return setlen + 1; |
280 | } |
281 | |
282 | void |
283 | mo_free_options(opt *set, int setlen) |
284 | { |
285 | int i; |
286 | |
287 | if (set == NULL) { |
288 | set = default_set; |
289 | setlen = default_setlen; |
290 | default_set = NULL; |
291 | default_setlen = 0; |
292 | } |
293 | for (i = 0; i < setlen; i++) { |
294 | if (set[i].name) |
295 | free(set[i].name); |
296 | if (set[i].value) |
297 | free(set[i].value); |
298 | } |
299 | free(set); |
300 | } |
301 | |