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 <sys/types.h>
21 #include <sys/socket.h>
22 #include <sys/time.h>
23 #include <sys/un.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <netdb.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <limits.h>
30 #include <string.h>
31 #include "grecs.h"
32
33 struct grecs_sockaddr_hints *grecs_sockaddr_hints;
34
35 void
grecs_value_free_content(struct grecs_value * val)36 grecs_value_free_content(struct grecs_value *val)
37 {
38 int i;
39
40 if (!val)
41 return;
42 switch (val->type) {
43 case GRECS_TYPE_STRING:
44 grecs_free(val->v.string);
45 break;
46
47 case GRECS_TYPE_LIST:
48 grecs_list_free(val->v.list);
49 break;
50
51 case GRECS_TYPE_ARRAY:
52 for (i = 0; i < val->v.arg.c; i++)
53 grecs_value_free(val->v.arg.v[i]);
54 free(val->v.arg.v);
55 }
56 }
57
58 void
grecs_value_free(struct grecs_value * val)59 grecs_value_free(struct grecs_value *val)
60 {
61 grecs_value_free_content(val);
62 grecs_free(val);
63 }
64
65 const char *
grecs_value_type_string(int t)66 grecs_value_type_string(int t)
67 {
68 static const char *types[] = {
69 [GRECS_TYPE_STRING] = N_("string"),
70 [GRECS_TYPE_LIST] = N_("list"),
71 [GRECS_TYPE_ARRAY] = N_("one or more arguments")
72 };
73 if (t >= 0 && t < sizeof(types) / sizeof(types[0]))
74 return types[t];
75 return N_("unrecognized type; please report");
76 }
77
78 struct grecs_node *
grecs_node_create(enum grecs_node_type type,grecs_locus_t * loc)79 grecs_node_create(enum grecs_node_type type, grecs_locus_t *loc)
80 {
81 struct grecs_node *np = grecs_zalloc(sizeof(*np));
82 np->type = type;
83 if (loc)
84 np->locus = *loc;
85 return np;
86 }
87
88 struct grecs_node *
grecs_node_create_points(enum grecs_node_type type,struct grecs_locus_point beg,struct grecs_locus_point end)89 grecs_node_create_points(enum grecs_node_type type,
90 struct grecs_locus_point beg,
91 struct grecs_locus_point end)
92 {
93 grecs_locus_t loc;
94
95 loc.beg = beg;
96 loc.end = end;
97 return grecs_node_create(type, &loc);
98 }
99
100 void
grecs_node_bind(struct grecs_node * master,struct grecs_node * node,int dn)101 grecs_node_bind(struct grecs_node *master, struct grecs_node *node, int dn)
102 {
103 struct grecs_node *np;
104
105 if (!node)
106 return;
107 if (dn) {
108 if (!master->down) {
109 master->down = node;
110 node->prev = NULL;
111 } else {
112 for (np = master->down; np->next; np = np->next)
113 ;
114 np->next = node;
115 node->prev = np;
116 }
117 for (; node; node = node->next)
118 node->up = master;
119 } else {
120 if (!master->next) {
121 master->next = node;
122 node->prev = master;
123 } else {
124 for (np = master->next; np->next; np = np->next)
125 ;
126 np->next = node;
127 node->prev = np;
128 }
129 node->up = master->up;
130 }
131 }
132
133 int
grecs_node_unlink(struct grecs_node * node)134 grecs_node_unlink(struct grecs_node *node)
135 {
136 if (node->prev)
137 node->prev->next = node->next;
138 else if (node->up)
139 node->up->down = node->next;
140 else
141 return 1;
142 if (node->next)
143 node->next->prev = node->prev;
144 node->up = node->prev = node->next = NULL;
145 return 0;
146 }
147
148 static void
listel_dispose(void * el)149 listel_dispose(void *el)
150 {
151 grecs_free(el);
152 }
153
154 struct grecs_list *
_grecs_simple_list_create(int dispose)155 _grecs_simple_list_create(int dispose)
156 {
157 struct grecs_list *lp = grecs_list_create();
158 if (dispose)
159 lp->free_entry = listel_dispose;
160 return lp;
161 }
162
163
164
165
166 static enum grecs_tree_recurse_res
_tree_recurse(struct grecs_node * node,grecs_tree_recursor_t recfun,void * data)167 _tree_recurse(struct grecs_node *node, grecs_tree_recursor_t recfun,
168 void *data)
169 {
170 enum grecs_tree_recurse_res res;
171 #define CKRES() \
172 switch (res) { \
173 case grecs_tree_recurse_fail: \
174 case grecs_tree_recurse_stop: \
175 return res; \
176 default: \
177 break; \
178 }
179
180 while (node) {
181 struct grecs_node *next = node->next;
182 if (node->type == grecs_node_stmt) {
183 res = recfun(grecs_tree_recurse_set, node, data);
184 CKRES();
185 } else {
186 switch (recfun(grecs_tree_recurse_pre, node, data)) {
187 case grecs_tree_recurse_ok:
188 res = _tree_recurse(node->down, recfun, data);
189 CKRES();
190 res = recfun(grecs_tree_recurse_post, node,
191 data);
192 CKRES();
193 break;
194 case grecs_tree_recurse_fail:
195 return grecs_tree_recurse_fail;
196 case grecs_tree_recurse_stop:
197 return grecs_tree_recurse_stop;
198 case grecs_tree_recurse_skip:
199 break;
200 }
201 }
202 node = next;
203 }
204 return grecs_tree_recurse_ok;
205 #undef CKRES
206 }
207
208 int
grecs_tree_recurse(struct grecs_node * node,grecs_tree_recursor_t recfun,void * data)209 grecs_tree_recurse(struct grecs_node *node, grecs_tree_recursor_t recfun,
210 void *data)
211 {
212 switch (_tree_recurse(node, recfun, data)) {
213 case grecs_tree_recurse_ok:
214 case grecs_tree_recurse_stop:
215 return 0;
216 default:
217 break;
218 }
219 return 1;
220 }
221
222 void
grecs_node_free(struct grecs_node * node)223 grecs_node_free(struct grecs_node *node)
224 {
225 if (!node)
226 return;
227 switch (node->type) {
228 case grecs_node_root:
229 grecs_symtab_free(node->v.texttab);
230 break;
231 default:
232 grecs_value_free(node->v.value);
233 }
234 grecs_free(node->ident);
235 grecs_free(node);
236 }
237
238 static enum grecs_tree_recurse_res
freeproc(enum grecs_tree_recurse_op op,struct grecs_node * node,void * data)239 freeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data)
240 {
241 switch (op) {
242 case grecs_tree_recurse_set:
243 case grecs_tree_recurse_post:
244 grecs_node_unlink(node);
245 grecs_node_free(node);
246 break;
247 case grecs_tree_recurse_pre:
248 /* descend into the subtree */
249 break;
250 }
251 return grecs_tree_recurse_ok;
252 }
253
254 int
grecs_tree_free(struct grecs_node * node)255 grecs_tree_free(struct grecs_node *node)
256 {
257 if (!node)
258 return 0;
259 if (node->type != grecs_node_root) {
260 errno = EINVAL;
261 return 1;
262 }
263 grecs_tree_recurse(node, freeproc, NULL);
264 return 0;
265 }
266
267
268
269 static int
fake_callback(enum grecs_callback_command cmd,grecs_node_t * node,void * varptr,void * cb_data)270 fake_callback(
271 #if GRECS_TREE_API
272 enum grecs_callback_command cmd,
273 grecs_node_t *node,
274 void *varptr,
275 void *cb_data
276 #else
277 enum grecs_callback_command cmd,
278 grecs_locus_t *locus,
279 void *varptr,
280 grecs_value_t *value,
281 void *cb_data
282 #endif
283 )
284 {
285 return 0;
286 }
287
288 static struct grecs_keyword fake = {
289 "*",
290 NULL,
291 NULL,
292 grecs_type_void,
293 GRECS_DFLT,
294 NULL,
295 0,
296 fake_callback,
297 NULL,
298 &fake
299 };
300
301 static struct grecs_keyword *
find_keyword(struct grecs_keyword * cursect,grecs_node_t * node)302 find_keyword(struct grecs_keyword *cursect, grecs_node_t *node)
303 {
304 if (cursect && cursect->kwd && cursect != &fake) {
305 struct grecs_keyword *found = NULL, *kwp;
306 char const *msg;
307
308 for (kwp = cursect->kwd; kwp->ident; kwp++) {
309 if (strcmp(kwp->ident, node->ident) == 0) {
310 found = kwp;
311 if (kwp->callback
312 || (node->down
313 ? kwp->type == grecs_type_section
314 : kwp->type != grecs_type_section))
315 return kwp;
316 }
317 }
318 if (found) {
319 if (found->type == grecs_type_section) {
320 msg = N_("section keyword used as a scalar");
321 } else {
322 msg = N_("scalar keyword used as a section");
323 }
324 } else {
325 msg = N_("unknown keyword");
326 }
327 grecs_error(&node->idloc, 0, "%s", gettext(msg));
328 } else {
329 return &fake;
330 }
331 return NULL;
332 }
333
334 static void *
target_ptr(struct grecs_keyword * kwp,char * base)335 target_ptr(struct grecs_keyword *kwp, char *base)
336 {
337 if (kwp->varptr)
338 base = (char*) kwp->varptr + kwp->offset;
339 else if (base)
340 base += kwp->offset;
341
342 return base;
343 }
344
345 static int
string_to_bool(const char * string,int * pval,grecs_locus_t const * locus)346 string_to_bool(const char *string, int *pval, grecs_locus_t const *locus)
347 {
348 if (strcmp(string, "yes") == 0
349 || strcmp(string, "true") == 0
350 || strcmp(string, "t") == 0
351 || strcmp(string, "1") == 0)
352 *pval = 1;
353 else if (strcmp(string, "no") == 0
354 || strcmp(string, "false") == 0
355 || strcmp(string, "nil") == 0
356 || strcmp(string, "0") == 0)
357 *pval = 0;
358 else {
359 grecs_error(locus, 0,
360 _("%s: not a valid boolean value"),
361 string);
362 return 1;
363 }
364 return 0;
365 }
366
367 static int
string_to_host(struct in_addr * in,const char * string,grecs_locus_t const * locus)368 string_to_host(struct in_addr *in, const char *string,
369 grecs_locus_t const *locus)
370 {
371 if (inet_aton(string, in) == 0) {
372 struct hostent *hp;
373
374 hp = gethostbyname(string);
375 if (hp == NULL)
376 return 1;
377 memcpy(in, hp->h_addr, sizeof(struct in_addr));
378 }
379 return 0;
380 }
381
382 #if !GRECS_SOCKADDR_LIST
383 static int
string_to_sockaddr(struct grecs_sockaddr * sp,const char * string,grecs_locus_t const * locus)384 string_to_sockaddr(struct grecs_sockaddr *sp, const char *string,
385 grecs_locus_t const *locus)
386 {
387 if (string[0] == '/') {
388 struct sockaddr_un s_un;
389 if (strlen(string) >= sizeof(s_un.sun_path)) {
390 grecs_error(locus, 0,
391 _("%s: UNIX socket name too long"),
392 string);
393 return 1;
394 }
395 s_un.sun_family = AF_UNIX;
396 strcpy(s_un.sun_path, string);
397 sp->len = sizeof(s_un);
398 sp->sa = grecs_malloc(sp->len);
399 memcpy(sp->sa, &s_un, sp->len);
400 } else {
401 char *p = strchr(string, ':');
402 size_t len;
403 struct sockaddr_in sa;
404
405 sa.sin_family = AF_INET;
406 if (p)
407 len = p - string;
408 else
409 len = strlen(string);
410
411 if (len == 0)
412 sa.sin_addr.s_addr = INADDR_ANY;
413 else {
414 char *host = grecs_malloc(len + 1);
415 memcpy(host, string, len);
416 host[len] = 0;
417
418 if (string_to_host(&sa.sin_addr, host, locus)) {
419 grecs_error(locus, 0,
420 _("%s: not a valid IP address or hostname"),
421 host);
422 grecs_free(host);
423 return 1;
424 }
425 grecs_free(host);
426 }
427
428 if (p) {
429 struct servent *serv;
430
431 p++;
432 serv = getservbyname(p, "tcp");
433 if (serv != NULL)
434 sa.sin_port = serv->s_port;
435 else {
436 unsigned long l;
437 char *q;
438
439 /* Not in services, maybe a number? */
440 l = strtoul(p, &q, 0);
441
442 if (*q || l > USHRT_MAX) {
443 grecs_error(locus, 0,
444 _("%s: not a valid port number"), p);
445 return 1;
446 }
447 sa.sin_port = htons(l);
448 }
449 } else if (grecs_default_port)
450 sa.sin_port = grecs_default_port;
451 else {
452 grecs_error(locus, 0, _("missing port number"));
453 return 1;
454 }
455 sp->len = sizeof(sa);
456 sp->sa = grecs_malloc(sp->len);
457 memcpy(sp->sa, &sa, sp->len);
458 }
459 return 0;
460 }
461 #endif
462
463 /* The TYPE_* defines come from gnulib's intprops.h */
464
465 /* True if the arithmetic type T is signed. */
466 # define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
467
468 /* The maximum and minimum values for the integer type T. These
469 macros have undefined behavior if T is signed and has padding bits. */
470 # define TYPE_MINIMUM(t) \
471 ((t) (! TYPE_SIGNED(t) \
472 ? (t) 0 \
473 : TYPE_SIGNED_MAGNITUDE(t) \
474 ? ~ (t) 0 \
475 : ~ TYPE_MAXIMUM(t)))
476 # define TYPE_MAXIMUM(t) \
477 ((t) (! TYPE_SIGNED(t) \
478 ? (t) -1 \
479 : ((((t) 1 << (sizeof(t) * CHAR_BIT - 2)) - 1) * 2 + 1)))
480 # define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
481
482
483 #define STRTONUM(s, type, base, res, limit, loc) \
484 { \
485 type sum = 0; \
486 \
487 for (; *s; s++) \
488 { \
489 type x; \
490 \
491 if ('0' <= *s && *s <= '9') \
492 x = sum * base + *s - '0'; \
493 else if (base == 16 && 'a' <= *s && *s <= 'f') \
494 x = sum * base + *s - 'a'; \
495 else if (base == 16 && 'A' <= *s && *s <= 'F') \
496 x = sum * base + *s - 'A'; \
497 else \
498 break; \
499 if (x <= sum) \
500 { \
501 grecs_error(loc, 0, _("numeric overflow")); \
502 return 1; \
503 } \
504 else if (limit && x > limit) \
505 { \
506 grecs_error(loc, 0, _("value out of allowed range")); \
507 return 1; \
508 } \
509 sum = x; \
510 } \
511 res = sum; \
512 }
513
514 #define STRxTONUM(s, type, res, limit, loc) \
515 { \
516 int base; \
517 if (*s == '0') \
518 { \
519 s++; \
520 if (*s == 0) \
521 base = 10; \
522 else if (*s == 'x' || *s == 'X') \
523 { \
524 s++; \
525 base = 16; \
526 } \
527 else \
528 base = 8; \
529 } else \
530 base = 10; \
531 STRTONUM(s, type, base, res, limit, loc); \
532 }
533
534 #define GETUNUM(str, type, res, loc) \
535 { \
536 type tmpres; \
537 const char *s = str; \
538 STRxTONUM(s, type, tmpres, 0, loc); \
539 if (*s) \
540 { \
541 grecs_error(loc, 0, _("not a number (stopped near `%s')"), \
542 s); \
543 return 1; \
544 } \
545 res = tmpres; \
546 }
547
548 #define GETSNUM(str, type, res, loc) \
549 { \
550 unsigned type tmpres; \
551 const char *s = str; \
552 int sign; \
553 unsigned type limit; \
554 \
555 if (*s == '-') \
556 { \
557 sign = 1; \
558 s++; \
559 limit = TYPE_MINIMUM(type); \
560 limit = - limit; \
561 } \
562 else \
563 { \
564 sign = 0; \
565 limit = TYPE_MAXIMUM(type); \
566 } \
567 \
568 STRxTONUM(s, unsigned type, tmpres, limit, loc); \
569 if (*s) \
570 { \
571 grecs_error(loc, 0, _("not a number (stopped near `%s')"), s); \
572 return 1; \
573 } \
574 res = sign ? - tmpres : tmpres; \
575 }
576
577
578 int
grecs_string_convert(void * target,enum grecs_data_type type,const char * string,grecs_locus_t const * locus)579 grecs_string_convert(void *target, enum grecs_data_type type,
580 const char *string, grecs_locus_t const *locus)
581 {
582 switch (type) {
583 case grecs_type_void:
584 abort();
585
586 case grecs_type_null:
587 break;
588
589 case grecs_type_string:
590 *(char**)target = grecs_strdup(string);
591 break;
592
593 case grecs_type_short:
594 GETUNUM(string, short, *(short*)target, locus);
595 break;
596
597 case grecs_type_ushort:
598 GETUNUM(string, unsigned short, *(unsigned short*)target, locus);
599 break;
600
601 case grecs_type_bool:
602 return string_to_bool(string, (int*)target, locus);
603
604 case grecs_type_int:
605 GETSNUM(string, int, *(int*)target, locus);
606 break;
607
608 case grecs_type_uint:
609 GETUNUM(string, unsigned int, *(unsigned int*)target, locus);
610 break;
611
612 case grecs_type_long:
613 GETSNUM(string, long, *(long*)target, locus);
614 break;
615
616 case grecs_type_ulong:
617 GETUNUM(string, unsigned long, *(unsigned long*)target, locus);
618 break;
619
620 case grecs_type_size:
621 GETUNUM(string, size_t, *(size_t*)target, locus);
622 break;
623 /*FIXME
624 case grecs_type_off:
625 GETSNUM(string, off_t, *(off_t*)target, locus);
626 break;
627 */
628 case grecs_type_time:
629 /*FIXME: Use getdate */
630 GETUNUM(string, time_t, *(time_t*)target, locus);
631 break;
632
633 case grecs_type_ipv4:
634 if (inet_aton(string, (struct in_addr *)target)) {
635 grecs_error(locus, 0, _("%s: not a valid IP address"),
636 string);
637 return 1;
638 }
639 break;
640
641 case grecs_type_host:
642 if (string_to_host((struct in_addr *)target, string, locus)) {
643 grecs_error(locus, 0,
644 _("%s: not a valid IP address or hostname"),
645 string);
646 return 1;
647 }
648 break;
649
650 case grecs_type_sockaddr:
651 #if GRECS_SOCKADDR_LIST
652 return grecs_str_to_sockaddr((struct grecs_sockaddr **)target,
653 string, grecs_sockaddr_hints,
654 locus);
655 #else
656 return string_to_sockaddr((struct grecs_sockaddr *)target, string,
657 locus);
658 #endif
659
660 case grecs_type_cidr:
661 return grecs_str_to_cidr((struct grecs_cidr *)target, string, locus);
662
663 case grecs_type_section:
664 grecs_error(locus, 0,
665 _("invalid use of block statement"));
666 return 1;
667 }
668 return 0;
669 }
670
671 struct grecs_prop
672 {
673 size_t size;
674 int (*cmp)(const void *, const void *);
675 };
676
677 static int
string_cmp(const void * elt1,const void * elt2)678 string_cmp(const void *elt1, const void *elt2)
679 {
680 return strcmp((const char *)elt1,(const char *)elt2);
681 }
682
683 #define __grecs_name_cat__(a,b) a ## b
684 #define NUMCMP(type) __grecs_name_cat__(type,_cmp)
685 #define __DECL_NUMCMP(type,ctype) \
686 static int \
687 NUMCMP(type)(const void *elt1, const void *elt2) \
688 { \
689 return memcmp(elt1, elt2, sizeof(ctype)); \
690 }
691 #define DECL_NUMCMP(type) __DECL_NUMCMP(type,type)
692
693 DECL_NUMCMP(short)
DECL_NUMCMP(int)694 DECL_NUMCMP(int)
695 DECL_NUMCMP(long)
696 DECL_NUMCMP(size_t)
697 /*FIXME DECL_NUMCMP(off_t)*/
698 DECL_NUMCMP(time_t)
699 __DECL_NUMCMP(in_addr, struct in_addr)
700 __DECL_NUMCMP(grecs_sockaddr, struct grecs_sockaddr)
701
702 static int
703 cidr_cmp(const void *elt1, const void *elt2)
704 {
705 struct grecs_cidr const *cp1 = elt1, *cp2 = elt2;
706 return !(cp1->family == cp2->family
707 && cp1->len == cp2->len
708 && memcmp(cp1->address, cp2->address, cp1->len) == 0
709 && memcmp(cp1->netmask, cp2->netmask, cp1->len) == 0);
710 }
711
712 struct grecs_prop grecs_prop_tab[] = {
713 { 0, NULL }, /* grecs_type_void */
714 { sizeof(char*), string_cmp }, /* grecs_type_string */
715 { sizeof(short), NUMCMP(short) }, /* grecs_type_short */
716 { sizeof(unsigned short), NUMCMP(short) }, /* grecs_type_ushort */
717 { sizeof(int), NUMCMP(int) }, /* grecs_type_int */
718 { sizeof(unsigned int), NUMCMP(int) }, /* grecs_type_uint */
719 { sizeof(long), NUMCMP(long) }, /* grecs_type_long */
720 { sizeof(unsigned long), NUMCMP(long) }, /* grecs_type_ulong */
721 { sizeof(size_t), NUMCMP(size_t) }, /* grecs_type_size */
722 #if 0
723 FIXME
724 { sizeof(off_t), NUMCMP(off_t) }, /* grecs_type_off */
725 #endif
726 { sizeof(time_t), NUMCMP(time_t) }, /* grecs_type_time */
727 { sizeof(int), NUMCMP(int) }, /* grecs_type_bool */
728 { sizeof(struct in_addr), NUMCMP(in_addr) }, /* grecs_type_ipv4 */
729 { sizeof(struct grecs_cidr), cidr_cmp }, /* grecs_type_cidr */
730 { sizeof(struct in_addr), NUMCMP(in_addr) }, /* grecs_type_host */
731 { sizeof(struct grecs_sockaddr), NUMCMP(grecs_sockaddr) },
732 /* grecs_type_sockaddr */
733 { 0, NULL }, /* grecs_type_section */
734 { 0, NULL } /* grecs_type_null */
735 };
736 #define grecs_prop_count \
737 (sizeof(grecs_prop_tab) / sizeof(grecs_prop_tab[0]))
738
739 void
grecs_process_ident(struct grecs_keyword * kwp,grecs_value_t * value,void * base,grecs_locus_t * locus)740 grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value,
741 void *base, grecs_locus_t *locus)
742 {
743 void *target;
744
745 if (!kwp)
746 return;
747
748 target = target_ptr(kwp, (char *) base);
749
750 if (kwp->callback) {
751 #if GRECS_TREE_API
752 struct grecs_node node = { 0 };
753 node.locus = *locus;
754 node.v.value = value;
755 node.ident = (char*) kwp->ident;
756 kwp->callback(grecs_callback_set_value,
757 &node,
758 target,
759 &kwp->callback_data);
760 #else
761 kwp->callback(grecs_callback_set_value,
762 locus,
763 target,
764 value,
765 &kwp->callback_data);
766 #endif
767 } else if (kwp->type == grecs_type_void || target == NULL)
768 return;
769 else if (!value) {
770 grecs_error(locus, 0, "%s has no value", kwp->ident);
771 return;
772 } else if (value->type == GRECS_TYPE_ARRAY) {
773 grecs_error(locus, 0,
774 _("too many arguments to `%s'; missing semicolon?"),
775 kwp->ident);
776 return;
777 } else if (value->type == GRECS_TYPE_LIST) {
778 if (kwp->flags & GRECS_LIST) {
779 struct grecs_list_entry *ep;
780 enum grecs_data_type type = kwp->type;
781 int num = 1;
782 struct grecs_list *list;
783 size_t size;
784
785 if (type >= grecs_prop_count
786 || (size = grecs_prop_tab[type].size) == 0) {
787 grecs_error(locus, 0,
788 _("INTERNAL ERROR at %s:%d: "
789 "unhandled data type %d"),
790 __FILE__, __LINE__, type);
791 abort();
792 }
793
794 list = _grecs_simple_list_create(
795 type == grecs_type_string);
796 list->cmp = grecs_prop_tab[type].cmp;
797
798 for (ep = value->v.list->head; ep; ep = ep->next) {
799 const grecs_value_t *vp = ep->data;
800
801 if (vp->type != GRECS_TYPE_STRING)
802 grecs_error(&vp->locus, 0,
803 _("%s: incompatible data type in list item #%d"),
804 kwp->ident, num);
805 else if (type == grecs_type_string)
806 grecs_list_append(list,
807 grecs_strdup(vp->v.string));
808 else {
809 void *ptr = grecs_malloc(size);
810 if (grecs_string_convert(ptr,
811 type,
812 vp->v.string,
813 &vp->locus)
814 == 0)
815 grecs_list_append(list, ptr);
816 else
817 grecs_free(ptr);
818 }
819 }
820 *(struct grecs_list**)target = list;
821 } else {
822 grecs_error(locus, 0,
823 _("incompatible data type for `%s'"),
824 kwp->ident);
825 return;
826 }
827 } else if (kwp->flags & GRECS_LIST) {
828 struct grecs_list *list;
829 enum grecs_data_type type = kwp->type;
830 size_t size;
831 void *ptr;
832
833 if (type >= grecs_prop_count
834 || (size = grecs_prop_tab[type].size) == 0) {
835 grecs_error(locus, 0,
836 _("INTERNAL ERROR at %s:%d: unhandled data type %d"),
837 __FILE__, __LINE__, type);
838 abort();
839 }
840
841 list = _grecs_simple_list_create(1);
842 list->cmp = grecs_prop_tab[type].cmp;
843 if (type == grecs_type_string)
844 grecs_list_append(list,
845 grecs_strdup(value->v.string));
846 else {
847 ptr = grecs_malloc(size);
848 if (grecs_string_convert(ptr, type,
849 value->v.string,
850 &value->locus)) {
851 grecs_free(ptr);
852 grecs_list_free(list);
853 return;
854 }
855 grecs_list_append(list, ptr);
856 }
857 *(struct grecs_list**)target = list;
858 } else {
859 if (kwp->type == grecs_type_string
860 && !(kwp->flags & GRECS_CONST))
861 free(*(char**)target);
862 grecs_string_convert(target, kwp->type,
863 value->v.string,
864 &value->locus);
865 }
866 kwp->flags &= ~GRECS_CONST;
867 }
868
869
870 struct nodeproc_closure {
871 struct grecs_keyword *cursect;
872 struct grecs_list *sections;
873 int flags;
874 };
875 #define CURRENT_BASE(clos) \
876 ((char*)((clos)->cursect ? (clos)->cursect->callback_data : NULL))
877
878 static void
stmt_begin(struct nodeproc_closure * clos,struct grecs_keyword * kwp,struct grecs_node * node)879 stmt_begin(struct nodeproc_closure *clos,
880 struct grecs_keyword *kwp, struct grecs_node *node)
881 {
882 void *target;
883
884 grecs_list_push(clos->sections, clos->cursect);
885 if (kwp) {
886 target = target_ptr(kwp, CURRENT_BASE(clos));
887 clos->cursect = kwp;
888 if (kwp->callback) {
889 #if GRECS_TREE_API
890 if (kwp->callback(grecs_callback_section_begin,
891 node,
892 target,
893 &kwp->callback_data))
894 #else
895 if (kwp->callback(grecs_callback_section_begin,
896 &node->locus,
897 target,
898 node->v.value,
899 &kwp->callback_data))
900 #endif
901 clos->cursect = &fake;
902 } else
903 kwp->callback_data = target;
904 } else
905 /* install an "ignore-all" section */
906 clos->cursect = kwp;
907 }
908
909 static void
stmt_end(struct nodeproc_closure * clos,struct grecs_node * node)910 stmt_end(struct nodeproc_closure *clos, struct grecs_node *node)
911 {
912 grecs_callback_fn callback = NULL;
913 void *dataptr = NULL;
914 struct grecs_keyword *kwp = clos->cursect;
915
916 if (clos->cursect && clos->cursect->callback) {
917 callback = clos->cursect->callback;
918 dataptr = &clos->cursect->callback_data;
919 }
920
921 clos->cursect = (struct grecs_keyword *)grecs_list_pop(clos->sections);
922 if (!clos->cursect)
923 abort();
924 if (callback)
925 #if GRECS_TREE_API
926 callback(grecs_callback_section_end,
927 node,
928 kwp ? target_ptr(kwp, CURRENT_BASE(clos)) : NULL,
929 dataptr);
930 #else
931 callback(grecs_callback_section_end,
932 &node->locus,
933 kwp ? target_ptr(kwp, CURRENT_BASE(clos)) : NULL,
934 NULL,
935 dataptr);
936 #endif
937 if (kwp)
938 kwp->callback_data = NULL;
939 }
940
941 static enum grecs_tree_recurse_res
nodeproc(enum grecs_tree_recurse_op op,struct grecs_node * node,void * data)942 nodeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data)
943 {
944 struct nodeproc_closure *clos = data;
945 struct grecs_keyword *kwp;
946
947 switch (op) {
948 case grecs_tree_recurse_set:
949 kwp = find_keyword(clos->cursect, node);
950 if (!kwp)
951 return grecs_tree_recurse_skip;
952 grecs_process_ident(kwp, node->v.value, CURRENT_BASE(clos),
953 &node->idloc);
954 break;
955
956 case grecs_tree_recurse_pre:
957 kwp = find_keyword(clos->cursect, node);
958 if (!kwp)
959 return grecs_tree_recurse_skip;
960 stmt_begin(clos, kwp, node);
961 break;
962
963 case grecs_tree_recurse_post:
964 stmt_end(clos, node);
965 break;
966 }
967 return grecs_tree_recurse_ok;
968 }
969
970 int
grecs_tree_process(struct grecs_node * node,struct grecs_keyword * kwd)971 grecs_tree_process(struct grecs_node *node, struct grecs_keyword *kwd)
972 {
973 int rc;
974 struct nodeproc_closure clos;
975 struct grecs_keyword config_keywords;
976
977 memset(&config_keywords, 0, sizeof(config_keywords));
978 config_keywords.kwd = kwd;
979 clos.cursect = &config_keywords;
980 clos.sections = grecs_list_create();
981 if (node->type == grecs_node_root)
982 node = node->down;
983 rc = grecs_tree_recurse(node, nodeproc, &clos);
984 grecs_list_free(clos.sections);
985 return rc;
986 }
987
988
989 int
grecs_node_eq(struct grecs_node * a,struct grecs_node * b)990 grecs_node_eq(struct grecs_node *a, struct grecs_node *b)
991 {
992 if (a->type != b->type)
993 return 1;
994 if (a->type == grecs_node_root)
995 return 0;
996 if (strcmp(a->ident, b->ident))
997 return 1;
998 if (a->type == grecs_node_block &&
999 !grecs_value_eq(a->v.value, b->v.value))
1000 return 1;
1001 return 0;
1002 }
1003
1004 static void
free_value_entry(void * ptr)1005 free_value_entry(void *ptr)
1006 {
1007 struct grecs_value *v = ptr;
1008 grecs_value_free(v);
1009 }
1010
1011 struct grecs_list *
grecs_value_list_create()1012 grecs_value_list_create()
1013 {
1014 struct grecs_list *list = grecs_list_create();
1015 list->free_entry = free_value_entry;
1016 return list;
1017 }
1018
1019 static void
value_to_list(struct grecs_value * val)1020 value_to_list(struct grecs_value *val)
1021 {
1022 struct grecs_list *list;
1023 int i;
1024
1025 if (val->type == GRECS_TYPE_LIST)
1026 return;
1027 list = grecs_value_list_create();
1028 switch (val->type) {
1029 case GRECS_TYPE_STRING:
1030 grecs_list_append(list, grecs_value_ptr_from_static(val));
1031 break;
1032
1033 case GRECS_TYPE_ARRAY:
1034 for (i = 0; i < val->v.arg.c; i++)
1035 grecs_list_append(list, val->v.arg.v[i]);
1036 }
1037 val->type = GRECS_TYPE_LIST;
1038 val->v.list = list;
1039 }
1040
1041 static void
value_to_array(struct grecs_value * val)1042 value_to_array(struct grecs_value *val)
1043 {
1044 if (val->type == GRECS_TYPE_ARRAY)
1045 return;
1046 else {
1047 struct grecs_value **vp;
1048 vp = grecs_calloc(1, sizeof(*vp));
1049 vp[0] = grecs_value_ptr_from_static(val);
1050 val->type = GRECS_TYPE_ARRAY;
1051 val->v.arg.c = 1;
1052 val->v.arg.v = vp;
1053 }
1054 }
1055
1056 static void
array_add(struct grecs_value * vx,struct grecs_value * vy)1057 array_add(struct grecs_value *vx, struct grecs_value *vy)
1058 {
1059 size_t i;
1060
1061 vx->v.arg.v = grecs_realloc(vx->v.arg.v,
1062 (vx->v.arg.c + vy->v.arg.c) *
1063 sizeof(vx->v.arg.v[0]));
1064 for (i = 0; i < vy->v.arg.c; i++)
1065 vx->v.arg.v[i + vy->v.arg.c] = vy->v.arg.v[i];
1066 grecs_free(vy->v.arg.v);
1067 vy->v.arg.v = NULL;
1068 vy->v.arg.c = 0;
1069 }
1070
1071 static void
node_aggregate_stmt(struct grecs_node * dst,struct grecs_node * src,int islist)1072 node_aggregate_stmt(struct grecs_node *dst, struct grecs_node *src, int islist)
1073 {
1074 if (islist) {
1075 struct grecs_list *t;
1076 /* Coerce both arguments to lists */
1077 value_to_list(dst->v.value);
1078 value_to_list(src->v.value);
1079 /* Aggregate two lists in order */
1080 grecs_list_add(src->v.value->v.list, dst->v.value->v.list);
1081 /* Swap them */
1082 t = dst->v.value->v.list;
1083 dst->v.value->v.list = src->v.value->v.list;
1084 src->v.value->v.list = t;
1085 } else {
1086 value_to_array(dst->v.value);
1087 value_to_array(src->v.value);
1088 array_add(dst->v.value, src->v.value);
1089 }
1090 }
1091
1092 static void
node_merge_stmt(struct grecs_node * to_node,struct grecs_node * from_node,struct grecs_keyword * kwp,int flags)1093 node_merge_stmt(struct grecs_node *to_node, struct grecs_node *from_node,
1094 struct grecs_keyword *kwp, int flags)
1095 {
1096 if (kwp &&
1097 (flags & GRECS_AGGR) ^ (kwp->flags & GRECS_AGGR) &&
1098 ((kwp->flags & GRECS_LIST) || kwp->callback))
1099 node_aggregate_stmt(to_node, from_node,
1100 kwp->flags & GRECS_LIST);
1101 else {
1102 grecs_value_free(from_node->v.value);
1103 from_node->v.value = NULL;
1104 }
1105 }
1106
1107 static void
node_merge_block(struct grecs_node * to_node,struct grecs_node * from_node,struct grecs_keyword * kwp)1108 node_merge_block(struct grecs_node *to_node, struct grecs_node *from_node,
1109 struct grecs_keyword *kwp)
1110 {
1111 struct grecs_node *sp;
1112
1113 if (!from_node->down)
1114 return;
1115 for (sp = from_node->down; ; sp = sp->next) {
1116 sp->up = to_node;
1117 if (!sp->next)
1118 break;
1119 }
1120
1121 sp->next = to_node->down;
1122 to_node->down->prev = sp;
1123
1124 to_node->down = from_node->down;
1125 from_node->down = NULL;
1126 }
1127
1128 static int
node_reduce(struct grecs_node * node,struct grecs_keyword * kwp,int flags)1129 node_reduce(struct grecs_node *node, struct grecs_keyword *kwp, int flags)
1130 {
1131 struct grecs_node *p;
1132
1133 for (p = node->next; p; p = p->next)
1134 if (grecs_node_eq(p, node) == 0)
1135 break;
1136 if (p) {
1137 switch (node->type) {
1138 case grecs_node_root:
1139 return 0;
1140 case grecs_node_stmt:
1141 node_merge_stmt(p, node, kwp, flags);
1142 break;
1143 case grecs_node_block:
1144 node_merge_block(p, node, kwp);
1145 break;
1146 }
1147 grecs_node_unlink(node);
1148 grecs_node_free(node);
1149 return 1;
1150 }
1151 return 0;
1152 }
1153
1154 static enum grecs_tree_recurse_res
reduceproc(enum grecs_tree_recurse_op op,struct grecs_node * node,void * data)1155 reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data)
1156 {
1157 struct nodeproc_closure *clos = data;
1158
1159 if (op == grecs_tree_recurse_post) {
1160 if (clos->sections)
1161 clos->cursect = (struct grecs_keyword *)
1162 grecs_list_pop(clos->sections);
1163 } else {
1164 struct grecs_keyword *kwp = NULL;
1165 if (clos->cursect) {
1166 kwp = find_keyword(clos->cursect, node);
1167 if (!kwp)
1168 return grecs_tree_recurse_skip;
1169 if (kwp->flags & GRECS_INAC)
1170 return grecs_tree_recurse_skip;
1171 if (!(kwp->flags & GRECS_MULT) &&
1172 node_reduce(node, kwp, clos->flags))
1173 return grecs_tree_recurse_skip;
1174 if (op == grecs_tree_recurse_pre) {
1175 grecs_list_push(clos->sections, clos->cursect);
1176 clos->cursect = kwp;
1177 }
1178 } else if (node_reduce(node, kwp, clos->flags))
1179 return grecs_tree_recurse_skip;
1180 }
1181 return grecs_tree_recurse_ok;
1182 }
1183
1184 int
grecs_tree_reduce(struct grecs_node * node,struct grecs_keyword * kwd,int flags)1185 grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd,
1186 int flags)
1187 {
1188 int rc;
1189 struct nodeproc_closure clos;
1190 struct grecs_keyword config_keywords;
1191
1192 memset(&config_keywords, 0, sizeof(config_keywords));
1193 config_keywords.kwd = kwd;
1194 if (kwd) {
1195 clos.cursect = &config_keywords;
1196 clos.sections = grecs_list_create();
1197 } else {
1198 clos.cursect = NULL;
1199 clos.sections = NULL;
1200 }
1201 clos.flags = flags;
1202 rc = grecs_tree_recurse(node->down, reduceproc, &clos);
1203 grecs_list_free(clos.sections);
1204 return rc;
1205 }
1206
1207
1208 struct grecs_node *
grecs_tree_first_node(struct grecs_node * tree)1209 grecs_tree_first_node(struct grecs_node *tree)
1210 {
1211 if (tree->type == grecs_node_root)
1212 return tree->down;
1213 return tree;
1214 }
1215
1216 struct grecs_node *
grecs_next_node(struct grecs_node * node)1217 grecs_next_node(struct grecs_node *node)
1218 {
1219 if (!node)
1220 return NULL;
1221 if (node->down)
1222 return node->down;
1223 while (!node->next) {
1224 node = node->up;
1225 if (!node || node->type == grecs_node_root)
1226 return NULL;
1227 }
1228 return node->next;
1229 }
1230