parse.c revision 1.7 1 /* $NetBSD: parse.c,v 1.7 2008/05/12 21:54:51 dyoung Exp $ */
2
3 /*-
4 * Copyright (c) 2008 David Young. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <err.h>
29 #include <errno.h>
30 #include <limits.h>
31 #include <netdb.h>
32 #include <stddef.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <arpa/inet.h>
38 #include <sys/param.h>
39 #include <net/if.h>
40 #include <net/if_dl.h>
41 #include <netatalk/at.h>
42 #include <netiso/iso.h>
43
44 #include "env.h"
45 #include "parse.h"
46 #include "util.h"
47
48 #define dbg_warnx(__fmt, ...) /* empty */
49
50 static int parser_default_init(struct parser *);
51 static int pbranch_init(struct parser *);
52 static int pkw_init(struct parser *);
53
54 static int pterm_match(const struct parser *, const struct match *,
55 struct match *, int, const char *);
56
57 static int paddr_match(const struct parser *, const struct match *,
58 struct match *, int, const char *);
59
60 static int pbranch_match(const struct parser *, const struct match *,
61 struct match *, int, const char *);
62
63 static int piface_match(const struct parser *, const struct match *,
64 struct match *, int, const char *);
65
66 static int pstr_match(const struct parser *, const struct match *,
67 struct match *, int, const char *);
68
69 static int pinteger_match(const struct parser *, const struct match *,
70 struct match *, int, const char *);
71
72 static int pkw_match(const struct parser *, const struct match *,
73 struct match *, int, const char *);
74
75 const struct parser_methods pterm_methods = {
76 .pm_match = pterm_match
77 , .pm_init = NULL
78 };
79
80 const struct parser_methods pstr_methods = {
81 .pm_match = pstr_match
82 , .pm_init = parser_default_init
83 };
84
85 const struct parser_methods pinteger_methods = {
86 .pm_match = pinteger_match
87 , .pm_init = parser_default_init
88 };
89
90 const struct parser_methods paddr_methods = {
91 .pm_match = paddr_match
92 , .pm_init = parser_default_init
93 };
94
95 const struct parser_methods piface_methods = {
96 .pm_match = piface_match
97 , .pm_init = parser_default_init
98 };
99
100 const struct parser_methods pbranch_methods = {
101 .pm_match = pbranch_match
102 , .pm_init = pbranch_init
103 };
104
105 const struct parser_methods pkw_methods = {
106 .pm_match = pkw_match
107 , .pm_init = pkw_init
108 };
109
110 static int
111 match_setenv(const struct match *im, struct match *om, const char *key,
112 prop_object_t o)
113 {
114 if (im == NULL)
115 om->m_env = prop_dictionary_create();
116 else
117 om->m_env = prop_dictionary_copy(im->m_env);
118
119 if (om->m_env == NULL)
120 goto delobj;
121
122 if (key != NULL && !prop_dictionary_set(om->m_env, key, o))
123 goto deldict;
124
125 if (o != NULL)
126 prop_object_release((prop_object_t)o);
127
128 return 0;
129 deldict:
130 prop_object_release((prop_object_t)om->m_env);
131 om->m_env = NULL;
132 delobj:
133 prop_object_release((prop_object_t)o);
134 errno = ENOMEM;
135 return -1;
136 }
137
138 int
139 pstr_match(const struct parser *p, const struct match *im, struct match *om,
140 int argidx, const char *arg)
141 {
142 prop_object_t o;
143 const struct pstr *ps = (const struct pstr *)p;
144 uint8_t buf[128];
145 int len;
146
147 if (arg == NULL) {
148 errno = EINVAL;
149 return -1;
150 }
151
152 len = (int)sizeof(buf);
153 if (get_string(arg, NULL, buf, &len) == NULL) {
154 errno = EINVAL;
155 return -1;
156 }
157
158 o = (prop_object_t)prop_data_create_data(buf, len);
159
160 if (o == NULL) {
161 errno = ENOMEM;
162 return -1;
163 }
164
165 if (match_setenv(im, om, ps->ps_key, o) == -1)
166 return -1;
167
168 om->m_argidx = argidx;
169 om->m_parser = p;
170 om->m_nextparser = p->p_nextparser;
171
172 return 0;
173 }
174
175 int
176 pinteger_match(const struct parser *p, const struct match *im, struct match *om,
177 int argidx, const char *arg)
178 {
179 prop_object_t o;
180 const struct pinteger *pi = (const struct pinteger *)p;
181 char *end;
182 int64_t val;
183
184 if (arg == NULL) {
185 errno = EINVAL;
186 return -1;
187 }
188
189 val = strtoimax(arg, &end, pi->pi_base);
190 if ((val == INTMAX_MIN || val == INTMAX_MAX) && errno == ERANGE)
191 return -1;
192
193 if (*end != '\0') {
194 errno = EINVAL;
195 return -1;
196 }
197
198 if (val < pi->pi_min || val > pi->pi_max) {
199 errno = ERANGE;
200 return -1;
201 }
202
203 o = (prop_object_t)prop_number_create_integer(val);
204
205 if (o == NULL) {
206 errno = ENOMEM;
207 return -1;
208 }
209
210 if (match_setenv(im, om, pi->pi_key, o) == -1)
211 return -1;
212
213 om->m_argidx = argidx;
214 om->m_parser = p;
215 om->m_nextparser = p->p_nextparser;
216
217 return 0;
218 }
219
220 static int
221 parse_linkaddr(const char *addr, struct sockaddr_storage *ss)
222 {
223 static const size_t maxlen =
224 sizeof(*ss) - offsetof(struct sockaddr_dl, sdl_data[0]);
225 enum {
226 LLADDR_S_INITIAL = 0,
227 LLADDR_S_ONE_OCTET = 1,
228 LLADDR_S_TWO_OCTETS = 2,
229 LLADDR_S_COLON = 3
230 } state = LLADDR_S_INITIAL;
231 uint8_t octet = 0, val;
232 struct sockaddr_dl *sdl;
233 const char *p;
234 int i;
235
236 memset(ss, 0, sizeof(*ss));
237 ss->ss_family = AF_LINK;
238 sdl = (struct sockaddr_dl *)ss;
239
240 for (i = 0, p = addr; i < maxlen; p++) {
241 dbg_warnx("%s.%d: *p == %c, state %d", __func__, __LINE__, *p,
242 state);
243 if (*p == '\0') {
244 dbg_warnx("%s.%d", __func__, __LINE__);
245 if (state != LLADDR_S_ONE_OCTET &&
246 state != LLADDR_S_TWO_OCTETS)
247 return -1;
248 dbg_warnx("%s.%d", __func__, __LINE__);
249 sdl->sdl_data[i++] = octet;
250 sdl->sdl_len =
251 offsetof(struct sockaddr_dl, sdl_data[i]);
252 sdl->sdl_alen = i;
253 return 0;
254 }
255 if (*p == ':') {
256 dbg_warnx("%s.%d", __func__, __LINE__);
257 if (state != LLADDR_S_ONE_OCTET &&
258 state != LLADDR_S_TWO_OCTETS)
259 return -1;
260 dbg_warnx("%s.%d", __func__, __LINE__);
261 sdl->sdl_data[i++] = octet;
262 state = LLADDR_S_COLON;
263 continue;
264 }
265 if ('a' <= *p && *p <= 'f')
266 val = 10 + *p - 'a';
267 else if ('A' <= *p && *p <= 'F')
268 val = 10 + *p - 'A';
269 else if ('0' <= *p && *p <= '9')
270 val = *p - '0';
271 else
272 return -1;
273
274 dbg_warnx("%s.%d", __func__, __LINE__);
275 if (state == LLADDR_S_ONE_OCTET) {
276 state = LLADDR_S_TWO_OCTETS;
277 octet <<= 4;
278 octet |= val;
279 } else if (state != LLADDR_S_INITIAL && state != LLADDR_S_COLON)
280 return -1;
281 else {
282 state = LLADDR_S_ONE_OCTET;
283 octet = val;
284 }
285 dbg_warnx("%s.%d", __func__, __LINE__);
286 }
287 return -1;
288 }
289
290 static int
291 paddr_match(const struct parser *p, const struct match *im, struct match *om,
292 int argidx, const char *arg0)
293 {
294 unsigned int net, node;
295 int nread;
296 union {
297 struct sockaddr sa;
298 struct sockaddr_at sat;
299 struct sockaddr_iso siso;
300 struct sockaddr_in sin;
301 struct sockaddr_storage ss;
302 } u;
303 const struct paddr *pa = (const struct paddr *)p;
304 prop_data_t d;
305 prop_object_t o;
306 int64_t af0;
307 int af, rc;
308 struct paddr_prefix *pfx, *mask;
309 const struct sockaddr *sa = NULL;
310 struct addrinfo hints, *result = NULL;
311 char *arg, *end, *plen = NULL, *servname0;
312 const char *servname;
313 long prefixlen = -1;
314 size_t len;
315
316 if (arg0 == NULL) {
317 errno = EINVAL;
318 return -1;
319 }
320
321 if (pa->pa_activator != NULL &&
322 prop_dictionary_get(im->m_env, pa->pa_activator) == NULL)
323 return -1;
324
325 if (pa->pa_deactivator != NULL &&
326 prop_dictionary_get(im->m_env, pa->pa_deactivator) != NULL)
327 return -1;
328
329 if (!prop_dictionary_get_int64(im->m_env, "af", &af0))
330 af = AF_UNSPEC;
331 else
332 af = af0;
333
334 switch (af) {
335 case AF_UNSPEC:
336 case AF_INET:
337 case AF_INET6:
338 if ((arg = strdup(arg0)) == NULL)
339 return -1;
340
341 servname0 = arg;
342 (void)strsep(&servname0, ",");
343 servname = (servname0 == NULL) ? "0" : servname0;
344
345 if (pa->pa_maskkey == NULL)
346 ;
347 else if ((plen = strrchr(arg, '/')) != NULL)
348 *plen++ = '\0';
349
350 memset(&u, 0, sizeof(u));
351
352 memset(&hints, 0, sizeof(hints));
353
354 hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
355 hints.ai_family = af;
356 hints.ai_socktype = SOCK_DGRAM;
357
358 for (;;) {
359 rc = getaddrinfo(arg, servname, &hints, &result);
360 if (rc == 0) {
361 if (result->ai_next == NULL)
362 sa = result->ai_addr;
363 else
364 errno = EMLINK;
365 break;
366 } else if ((hints.ai_flags & AI_NUMERICHOST) != 0 &&
367 (af == AF_INET || af == AF_UNSPEC) &&
368 inet_aton(arg, &u.sin.sin_addr) == 1) {
369 u.sin.sin_family = AF_INET;
370 u.sin.sin_len = sizeof(u.sin);
371 sa = &u.sa;
372 break;
373 } else if ((hints.ai_flags & AI_NUMERICHOST) == 0 ||
374 rc != EAI_NONAME) {
375 errno = ENOENT;
376 break;
377 }
378 hints.ai_flags &= ~AI_NUMERICHOST;
379 }
380
381
382 if (plen == NULL)
383 prefixlen = -1;
384 else {
385 prefixlen = strtol(plen, &end, 10);
386 if (end != NULL && *end != '\0')
387 sa = NULL;
388 if (prefixlen < 0 || prefixlen >= UINT8_MAX) {
389 errno = ERANGE;
390 sa = NULL;
391 }
392 }
393
394 free(arg);
395 if (sa != NULL || af != AF_UNSPEC)
396 break;
397 /*FALLTHROUGH*/
398 case AF_APPLETALK:
399 if (sscanf(arg0, "%u.%u%n", &net, &node, &nread) == 2 &&
400 net != 0 && net <= 0xffff && node != 0 && node <= 0xfe &&
401 arg0[nread] == '\0') {
402 u.sat.sat_family = AF_APPLETALK;
403 u.sat.sat_len = sizeof(u.sat);
404 u.sat.sat_addr.s_net = htons(net);
405 u.sat.sat_addr.s_node = node;
406 sa = &u.sa;
407 }
408 if (af != AF_UNSPEC)
409 break;
410 /*FALLTHROUGH*/
411 case AF_ISO:
412 u.siso.siso_len = sizeof(u.siso);
413 u.siso.siso_family = AF_ISO;
414 /* XXX iso_addr(3) matches ANYTHING! */
415 u.siso.siso_addr = *iso_addr(arg0);
416 sa = &u.sa;
417 break;
418 case AF_LINK:
419 if (parse_linkaddr(arg0, &u.ss) == -1)
420 sa = NULL;
421 else
422 sa = &u.sa;
423 break;
424 }
425
426 if (sa == NULL)
427 return -1;
428
429 len = offsetof(struct paddr_prefix, pfx_addr) + sa->sa_len;
430
431 if ((pfx = malloc(len)) == NULL)
432 return -1;
433
434 #if 0
435 {
436 int i;
437
438 for (i = 0; i < sa->sa_len; i++)
439 printf(" %02x", ((const uint8_t *)sa)[i]);
440 printf("\n");
441 }
442 #endif
443
444 pfx->pfx_len = (int16_t)prefixlen;
445 memcpy(&pfx->pfx_addr, sa, sa->sa_len);
446 af = sa->sa_family;
447
448 if (result != NULL)
449 freeaddrinfo(result);
450
451 o = (prop_object_t)prop_data_create_data(pfx, len);
452
453 free(pfx);
454
455 if (o == NULL)
456 return -1;
457
458 if (match_setenv(im, om, pa->pa_addrkey, o) == -1)
459 return -1;
460
461 if (pa->pa_maskkey != NULL && plen != NULL) {
462 size_t masklen;
463
464 if ((mask = prefixlen_to_mask(af, prefixlen)) == NULL) {
465 err(EXIT_FAILURE, "%s: prefixlen_to_mask(%d, %ld)",
466 __func__, af, prefixlen);
467 return -1;
468 }
469
470 masklen = offsetof(struct paddr_prefix, pfx_addr) +
471 mask->pfx_addr.sa_len;
472
473 d = prop_data_create_data(mask, masklen);
474 free(mask);
475
476 if (d == NULL) {
477 err(EXIT_FAILURE, "%s: prop_data_create_data",
478 __func__);
479 return -1;
480 }
481
482 rc = prop_dictionary_set(om->m_env, pa->pa_maskkey,
483 (prop_object_t)d) ? 0 : -1;
484
485 prop_object_release((prop_object_t)d);
486
487 if (rc != 0) {
488 err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
489 return rc;
490 }
491 }
492
493 om->m_argidx = argidx;
494 om->m_parser = p;
495 om->m_nextparser = p->p_nextparser;
496 return 0;
497 }
498
499 static int
500 pterm_match(const struct parser *p, const struct match *im,
501 struct match *om, int argidx, const char *arg)
502 {
503 const struct pterm *pt = (const struct pterm *)p;
504 prop_bool_t b;
505
506 if (arg != NULL) {
507 errno = EINVAL;
508 return -1;
509 }
510 b = prop_bool_create(true);
511
512 if (match_setenv(im, om, pt->pt_key, (prop_object_t)b) == -1)
513 return -1;
514
515 om->m_argidx = argidx;
516 om->m_parser = p;
517 om->m_nextparser = NULL;
518 return 0;
519 }
520
521 static int
522 piface_match(const struct parser *p, const struct match *im,
523 struct match *om, int argidx, const char *arg)
524 {
525 const struct piface *pif = (const struct piface *)p;
526 prop_object_t o;
527
528 if (arg == NULL || strlen(arg) > IFNAMSIZ) {
529 errno = EINVAL;
530 return -1;
531 }
532
533 if ((o = (prop_object_t)prop_string_create_cstring(arg)) == NULL) {
534 errno = ENOMEM;
535 return -1;
536 }
537
538 if (match_setenv(im, om, pif->pif_key, o) == -1)
539 return -1;
540
541 om->m_argidx = argidx;
542 om->m_parser = p;
543 om->m_nextparser = p->p_nextparser;
544 return 0;
545 }
546
547 static void
548 match_cleanup(struct match *dst)
549 {
550 if (dst->m_env != NULL)
551 prop_object_release((prop_object_t)dst->m_env);
552 memset(dst, 0, sizeof(*dst));
553 }
554
555 static void
556 match_copy(struct match *dst, const struct match *src)
557 {
558 match_cleanup(dst);
559
560 prop_object_retain((prop_object_t)src->m_env);
561 *dst = *src;
562 }
563
564 static int
565 pbranch_match(const struct parser *p, const struct match *im,
566 struct match *om, int argidx, const char *arg)
567 {
568 const struct parser *nextp;
569 struct branch *b;
570 const struct pbranch *pb = (const struct pbranch *)p;
571 struct match tmpm;
572 int nforbid = 0, nmatch = 0, rc;
573 parser_match_t matchfunc;
574
575 memset(&tmpm, 0, sizeof(tmpm));
576
577 SIMPLEQ_FOREACH(b, &pb->pb_branches, b_next) {
578 dbg_warnx("%s: b->b_nextparser %p", __func__,
579 (const void *)b->b_nextparser);
580 nextp = b->b_nextparser;
581 if (nextp == NULL) {
582 if (arg == NULL) {
583 nmatch++;
584 match_setenv(im, om, NULL, NULL);
585 om->m_nextparser = NULL;
586 om->m_parser = p;
587 om->m_argidx = argidx;
588 }
589 continue;
590 }
591 matchfunc = nextp->p_methods->pm_match;
592 rc = (*matchfunc)(nextp, im, &tmpm, argidx, arg);
593 if (rc == 0) {
594 match_copy(om, &tmpm);
595 match_cleanup(&tmpm);
596 nmatch++;
597 dbg_warnx("%s: branch %s ok", __func__, nextp->p_name);
598 if (pb->pb_match_first)
599 break;
600 } else if (rc == 1) {
601 nforbid++;
602 if (pb->pb_match_first)
603 break;
604 } else {
605 dbg_warnx("%s: fail branch %s", __func__,
606 nextp->p_name);
607 }
608 }
609 switch (nmatch) {
610 case 0:
611 errno = ENOENT;
612 return (nforbid == 0) ? -1 : 1;
613 case 1:
614 dbg_warnx("%s: branch ok", __func__);
615 return 0;
616 default:
617 match_cleanup(om);
618 errno = EMLINK;
619 return -1;
620 }
621 }
622
623 static int
624 pkw_match(const struct parser *p, const struct match *im,
625 struct match *om, int argidx, const char *arg)
626 {
627 prop_object_t o = NULL;
628 struct kwinst *k;
629 union kwval *u = NULL;
630 const struct pkw *pk = (const struct pkw *)p;
631
632 if (arg == NULL) {
633 errno = EINVAL;
634 return -1;
635 }
636
637 SIMPLEQ_FOREACH(k, &pk->pk_keywords, k_next) {
638 if (k->k_act != NULL &&
639 prop_dictionary_get(im->m_env, k->k_act) == NULL)
640 continue;
641
642 if (k->k_neg && arg[0] == '-' &&
643 strcmp(k->k_word, arg + 1) == 0)
644 u = &k->k_negu;
645 else if (strcmp(k->k_word, arg) == 0)
646 u = &k->k_u;
647 else
648 continue;
649
650 if (k->k_altdeact != NULL &&
651 prop_dictionary_get(im->m_env, k->k_altdeact) != NULL)
652 return 1;
653
654 if (k->k_deact != NULL &&
655 prop_dictionary_get(im->m_env, k->k_deact) != NULL)
656 return 1;
657 break;
658 }
659 if (k == NULL) {
660 errno = ENOENT;
661 return -1;
662 }
663 switch (k->k_type) {
664 case KW_T_NONE:
665 break;
666 case KW_T_BOOL:
667 o = (prop_object_t)prop_bool_create(u->u_bool);
668 if (o == NULL)
669 goto err;
670 break;
671 case KW_T_NUM:
672 o = (prop_object_t)prop_number_create_integer(u->u_num);
673 if (o == NULL)
674 goto err;
675 break;
676 case KW_T_OBJ:
677 o = u->u_obj;
678 break;
679 case KW_T_STR:
680 o = (prop_object_t)prop_data_create_data_nocopy(u->u_str,
681 strlen(u->u_str));
682 if (o == NULL)
683 goto err;
684 break;
685 default:
686 errx(EXIT_FAILURE, "unknown keyword type %d", k->k_type);
687 }
688
689 if (match_setenv(im, om, (o == NULL) ? NULL : k->k_key, o) == -1)
690 return -1;
691
692 om->m_argidx = argidx;
693 om->m_parser = p;
694 om->m_nextparser = k->k_nextparser;
695 om->m_exec = k->k_exec;
696 return 0;
697 err:
698 errno = ENOMEM;
699 return -1;
700 }
701
702 struct paddr *
703 paddr_create(const char *name, parser_exec_t pexec, const char *addrkey,
704 const char *maskkey, struct parser *next)
705 {
706 struct paddr *pa;
707
708 if ((pa = calloc(sizeof(*pa), 1)) == NULL)
709 return NULL;
710
711 pa->pa_parser.p_methods = &paddr_methods;
712 pa->pa_parser.p_exec = pexec;
713 pa->pa_parser.p_name = name;
714 pa->pa_parser.p_nextparser = next;
715
716 pa->pa_addrkey = addrkey;
717 pa->pa_maskkey = maskkey;
718
719 return pa;
720 }
721
722 struct piface *
723 piface_create(const char *name, parser_exec_t pexec, const char *defkey,
724 struct parser *defnext)
725 {
726 struct piface *pif;
727
728 if ((pif = calloc(sizeof(*pif), 1)) == NULL)
729 return NULL;
730
731 pif->pif_parser.p_methods = &piface_methods;
732 pif->pif_parser.p_exec = pexec;
733 pif->pif_parser.p_name = name;
734 pif->pif_parser.p_nextparser = defnext;
735
736 pif->pif_key = defkey;
737
738 return pif;
739 }
740
741 int
742 pbranch_setbranches(struct pbranch *pb, const struct branch *brs, size_t nbr)
743 {
744 struct branch *b;
745 int i;
746
747 dbg_warnx("%s: nbr %zu", __func__, nbr);
748
749 while ((b = SIMPLEQ_FIRST(&pb->pb_branches)) != NULL) {
750 SIMPLEQ_REMOVE_HEAD(&pb->pb_branches, b_next);
751 free(b);
752 }
753
754 for (i = 0; i < nbr; i++) {
755 if ((b = malloc(sizeof(*b))) == NULL)
756 goto err;
757 *b = brs[i];
758 dbg_warnx("%s: b->b_nextparser %p", __func__,
759 (const void *)b->b_nextparser);
760 SIMPLEQ_INSERT_TAIL(&pb->pb_branches, b, b_next);
761 }
762
763 return 0;
764 err:
765 while ((b = SIMPLEQ_FIRST(&pb->pb_branches)) != NULL) {
766 SIMPLEQ_REMOVE_HEAD(&pb->pb_branches, b_next);
767 free(b);
768 }
769 return -1;
770 }
771
772 static int
773 pbranch_init(struct parser *p)
774 {
775 struct branch *b;
776 struct pbranch *pb = (struct pbranch *)p;
777 struct parser *np;
778
779 if (pb->pb_nbrinit == 0 || !SIMPLEQ_EMPTY(&pb->pb_branches))
780 return 0;
781
782 if (pbranch_setbranches(pb, pb->pb_brinit, pb->pb_nbrinit) == -1)
783 return -1;
784
785 SIMPLEQ_FOREACH(b, &pb->pb_branches, b_next) {
786 np = b->b_nextparser;
787 if (np != NULL && parser_init(np) == -1)
788 return -1;
789 }
790 return 0;
791 }
792
793 struct pbranch *
794 pbranch_create(const char *name, const struct branch *brs, size_t nbr,
795 bool match_first)
796 {
797 struct pbranch *pb;
798
799 dbg_warnx("%s: nbr %zu", __func__, nbr);
800
801 if ((pb = calloc(1, sizeof(*pb))) == NULL)
802 return NULL;
803
804 pb->pb_parser.p_methods = &pbranch_methods;
805 pb->pb_parser.p_name = name;
806
807 SIMPLEQ_INIT(&pb->pb_branches);
808
809 if (pbranch_setbranches(pb, brs, nbr) == -1)
810 goto post_pb_err;
811
812 pb->pb_match_first = match_first;
813 return pb;
814 post_pb_err:
815 free(pb);
816 return NULL;
817 }
818
819 static int
820 parser_default_init(struct parser *p)
821 {
822 struct parser *np;
823
824 np = p->p_nextparser;
825 if (np != NULL && parser_init(np) == -1)
826 return -1;
827
828 return 0;
829 }
830
831 static int
832 pkw_setwords(struct pkw *pk, parser_exec_t defexec, const char *defkey,
833 const struct kwinst *kws, size_t nkw, struct parser *defnext)
834 {
835 struct kwinst *k;
836 int i;
837
838 for (i = 0; i < nkw; i++) {
839 if ((k = malloc(sizeof(*k))) == NULL)
840 goto post_pk_err;
841 *k = kws[i];
842 if (k->k_nextparser == NULL)
843 k->k_nextparser = defnext;
844 if (k->k_key == NULL)
845 k->k_key = defkey;
846 if (k->k_exec == NULL)
847 k->k_exec = defexec;
848 SIMPLEQ_INSERT_TAIL(&pk->pk_keywords, k, k_next);
849 }
850 return 0;
851
852 post_pk_err:
853 while ((k = SIMPLEQ_FIRST(&pk->pk_keywords)) != NULL) {
854 SIMPLEQ_REMOVE_HEAD(&pk->pk_keywords, k_next);
855 free(k);
856 }
857 return -1;
858 }
859
860 static int
861 pkw_init(struct parser *p)
862 {
863 struct kwinst *k;
864 struct pkw *pk = (struct pkw *)p;
865 struct parser *np;
866
867 if (pk->pk_nkwinit == 0 || !SIMPLEQ_EMPTY(&pk->pk_keywords))
868 return 0;
869 if (pkw_setwords(pk, pk->pk_execinit, pk->pk_keyinit, pk->pk_kwinit,
870 pk->pk_nkwinit, pk->pk_nextinit) == -1)
871 return -1;
872 SIMPLEQ_FOREACH(k, &pk->pk_keywords, k_next) {
873 np = k->k_nextparser;
874 if (np != NULL && parser_init(np) == -1)
875 return -1;
876 }
877 return 0;
878 }
879
880 struct pkw *
881 pkw_create(const char *name, parser_exec_t defexec, const char *defkey,
882 const struct kwinst *kws, size_t nkw, struct parser *defnext)
883 {
884 struct pkw *pk;
885
886 if ((pk = calloc(1, sizeof(*pk))) == NULL)
887 return NULL;
888
889 pk->pk_parser.p_methods = &pkw_methods;
890 pk->pk_parser.p_exec = defexec;
891 pk->pk_parser.p_name = name;
892
893 SIMPLEQ_INIT(&pk->pk_keywords);
894
895 if (pkw_setwords(pk, defexec, defkey, kws, nkw, defnext) == -1)
896 goto err;
897
898 return pk;
899 err:
900 free(pk);
901 return NULL;
902 }
903
904 int
905 parse(int argc, char **argv, const struct parser *p0, struct match *matches,
906 size_t *nmatch, int *narg)
907 {
908 int i, rc = 0;
909 struct match *lastm = NULL, *m = matches;
910 const struct parser *p = p0;
911
912 for (i = 0; i < argc && p != NULL; i++) {
913 if (m - matches >= *nmatch) {
914 errno = EFBIG;
915 rc = -1;
916 break;
917 }
918 rc = (*p->p_methods->pm_match)(p, lastm, m, i, argv[i]);
919 if (rc != 0)
920 goto out;
921 p = m->m_nextparser;
922 lastm = m++;
923 }
924 for (; m - matches < *nmatch && p != NULL; ) {
925 rc = (*p->p_methods->pm_match)(p, lastm, m, i, NULL);
926 if (rc != 0)
927 break;
928 p = m->m_nextparser;
929 lastm = m++;
930 }
931 out:
932 *nmatch = m - matches;
933 *narg = i;
934 return rc;
935 }
936
937 int
938 matches_exec(const struct match *matches, prop_dictionary_t xenv, size_t nmatch)
939 {
940 int i, rc = 0;
941 const struct match *m;
942 parser_exec_t pexec;
943 prop_dictionary_t d;
944
945 for (i = 0; i < nmatch; i++) {
946 m = &matches[i];
947 dbg_warnx("%s.%d: i %d", __func__, __LINE__, i);
948 pexec = (m->m_parser->p_exec != NULL)
949 ? m->m_parser->p_exec : m->m_exec;
950 if (pexec == NULL)
951 continue;
952 dbg_warnx("%s.%d: m->m_parser->p_name %s", __func__, __LINE__,
953 m->m_parser->p_name);
954 d = prop_dictionary_augment(m->m_env, xenv);
955 rc = (*pexec)(d, xenv);
956 prop_object_release((prop_object_t)d);
957 if (rc == -1)
958 break;
959 }
960 return rc;
961 }
962