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, 2025 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 : #include <string.h>
28 : #include <ctype.h>
29 :
30 : #ifdef HAVE_UNISTD_H
31 : #include <unistd.h>
32 : #endif
33 :
34 : #ifdef NATIVE_WIN32
35 : #define getpid _getpid
36 : #endif
37 :
38 : /* these two are used if the set parameter passed into functions is NULL */
39 : static int default_setlen = 0;
40 : static opt *default_set = NULL;
41 :
42 : static int
43 2124 : mo_default_set(opt **Set, int setlen)
44 : {
45 2124 : if (*Set == NULL) {
46 0 : if (default_set == NULL) {
47 0 : default_setlen = mo_builtin_settings(&default_set);
48 0 : default_setlen = mo_system_config(&default_set, default_setlen);
49 : }
50 0 : *Set = default_set;
51 0 : setlen = default_setlen;
52 : }
53 2124 : return setlen;
54 : }
55 :
56 : void
57 347 : mo_print_options(opt *set, int setlen)
58 : {
59 347 : int i = 0;
60 :
61 347 : setlen = mo_default_set(&set, setlen);
62 4609 : for (i = 0; i < setlen; i++) {
63 3915 : if (set[i].kind == opt_builtin) {
64 1735 : fprintf(stderr, "# builtin opt \t%s = %s\n", set[i].name, set[i].value);
65 : }
66 : }
67 4262 : for (i = 0; i < setlen; i++) {
68 3915 : if (set[i].kind == opt_config) {
69 0 : fprintf(stderr, "# config opt \t%s = %s\n", set[i].name, set[i].value);
70 : }
71 : }
72 4262 : for (i = 0; i < setlen; i++) {
73 3915 : if (set[i].kind == opt_cmdline) {
74 2180 : fprintf(stderr, "# cmdline opt \t%s = %s\n", set[i].name, set[i].value);
75 : }
76 : }
77 347 : }
78 :
79 :
80 : const char *
81 1777 : mo_find_option(opt *set, int setlen, const char *name)
82 : {
83 1777 : opt *o = NULL;
84 1777 : int i;
85 :
86 1777 : setlen = mo_default_set(&set, setlen);
87 23361 : for (i = 0; i < setlen; i++) {
88 19807 : if (strcmp(set[i].name, name) == 0)
89 724 : if (!o || o->kind < set[i].kind)
90 19807 : o = set + i;
91 : }
92 1777 : if (o)
93 366 : return o->value;
94 : return NULL;
95 : }
96 :
97 : static int
98 0 : mo_config_file(opt **Set, int setlen, const char *file)
99 : {
100 0 : char buf[BUFSIZ];
101 0 : FILE *fd = NULL;
102 0 : opt *set;
103 :
104 0 : if (Set == NULL) {
105 0 : if (default_set == NULL) {
106 0 : set = NULL;
107 0 : setlen = mo_default_set(&set, 0);
108 : } else
109 0 : setlen = default_setlen;
110 : Set = &default_set;
111 : }
112 0 : set = *Set;
113 0 : fd = fopen(file, "r");
114 0 : if (fd == NULL) {
115 0 : fprintf(stderr, "Could not open file %s\n", file);
116 0 : return setlen;
117 : }
118 0 : while (fgets(buf, BUFSIZ, fd) != NULL) {
119 : char *s, *t, *val;
120 : int quote;
121 :
122 0 : for (s = buf; *s && isspace((unsigned char) *s); s++)
123 : ;
124 0 : if (*s == '#')
125 0 : continue; /* commentary */
126 0 : if (*s == 0)
127 0 : continue; /* empty line */
128 :
129 0 : val = strchr(s, '=');
130 0 : if (val == NULL) {
131 0 : fprintf(stderr, "mo_config_file: syntax error in %s at %s\n", file, s);
132 0 : break;
133 : }
134 0 : *val = 0;
135 :
136 0 : for (t = s; *t && !isspace((unsigned char) *t); t++)
137 : ;
138 0 : *t = 0;
139 :
140 : /* skip any leading blanks in the value part */
141 0 : for (val++; *val && isspace((unsigned char) *val); val++)
142 : ;
143 :
144 : /* search to unquoted # */
145 : quote = 0;
146 0 : for (t = val; *t; t++) {
147 0 : if (*t == '"')
148 0 : quote = !quote;
149 0 : else if (!quote && *t == '#')
150 : break;
151 : }
152 0 : if (quote) {
153 0 : fprintf(stderr, "mo_config_file: wrong number of quotes in %s at %s\n", file, val);
154 0 : break;
155 : }
156 : /* remove trailing white space */
157 0 : while (isspace((unsigned char) t[-1]))
158 0 : t--;
159 0 : *t++ = 0;
160 :
161 : /* treat value as empty if it consists only of white space */
162 0 : if (t <= val)
163 0 : val = t - 1;
164 :
165 0 : opt *tmp = realloc(set, (setlen + 1) * sizeof(opt));
166 0 : if (tmp == NULL)
167 : break;
168 0 : *Set = set = tmp;
169 0 : set[setlen].kind = opt_config;
170 0 : set[setlen].name = strdup(s);
171 0 : set[setlen].value = malloc((size_t) (t - val));
172 0 : if (set[setlen].name == NULL || set[setlen].value == NULL) {
173 0 : free(set[setlen].name);
174 0 : free(set[setlen].value);
175 0 : break;
176 : }
177 0 : for (t = val, s = set[setlen].value; *t; t++)
178 0 : if (*t != '"')
179 0 : *s++ = *t;
180 0 : *s = 0;
181 0 : setlen++;
182 : }
183 0 : (void) fclose(fd);
184 0 : return setlen;
185 : }
186 :
187 : int
188 347 : mo_system_config(opt **Set, int setlen)
189 : {
190 347 : const char *cfg;
191 :
192 347 : if (Set == NULL) {
193 0 : if (default_set == NULL) {
194 0 : opt *set = NULL;
195 :
196 0 : setlen = mo_default_set(&set, 0);
197 : } else
198 0 : setlen = default_setlen;
199 : Set = &default_set;
200 : }
201 347 : cfg = mo_find_option(*Set, setlen, "config");
202 347 : if (!cfg)
203 : return setlen;
204 0 : setlen = mo_config_file(Set, setlen, cfg);
205 0 : return setlen;
206 : }
207 :
208 : int
209 360 : mo_builtin_settings(opt **Set)
210 : {
211 360 : int i = 0;
212 360 : opt *set;
213 :
214 360 : if (Set == NULL)
215 : return 0;
216 :
217 : #define N_OPTIONS 5 /*MUST MATCH # OPTIONS BELOW */
218 360 : set = malloc(sizeof(opt) * N_OPTIONS);
219 360 : if (set == NULL)
220 : return 0;
221 :
222 360 : *Set = set;
223 360 : set[i].kind = opt_builtin;
224 360 : set[i].name = strdup("gdk_dbpath");
225 360 : set[i].value = strdup(LOCALSTATEDIR DIR_SEP_STR "monetdb5" DIR_SEP_STR
226 : "dbfarm" DIR_SEP_STR "demo");
227 360 : if (set[i].name == NULL || set[i].value == NULL) {
228 0 : free(set[i].name);
229 0 : free(set[i].value);
230 0 : return i;
231 : }
232 360 : i++;
233 360 : set[i].kind = opt_builtin;
234 360 : set[i].name = strdup("mapi_port");
235 360 : set[i].value = strdup(MAPI_PORT_STR);
236 360 : if (set[i].name == NULL || set[i].value == NULL) {
237 0 : free(set[i].name);
238 0 : free(set[i].value);
239 0 : return i;
240 : }
241 360 : i++;
242 360 : set[i].kind = opt_builtin;
243 360 : set[i].name = strdup("sql_optimizer");
244 360 : set[i].value = strdup("default_pipe");
245 360 : if (set[i].name == NULL || set[i].value == NULL) {
246 0 : free(set[i].name);
247 0 : free(set[i].value);
248 0 : return i;
249 : }
250 360 : i++;
251 360 : set[i].kind = opt_builtin;
252 360 : set[i].name = strdup("sql_debug");
253 360 : set[i].value = strdup("0");
254 360 : if (set[i].name == NULL || set[i].value == NULL) {
255 0 : free(set[i].name);
256 0 : free(set[i].value);
257 0 : return i;
258 : }
259 360 : i++;
260 360 : set[i].kind = opt_builtin;
261 360 : set[i].name = strdup("raw_strings");
262 360 : set[i].value = strdup("false");
263 360 : if (set[i].name == NULL || set[i].value == NULL) {
264 0 : free(set[i].name);
265 0 : free(set[i].value);
266 0 : return i;
267 : }
268 360 : i++;
269 :
270 : assert(i == N_OPTIONS);
271 : return i;
272 : }
273 :
274 : int
275 2192 : mo_add_option(opt **Set, int setlen, opt_kind kind, const char *name, const char *value)
276 : {
277 2192 : opt *set;
278 :
279 2192 : if (Set == NULL) {
280 0 : if (default_set == NULL) {
281 0 : set = NULL;
282 0 : setlen = mo_default_set(&set, 0);
283 : } else
284 0 : setlen = default_setlen;
285 : Set = &default_set;
286 : }
287 2192 : opt *tmp = (opt *) realloc(*Set, (setlen + 1) * sizeof(opt));
288 2192 : if (tmp == NULL)
289 : return setlen;
290 2192 : *Set = set = tmp;
291 2192 : set[setlen].kind = kind;
292 2192 : set[setlen].name = strdup(name);
293 2192 : set[setlen].value = strdup(value);
294 2192 : if (set[setlen].name == NULL || set[setlen].value == NULL) {
295 0 : free(set[setlen].name);
296 0 : free(set[setlen].value);
297 0 : return setlen;
298 : }
299 : return setlen + 1;
300 : }
301 :
302 : void
303 359 : mo_free_options(opt *set, int setlen)
304 : {
305 359 : int i;
306 :
307 359 : if (set == NULL) {
308 0 : set = default_set;
309 0 : setlen = default_setlen;
310 0 : default_set = NULL;
311 0 : default_setlen = 0;
312 : }
313 4346 : for (i = 0; i < setlen; i++) {
314 3987 : if (set[i].name)
315 3987 : free(set[i].name);
316 3987 : if (set[i].value)
317 3987 : free(set[i].value);
318 : }
319 359 : free(set);
320 359 : }
|