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