1 /* grecs - Gray's Extensible Configuration System
2 Copyright (C) 2007-2016 Sergey Poznyakoff
3
4 Grecs is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 Grecs is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with Grecs. If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <string.h>
21 #include <errno.h>
22 #include <ctype.h>
23 #include "grecs.h"
24 #include "wordsplit.h"
25 #include <fnmatch.h>
26 #include <stdlib.h>
27
28 static int
_grecs_list_eq(struct grecs_value * a,struct grecs_value * b)29 _grecs_list_eq(struct grecs_value *a, struct grecs_value *b)
30 {
31 struct grecs_list_entry *aent, *bent;
32 if (grecs_list_size(a->v.list) != grecs_list_size(b->v.list))
33 return 0;
34
35 for (aent = a->v.list->head, bent = b->v.list->head;;
36 aent = aent->next, bent = bent->next) {
37 if (!aent)
38 return bent == NULL;
39 if (!bent)
40 return 0;
41 if (!grecs_value_eq(aent->data, bent->data))
42 return 0;
43 }
44 /*notreached*/
45 return 1;
46 }
47
48 static int
_grecs_array_eq(struct grecs_value * a,struct grecs_value * b)49 _grecs_array_eq(struct grecs_value *a, struct grecs_value *b)
50 {
51 size_t i;
52
53 if (a->v.arg.c != b->v.arg.c)
54 return 0;
55
56 for (i = 0; i < a->v.arg.c; i++)
57 if (!grecs_value_eq(a->v.arg.v[i], b->v.arg.v[i]))
58 return 0;
59 return 1;
60 }
61
62 /* Return 1 if configuration value A equals B */
63 int
grecs_value_eq(struct grecs_value * a,struct grecs_value * b)64 grecs_value_eq(struct grecs_value *a, struct grecs_value *b)
65 {
66 if (a == 0 || b == 0)
67 return a == b;
68 if (a->type != b->type)
69 return 0;
70 switch (a->type) {
71 case GRECS_TYPE_STRING:
72 if (a->v.string == NULL)
73 return b->v.string == NULL;
74 return strcmp(a->v.string, b->v.string) == 0;
75
76 case GRECS_TYPE_LIST:
77 return _grecs_list_eq(a, b);
78
79 case GRECS_TYPE_ARRAY:
80 return _grecs_array_eq(a, b);
81 }
82 return 0;
83 }
84
85 static int
_grecs_list_match(struct grecs_value * pat,struct grecs_value * b,int flags)86 _grecs_list_match(struct grecs_value *pat, struct grecs_value *b, int flags)
87 {
88 struct grecs_list_entry *aent, *bent;
89 if (grecs_list_size(pat->v.list) != grecs_list_size(b->v.list))
90 return 0;
91
92 for (aent = pat->v.list->head, bent = b->v.list->head;;
93 aent = aent->next, bent = bent->next) {
94 if (!aent)
95 return bent == NULL;
96 if (!bent)
97 return 0;
98 if (!grecs_value_match(aent->data, bent->data, flags))
99 return 0;
100 }
101 /*notreached*/
102 return 1;
103 }
104
105 static int
_grecs_array_match(struct grecs_value * pat,struct grecs_value * b,int flags)106 _grecs_array_match(struct grecs_value *pat, struct grecs_value *b, int flags)
107 {
108 size_t i;
109
110 if (pat->v.arg.c > b->v.arg.c)
111 return 0;
112
113 for (i = 0; i < pat->v.arg.c; i++)
114 if (!grecs_value_match(pat->v.arg.v[i], b->v.arg.v[i], flags))
115 return 0;
116 return 1;
117 }
118
119 int
grecs_value_match(struct grecs_value * pat,struct grecs_value * b,int flags)120 grecs_value_match(struct grecs_value *pat, struct grecs_value *b, int flags)
121 {
122 if (pat == 0 || b == 0)
123 return pat == b;
124 if (pat->type != b->type) {
125 if (pat->type != GRECS_TYPE_STRING)
126 return 0;
127 switch (b->type) {
128 case GRECS_TYPE_LIST:
129 b = grecs_list_index(b->v.list, 0);
130 break;
131
132 case GRECS_TYPE_ARRAY:
133 b = b->v.arg.v[0];
134 }
135 }
136
137 switch (pat->type) {
138 case GRECS_TYPE_STRING:
139 if (pat->v.string == NULL)
140 return b->v.string == NULL;
141 return fnmatch(pat->v.string, b->v.string, flags) == 0;
142
143 case GRECS_TYPE_LIST:
144 return _grecs_list_match(pat, b, flags);
145
146 case GRECS_TYPE_ARRAY:
147 return _grecs_array_match(pat, b, flags);
148 }
149 return 0;
150 }
151
152
153 struct grecs_match_buf {
154 int argc; /* number of path components */
155 char **argv; /* array of path components */
156 int argi; /* Index of the current component */
157 struct grecs_value **labelv; /* Component labels */
158 struct grecs_node *root; /* Root node */
159 struct grecs_node *node; /* Last found node */
160 };
161
162 #define ISWC(c,w) ((c)[0] == (w) && (c)[1] == 0)
163
164 grecs_match_buf_t
grecs_match_buf_create(int argc,char ** argv,struct grecs_value ** labelv)165 grecs_match_buf_create(int argc, char **argv, struct grecs_value **labelv)
166 {
167 int i;
168 struct grecs_match_buf *buf = grecs_zalloc(sizeof(*buf));
169
170 buf->argc = argc;
171 buf->argv = argv;
172 buf->labelv = labelv;
173 /* Compress argv/argc by replacing contiguous sequences of *'s
174 with a single *. */
175 for (i = 0; i < buf->argc; i++) {
176 if (ISWC(buf->argv[i], '*')) {
177 int j;
178
179 for (j = i + 1;
180 j < buf->argc && ISWC(buf->argv[j], '*'); j++) {
181 free(buf->argv[j]);
182 grecs_value_free_content(buf->labelv[i]);
183 }
184 j -= i;
185 if (j > 1) {
186 memmove(&buf->argv[i+1], &buf->argv[i+j],
187 (buf->argc - (i + j)) *
188 sizeof(buf->argv[0]));
189 memmove(&buf->labelv[i+1], &buf->labelv[i+j],
190 (buf->argc - (i + j)) *
191 sizeof(buf->labelv[0]));
192 buf->argc -= j - 1;
193 }
194 }
195 }
196
197 return buf;
198 }
199
200 size_t
grecs_match_buf_get_args(grecs_match_buf_t buf,char *** argv)201 grecs_match_buf_get_args(grecs_match_buf_t buf, char ***argv)
202 {
203 if (argv)
204 *argv = buf->argv;
205 return buf->argc;
206 }
207
208 struct grecs_node *
grecs_match_buf_get_node(grecs_match_buf_t buf)209 grecs_match_buf_get_node(grecs_match_buf_t buf)
210 {
211 return buf->node;
212 }
213
214 struct grecs_node *
grecs_match_buf_get_root(grecs_match_buf_t buf)215 grecs_match_buf_get_root(grecs_match_buf_t buf)
216 {
217 return buf->root;
218 }
219
220 void
grecs_match_buf_set_root(grecs_match_buf_t buf,struct grecs_node * root)221 grecs_match_buf_set_root(grecs_match_buf_t buf, struct grecs_node *root)
222 {
223 buf->root = root;
224 }
225
226 static void
grecs_match_buf_free_contents(struct grecs_match_buf * buf)227 grecs_match_buf_free_contents(struct grecs_match_buf *buf)
228 {
229 size_t i;
230 for (i = 0; i < buf->argc; i++) {
231 free(buf->argv[i]);
232 grecs_value_free(buf->labelv[i]);
233 }
234 free(buf->argv);
235 free(buf->labelv);
236 }
237
238 void
grecs_match_buf_free(struct grecs_match_buf * buf)239 grecs_match_buf_free(struct grecs_match_buf *buf)
240 {
241 if (buf) {
242 grecs_match_buf_free_contents(buf);
243 free(buf);
244 }
245 }
246
247
248 static struct grecs_value *
parse_label(const char * str)249 parse_label(const char *str)
250 {
251 struct grecs_value *val = NULL;
252 size_t i;
253 struct wordsplit ws;
254 size_t len = strlen (str);
255
256 if (len > 1 && str[0] == '(' && str[len-1] == ')') {
257 struct grecs_list *lst;
258
259 ws.ws_delim = ",";
260 if (wordsplit_len (str + 1, len - 2, &ws,
261 WRDSF_DEFFLAGS|WRDSF_DELIM|
262 WRDSF_WS)) {
263 return NULL;
264 }
265
266 lst = grecs_value_list_create();
267 for (i = 0; i < ws.ws_wordc; i++) {
268 struct grecs_value *p = grecs_zalloc(sizeof(*p));
269 p->type = GRECS_TYPE_STRING;
270 p->v.string = ws.ws_wordv[i];
271 grecs_list_append(lst, p);
272 }
273 val = grecs_malloc(sizeof(*val));
274 val->type = GRECS_TYPE_LIST;
275 val->v.list = lst;
276 } else {
277 if (wordsplit(str, &ws, WRDSF_DEFFLAGS))
278 return NULL;
279 val = grecs_zalloc(sizeof(*val));
280 if (ws.ws_wordc == 1) {
281 val->type = GRECS_TYPE_STRING;
282 val->v.string = ws.ws_wordv[0];
283 } else {
284 val->type = GRECS_TYPE_ARRAY;
285 val->v.arg.c = ws.ws_wordc;
286 val->v.arg.v = grecs_calloc(ws.ws_wordc,
287 sizeof(val->v.arg.v[0]));
288 for (i = 0; i < ws.ws_wordc; i++) {
289 val->v.arg.v[i] =
290 grecs_zalloc(sizeof(*val->v.arg.v[0]));
291 val->v.arg.v[i]->type = GRECS_TYPE_STRING;
292 val->v.arg.v[i]->v.string = ws.ws_wordv[i];
293 }
294 }
295 }
296 ws.ws_wordc = 0;
297 wordsplit_free(&ws);
298 return val;
299 }
300
301 static int
split_cfg_path(const char * path,int * pargc,char *** pargv,grecs_value_t *** pvalv)302 split_cfg_path(const char *path, int *pargc, char ***pargv,
303 grecs_value_t ***pvalv)
304 {
305 int argc;
306 char **argv;
307 char *delim = ".";
308 char static_delim[2] = { 0, 0 };
309
310 if (path[0] == '\\') {
311 argv = calloc(2, sizeof (*argv));
312 if (!argv)
313 return WRDSE_NOSPACE;
314 argv[0] = strdup(path + 1);
315 if (!argv[0]) {
316 free(argv);
317 return WRDSE_NOSPACE;
318 }
319 argv[1] = NULL;
320 argc = 1;
321 } else {
322 int rc;
323 struct wordsplit ws;
324
325 if (strchr("./:;,^~", path[0])) {
326 delim = static_delim;
327 delim[0] = path[0];
328 path++;
329 }
330 ws.ws_delim = delim;
331
332 rc = wordsplit(path, &ws,
333 WRDSF_DELIM | WRDSF_DEFFLAGS);
334 if (rc)
335 return rc;
336 argc = ws.ws_wordc;
337 argv = ws.ws_wordv;
338 ws.ws_wordc = 0;
339 ws.ws_wordv = NULL;
340 wordsplit_free(&ws);
341 }
342
343 *pargv = argv;
344 *pargc = argc;
345 if (pvalv) {
346 int i;
347 grecs_value_t **valv;
348
349 valv = grecs_calloc(argc, sizeof(valv[0]));
350 for (i = 0; i < argc; i++) {
351 char *p = strchr(argv[i], '=');
352 if (p) {
353 *p++ = 0;
354 valv[i] = parse_label(p);
355 }
356 }
357 *pvalv = valv;
358 }
359 return 0;
360 }
361
362
363 enum grecs_tree_recurse_res
grecs_node_exact_match(enum grecs_tree_recurse_op op,struct grecs_node * node,void * data)364 grecs_node_exact_match(enum grecs_tree_recurse_op op,
365 struct grecs_node *node, void *data)
366 {
367 int match = 0;
368 struct grecs_match_buf *buf = data;
369
370 if (node->type == grecs_node_root)
371 return grecs_tree_recurse_ok;
372 if (op == grecs_tree_recurse_post) {
373 if (buf->argi == 0)
374 return grecs_tree_recurse_stop;
375 --buf->argi;
376 return grecs_tree_recurse_ok;
377 }
378
379 if (strcmp(buf->argv[buf->argi], node->ident) == 0
380 && (!buf->labelv[buf->argi] ||
381 grecs_value_eq(buf->labelv[buf->argi], node->v.value))) {
382 if (buf->argi + 1 == buf->argc) {
383 buf->node = node;
384 return grecs_tree_recurse_stop;
385 }
386 match = 1;
387 }
388
389 if (match) {
390 if (op == grecs_tree_recurse_pre) {
391 if (buf->argi + 1 == buf->argc)
392 return grecs_tree_recurse_skip;
393 buf->argi++;
394 }
395 return grecs_tree_recurse_ok;
396 }
397
398 return node->type == grecs_node_block ?
399 grecs_tree_recurse_skip : grecs_tree_recurse_ok;
400 }
401
402 struct grecs_node *
grecs_find_node(struct grecs_node * node,const char * path)403 grecs_find_node(struct grecs_node *node, const char *path)
404 {
405 int rc;
406 struct grecs_match_buf buf;
407
408 if (strcmp(path, ".") == 0)
409 return node;
410 rc = split_cfg_path(path, &buf.argc, &buf.argv, &buf.labelv);
411 if (rc || !buf.argc)
412 return NULL;
413 buf.argi = 0;
414 buf.node = NULL;
415 grecs_tree_recurse(node, grecs_node_exact_match, &buf);
416 grecs_match_buf_free_contents(&buf);
417 return buf.node;
418 }
419
420
421 static void
fixup_loci(struct grecs_node * node,grecs_locus_t const * plocus,struct grecs_locus_point const * endp)422 fixup_loci(struct grecs_node *node,
423 grecs_locus_t const *plocus,
424 struct grecs_locus_point const *endp)
425 {
426 grecs_locus_t loc = *plocus;
427
428 for (; node; node = node->down) {
429 node->idloc = loc;
430
431 node->locus = loc;
432 if (endp)
433 node->locus.end = *endp;
434 }
435 }
436
437 struct grecs_node *
grecs_node_from_path_locus(const char * path,const char * value,grecs_locus_t * plocus,grecs_locus_t * vallocus)438 grecs_node_from_path_locus(const char *path, const char *value,
439 grecs_locus_t *plocus, grecs_locus_t *vallocus)
440 {
441 int rc;
442 int i;
443 int argc;
444 char **argv;
445 struct grecs_node *dn = NULL;
446
447 rc = split_cfg_path(path, &argc, &argv, NULL);
448 if (rc)
449 return NULL;
450
451 dn = grecs_node_create(grecs_node_stmt, NULL);
452 dn->ident = argv[argc - 1];
453 if (value) {
454 struct grecs_value *gval = parse_label(value);
455 if (vallocus)
456 gval->locus = *vallocus;
457 dn->v.value = gval;
458 } else
459 dn->v.value = NULL;
460
461 for (i = argc - 2; i >= 0; i--) {
462 struct grecs_value *label = NULL;
463 struct grecs_node *node;
464 char *p, *q = argv[i];
465
466 do {
467 p = strchr(q, '=');
468 if (p && p > argv[i] && p[-1] != '\\') {
469 *p++ = 0;
470 label = parse_label(p);
471 break;
472 } else if (p)
473 q = p + 1;
474 else
475 break;
476 } while (*q);
477
478 node = grecs_node_create(grecs_node_block, plocus);
479 node->ident = argv[i];
480 if (label)
481 node->v.value = label;
482
483 node->down = dn;
484 if (dn)
485 dn->up = node;
486 dn = node;
487 }
488
489 if (plocus)
490 fixup_loci(dn,
491 plocus, vallocus ? &vallocus->end : NULL);
492
493 free(argv);
494 return dn;
495 }
496
497 struct grecs_node *
grecs_node_from_path(const char * path,const char * value)498 grecs_node_from_path(const char *path, const char *value)
499 {
500 return grecs_node_from_path_locus(path, value, NULL, NULL);
501 }
502
503
504 static int
is_root(struct grecs_match_buf * buf,struct grecs_node * node)505 is_root(struct grecs_match_buf *buf, struct grecs_node *node)
506 {
507 return (buf->root == node || node->type == grecs_node_root);
508 }
509
510 static int
grecs_match(struct grecs_match_buf * buf)511 grecs_match(struct grecs_match_buf *buf)
512 {
513 struct grecs_node *node;
514 int wcard = 0;
515
516 buf->argi = buf->argc - 1;
517 node = buf->node;
518
519 while (buf->argi >= 0) {
520 if (ISWC(buf->argv[buf->argi], '*')) {
521 wcard = 1;
522 if (buf->argi-- == 0)
523 return 1;
524 continue;
525 }
526
527 if ((ISWC(buf->argv[buf->argi], '%') ||
528 strcmp(buf->argv[buf->argi], node->ident) == 0)
529 /* FIXME: */
530 && (!buf->labelv[buf->argi] ||
531 grecs_value_match(buf->labelv[buf->argi],
532 node->v.value, 0))) {
533 wcard = 0;
534 node = node->up;
535 if (buf->argi-- == 0)
536 return is_root(buf, node);
537 } else if (!wcard)
538 return 0;
539 else
540 node = node->up;
541 if (is_root(buf, node))
542 return ISWC(buf->argv[buf->argi], '*');
543 }
544 return 0;
545 }
546
547 struct grecs_node *
grecs_match_next(struct grecs_match_buf * buf)548 grecs_match_next(struct grecs_match_buf *buf)
549 {
550 if (!buf)
551 return NULL;
552 while ((buf->node = grecs_next_node(buf->node)))
553 if (grecs_match(buf))
554 break;
555 return buf->node;
556 }
557
558 struct grecs_node *
grecs_match_buf_first(struct grecs_match_buf * buf,struct grecs_node * tree)559 grecs_match_buf_first(struct grecs_match_buf *buf, struct grecs_node *tree)
560 {
561 struct grecs_node *node;
562
563 buf->argi = 0;
564 buf->root = tree;
565 buf->node = grecs_tree_first_node(tree);
566 if (!buf->node)
567 return NULL;
568 if (grecs_match(buf))
569 node = buf->node;
570 else
571 node = grecs_match_next(buf);
572 return node;
573 }
574
575 struct grecs_node *
grecs_match_first(struct grecs_node * tree,const char * pattern,struct grecs_match_buf ** pbuf)576 grecs_match_first(struct grecs_node *tree, const char *pattern,
577 struct grecs_match_buf **pbuf)
578 {
579 struct grecs_node *node;
580 struct grecs_match_buf *buf;
581
582 if (strcmp(pattern, ".") == 0) {
583 *pbuf = NULL;
584 return tree;
585 }
586
587 buf = grecs_zalloc(sizeof(*buf));
588 if (split_cfg_path(pattern, &buf->argc, &buf->argv, &buf->labelv)) {
589 free(buf);
590 return NULL;
591 }
592 node = grecs_match_buf_first(buf, tree);
593 if (node)
594 *pbuf = buf;
595 else {
596 grecs_match_buf_free(buf);
597 *pbuf = NULL;
598 }
599 return node;
600 }
601
602