parse.c revision 1.6 1 /* $NetBSD: parse.c,v 1.6 2008/05/12 00:39:18 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,
228 LLADDR_S_TWO_OCTETS,
229 LLADDR_S_COLON
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 if (*p == '\0') {
242 if (state != LLADDR_S_ONE_OCTET &&
243 state != LLADDR_S_TWO_OCTETS)
244 return -1;
245 sdl->sdl_data[i++] = octet;
246 sdl->sdl_len =
247 offsetof(struct sockaddr_dl, sdl_data[i]);
248 return 0;
249 }
250 if (*p == ':') {
251 if (state != LLADDR_S_ONE_OCTET &&
252 state != LLADDR_S_TWO_OCTETS)
253 return -1;
254 sdl->sdl_data[i++] = octet;
255 state = LLADDR_S_COLON;
256 }
257 if ('a' <= *p && *p <= 'f')
258 val = 10 + *p - 'a';
259 else if ('A' <= *p && *p <= 'F')
260 val = 10 + *p - 'A';
261 else if ('0' <= *p && *p <= '9')
262 val = *p - '0';
263 else
264 return -1;
265
266 if (state == LLADDR_S_ONE_OCTET) {
267 state = LLADDR_S_TWO_OCTETS;
268 octet <<= 4;
269 octet |= val;
270 } else if (state != LLADDR_S_INITIAL && state != LLADDR_S_COLON)
271 return -1;
272 else {
273 state = LLADDR_S_ONE_OCTET;
274 octet = val;
275 }
276 }
277 return -1;
278 }
279
280 static int
281 paddr_match(const struct parser *p, const struct match *im, struct match *om,
282 int argidx, const char *arg0)
283 {
284 unsigned int net, node;
285 int nread;
286 union {
287 struct sockaddr sa;
288 struct sockaddr_at sat;
289 struct sockaddr_iso siso;
290 struct sockaddr_in sin;
291 struct sockaddr_storage ss;
292 } u;
293 const struct paddr *pa = (const struct paddr *)p;
294 prop_data_t d;
295 prop_object_t o;
296 int64_t af0;
297 int af, rc;
298 struct paddr_prefix *pfx, *mask;
299 const struct sockaddr *sa = NULL;
300 struct addrinfo hints, *result = NULL;
301 char *arg, *end, *plen = NULL, *servname0;
302 const char *servname;
303 long prefixlen = -1;
304 size_t len;
305
306 if (arg0 == NULL) {
307 errno = EINVAL;
308 return -1;
309 }
310
311 if (pa->pa_activator != NULL &&
312 prop_dictionary_get(im->m_env, pa->pa_activator) == NULL)
313 return -1;
314
315 if (pa->pa_deactivator != NULL &&
316 prop_dictionary_get(im->m_env, pa->pa_deactivator) != NULL)
317 return -1;
318
319 if (!prop_dictionary_get_int64(im->m_env, "af", &af0))
320 af = AF_UNSPEC;
321 else
322 af = af0;
323
324 switch (af) {
325 case AF_UNSPEC:
326 case AF_INET:
327 case AF_INET6:
328 if ((arg = strdup(arg0)) == NULL)
329 return -1;
330
331 servname0 = arg;
332 (void)strsep(&servname0, ",");
333 servname = (servname0 == NULL) ? "0" : servname0;
334
335 if (pa->pa_maskkey == NULL)
336 ;
337 else if ((plen = strrchr(arg, '/')) != NULL)
338 *plen++ = '\0';
339
340 memset(&u, 0, sizeof(u));
341
342 memset(&hints, 0, sizeof(hints));
343
344 hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
345 hints.ai_family = af;
346 hints.ai_socktype = SOCK_DGRAM;
347
348 for (;;) {
349 rc = getaddrinfo(arg, servname, &hints, &result);
350 if (rc == 0) {
351 if (result->ai_next == NULL)
352 sa = result->ai_addr;
353 else
354 errno = EMLINK;
355 break;
356 } else if ((hints.ai_flags & AI_NUMERICHOST) != 0 &&
357 (af == AF_INET || af == AF_UNSPEC) &&
358 inet_aton(arg, &u.sin.sin_addr) == 1) {
359 u.sin.sin_family = AF_INET;
360 u.sin.sin_len = sizeof(u.sin);
361 sa = &u.sa;
362 break;
363 } else if ((hints.ai_flags & AI_NUMERICHOST) == 0 ||
364 rc != EAI_NONAME) {
365 errno = ENOENT;
366 break;
367 }
368 hints.ai_flags &= ~AI_NUMERICHOST;
369 }
370
371
372 if (plen == NULL)
373 prefixlen = -1;
374 else {
375 prefixlen = strtol(plen, &end, 10);
376 if (end != NULL && *end != '\0')
377 sa = NULL;
378 if (prefixlen < 0 || prefixlen >= UINT8_MAX) {
379 errno = ERANGE;
380 sa = NULL;
381 }
382 }
383
384 free(arg);
385 if (sa != NULL || af != AF_UNSPEC)
386 break;
387 /*FALLTHROUGH*/
388 case AF_APPLETALK:
389 if (sscanf(arg0, "%u.%u%n", &net, &node, &nread) == 2 &&
390 net != 0 && net <= 0xffff && node != 0 && node <= 0xfe &&
391 arg0[nread] == '\0') {
392 u.sat.sat_family = AF_APPLETALK;
393 u.sat.sat_len = sizeof(u.sat);
394 u.sat.sat_addr.s_net = htons(net);
395 u.sat.sat_addr.s_node = node;
396 sa = &u.sa;
397 }
398 if (af != AF_UNSPEC)
399 break;
400 /*FALLTHROUGH*/
401 case AF_ISO:
402 u.siso.siso_len = sizeof(u.siso);
403 u.siso.siso_family = AF_ISO;
404 /* XXX iso_addr(3) matches ANYTHING! */
405 u.siso.siso_addr = *iso_addr(arg0);
406 sa = &u.sa;
407 break;
408 case AF_LINK:
409 if (parse_linkaddr(arg0, &u.ss) == -1)
410 sa = NULL;
411 else
412 sa = &u.sa;
413 break;
414 }
415
416 if (sa == NULL)
417 return -1;
418
419 len = offsetof(struct paddr_prefix, pfx_addr) + sa->sa_len;
420
421 if ((pfx = malloc(len)) == NULL)
422 return -1;
423
424 #if 0
425 {
426 int i;
427
428 for (i = 0; i < sa->sa_len; i++)
429 printf(" %02x", ((const uint8_t *)sa)[i]);
430 printf("\n");
431 }
432 #endif
433
434 pfx->pfx_len = (int16_t)prefixlen;
435 memcpy(&pfx->pfx_addr, sa, sa->sa_len);
436 af = sa->sa_family;
437
438 if (result != NULL)
439 freeaddrinfo(result);
440
441 o = (prop_object_t)prop_data_create_data(pfx, len);
442
443 free(pfx);
444
445 if (o == NULL)
446 return -1;
447
448 if (match_setenv(im, om, pa->pa_addrkey, o) == -1)
449 return -1;
450
451 if (pa->pa_maskkey != NULL && plen != NULL) {
452 size_t masklen;
453
454 if ((mask = prefixlen_to_mask(af, prefixlen)) == NULL) {
455 err(EXIT_FAILURE, "%s: prefixlen_to_mask(%d, %ld)",
456 __func__, af, prefixlen);
457 return -1;
458 }
459
460 masklen = offsetof(struct paddr_prefix, pfx_addr) +
461 mask->pfx_addr.sa_len;
462
463 d = prop_data_create_data(mask, masklen);
464 free(mask);
465
466 if (d == NULL) {
467 err(EXIT_FAILURE, "%s: prop_data_create_data",
468 __func__);
469 return -1;
470 }
471
472 rc = prop_dictionary_set(om->m_env, pa->pa_maskkey,
473 (prop_object_t)d) ? 0 : -1;
474
475 prop_object_release((prop_object_t)d);
476
477 if (rc != 0) {
478 err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
479 return rc;
480 }
481 }
482
483 om->m_argidx = argidx;
484 om->m_parser = p;
485 om->m_nextparser = p->p_nextparser;
486 return 0;
487 }
488
489 static int
490 pterm_match(const struct parser *p, const struct match *im,
491 struct match *om, int argidx, const char *arg)
492 {
493 const struct pterm *pt = (const struct pterm *)p;
494 prop_bool_t b;
495
496 if (arg != NULL) {
497 errno = EINVAL;
498 return -1;
499 }
500 b = prop_bool_create(true);
501
502 if (match_setenv(im, om, pt->pt_key, (prop_object_t)b) == -1)
503 return -1;
504
505 om->m_argidx = argidx;
506 om->m_parser = p;
507 om->m_nextparser = NULL;
508 return 0;
509 }
510
511 static int
512 piface_match(const struct parser *p, const struct match *im,
513 struct match *om, int argidx, const char *arg)
514 {
515 const struct piface *pif = (const struct piface *)p;
516 prop_object_t o;
517
518 if (arg == NULL || strlen(arg) > IFNAMSIZ) {
519 errno = EINVAL;
520 return -1;
521 }
522
523 if ((o = (prop_object_t)prop_string_create_cstring(arg)) == NULL) {
524 errno = ENOMEM;
525 return -1;
526 }
527
528 if (match_setenv(im, om, pif->pif_key, o) == -1)
529 return -1;
530
531 om->m_argidx = argidx;
532 om->m_parser = p;
533 om->m_nextparser = p->p_nextparser;
534 return 0;
535 }
536
537 static void
538 match_cleanup(struct match *dst)
539 {
540 if (dst->m_env != NULL)
541 prop_object_release((prop_object_t)dst->m_env);
542 memset(dst, 0, sizeof(*dst));
543 }
544
545 static void
546 match_copy(struct match *dst, const struct match *src)
547 {
548 match_cleanup(dst);
549
550 prop_object_retain((prop_object_t)src->m_env);
551 *dst = *src;
552 }
553
554 static int
555 pbranch_match(const struct parser *p, const struct match *im,
556 struct match *om, int argidx, const char *arg)
557 {
558 const struct parser *nextp;
559 struct branch *b;
560 const struct pbranch *pb = (const struct pbranch *)p;
561 struct match tmpm;
562 int nforbid = 0, nmatch = 0, rc;
563 parser_match_t matchfunc;
564
565 memset(&tmpm, 0, sizeof(tmpm));
566
567 SIMPLEQ_FOREACH(b, &pb->pb_branches, b_next) {
568 dbg_warnx("%s: b->b_nextparser %p", __func__,
569 (const void *)b->b_nextparser);
570 nextp = b->b_nextparser;
571 if (nextp == NULL) {
572 if (arg == NULL) {
573 nmatch++;
574 match_setenv(im, om, NULL, NULL);
575 om->m_nextparser = NULL;
576 om->m_parser = p;
577 om->m_argidx = argidx;
578 }
579 continue;
580 }
581 matchfunc = nextp->p_methods->pm_match;
582 rc = (*matchfunc)(nextp, im, &tmpm, argidx, arg);
583 if (rc == 0) {
584 match_copy(om, &tmpm);
585 match_cleanup(&tmpm);
586 nmatch++;
587 dbg_warnx("%s: branch %s ok", __func__, nextp->p_name);
588 if (pb->pb_match_first)
589 break;
590 } else if (rc == 1) {
591 nforbid++;
592 if (pb->pb_match_first)
593 break;
594 } else {
595 dbg_warnx("%s: fail branch %s", __func__,
596 nextp->p_name);
597 }
598 }
599 switch (nmatch) {
600 case 0:
601 errno = ENOENT;
602 return (nforbid == 0) ? -1 : 1;
603 case 1:
604 dbg_warnx("%s: branch ok", __func__);
605 return 0;
606 default:
607 match_cleanup(om);
608 errno = EMLINK;
609 return -1;
610 }
611 }
612
613 static int
614 pkw_match(const struct parser *p, const struct match *im,
615 struct match *om, int argidx, const char *arg)
616 {
617 prop_object_t o = NULL;
618 struct kwinst *k;
619 union kwval *u = NULL;
620 const struct pkw *pk = (const struct pkw *)p;
621
622 if (arg == NULL) {
623 errno = EINVAL;
624 return -1;
625 }
626
627 SIMPLEQ_FOREACH(k, &pk->pk_keywords, k_next) {
628 if (k->k_act != NULL &&
629 prop_dictionary_get(im->m_env, k->k_act) == NULL)
630 continue;
631
632 if (k->k_neg && arg[0] == '-' &&
633 strcmp(k->k_word, arg + 1) == 0)
634 u = &k->k_negu;
635 else if (strcmp(k->k_word, arg) == 0)
636 u = &k->k_u;
637 else
638 continue;
639
640 if (k->k_altdeact != NULL &&
641 prop_dictionary_get(im->m_env, k->k_altdeact) != NULL)
642 return 1;
643
644 if (k->k_deact != NULL &&
645 prop_dictionary_get(im->m_env, k->k_deact) != NULL)
646 return 1;
647 break;
648 }
649 if (k == NULL) {
650 errno = ENOENT;
651 return -1;
652 }
653 switch (k->k_type) {
654 case KW_T_NONE:
655 break;
656 case KW_T_BOOL:
657 o = (prop_object_t)prop_bool_create(u->u_bool);
658 if (o == NULL)
659 goto err;
660 break;
661 case KW_T_NUM:
662 o = (prop_object_t)prop_number_create_integer(u->u_num);
663 if (o == NULL)
664 goto err;
665 break;
666 case KW_T_OBJ:
667 o = u->u_obj;
668 break;
669 case KW_T_STR:
670 o = (prop_object_t)prop_data_create_data_nocopy(u->u_str,
671 strlen(u->u_str));
672 if (o == NULL)
673 goto err;
674 break;
675 default:
676 errx(EXIT_FAILURE, "unknown keyword type %d", k->k_type);
677 }
678
679 if (match_setenv(im, om, (o == NULL) ? NULL : k->k_key, o) == -1)
680 return -1;
681
682 om->m_argidx = argidx;
683 om->m_parser = p;
684 om->m_nextparser = k->k_nextparser;
685 om->m_exec = k->k_exec;
686 return 0;
687 err:
688 errno = ENOMEM;
689 return -1;
690 }
691
692 struct paddr *
693 paddr_create(const char *name, parser_exec_t pexec, const char *addrkey,
694 const char *maskkey, struct parser *next)
695 {
696 struct paddr *pa;
697
698 if ((pa = calloc(sizeof(*pa), 1)) == NULL)
699 return NULL;
700
701 pa->pa_parser.p_methods = &paddr_methods;
702 pa->pa_parser.p_exec = pexec;
703 pa->pa_parser.p_name = name;
704 pa->pa_parser.p_nextparser = next;
705
706 pa->pa_addrkey = addrkey;
707 pa->pa_maskkey = maskkey;
708
709 return pa;
710 }
711
712 struct piface *
713 piface_create(const char *name, parser_exec_t pexec, const char *defkey,
714 struct parser *defnext)
715 {
716 struct piface *pif;
717
718 if ((pif = calloc(sizeof(*pif), 1)) == NULL)
719 return NULL;
720
721 pif->pif_parser.p_methods = &piface_methods;
722 pif->pif_parser.p_exec = pexec;
723 pif->pif_parser.p_name = name;
724 pif->pif_parser.p_nextparser = defnext;
725
726 pif->pif_key = defkey;
727
728 return pif;
729 }
730
731 int
732 pbranch_setbranches(struct pbranch *pb, const struct branch *brs, size_t nbr)
733 {
734 struct branch *b;
735 int i;
736
737 dbg_warnx("%s: nbr %zu", __func__, nbr);
738
739 while ((b = SIMPLEQ_FIRST(&pb->pb_branches)) != NULL) {
740 SIMPLEQ_REMOVE_HEAD(&pb->pb_branches, b_next);
741 free(b);
742 }
743
744 for (i = 0; i < nbr; i++) {
745 if ((b = malloc(sizeof(*b))) == NULL)
746 goto err;
747 *b = brs[i];
748 dbg_warnx("%s: b->b_nextparser %p", __func__,
749 (const void *)b->b_nextparser);
750 SIMPLEQ_INSERT_TAIL(&pb->pb_branches, b, b_next);
751 }
752
753 return 0;
754 err:
755 while ((b = SIMPLEQ_FIRST(&pb->pb_branches)) != NULL) {
756 SIMPLEQ_REMOVE_HEAD(&pb->pb_branches, b_next);
757 free(b);
758 }
759 return -1;
760 }
761
762 static int
763 pbranch_init(struct parser *p)
764 {
765 struct branch *b;
766 struct pbranch *pb = (struct pbranch *)p;
767 struct parser *np;
768
769 if (pb->pb_nbrinit == 0 || !SIMPLEQ_EMPTY(&pb->pb_branches))
770 return 0;
771
772 if (pbranch_setbranches(pb, pb->pb_brinit, pb->pb_nbrinit) == -1)
773 return -1;
774
775 SIMPLEQ_FOREACH(b, &pb->pb_branches, b_next) {
776 np = b->b_nextparser;
777 if (np != NULL && parser_init(np) == -1)
778 return -1;
779 }
780 return 0;
781 }
782
783 struct pbranch *
784 pbranch_create(const char *name, const struct branch *brs, size_t nbr,
785 bool match_first)
786 {
787 struct pbranch *pb;
788
789 dbg_warnx("%s: nbr %zu", __func__, nbr);
790
791 if ((pb = calloc(1, sizeof(*pb))) == NULL)
792 return NULL;
793
794 pb->pb_parser.p_methods = &pbranch_methods;
795 pb->pb_parser.p_name = name;
796
797 SIMPLEQ_INIT(&pb->pb_branches);
798
799 if (pbranch_setbranches(pb, brs, nbr) == -1)
800 goto post_pb_err;
801
802 pb->pb_match_first = match_first;
803 return pb;
804 post_pb_err:
805 free(pb);
806 return NULL;
807 }
808
809 static int
810 parser_default_init(struct parser *p)
811 {
812 struct parser *np;
813
814 np = p->p_nextparser;
815 if (np != NULL && parser_init(np) == -1)
816 return -1;
817
818 return 0;
819 }
820
821 static int
822 pkw_setwords(struct pkw *pk, parser_exec_t defexec, const char *defkey,
823 const struct kwinst *kws, size_t nkw, struct parser *defnext)
824 {
825 struct kwinst *k;
826 int i;
827
828 for (i = 0; i < nkw; i++) {
829 if ((k = malloc(sizeof(*k))) == NULL)
830 goto post_pk_err;
831 *k = kws[i];
832 if (k->k_nextparser == NULL)
833 k->k_nextparser = defnext;
834 if (k->k_key == NULL)
835 k->k_key = defkey;
836 if (k->k_exec == NULL)
837 k->k_exec = defexec;
838 SIMPLEQ_INSERT_TAIL(&pk->pk_keywords, k, k_next);
839 }
840 return 0;
841
842 post_pk_err:
843 while ((k = SIMPLEQ_FIRST(&pk->pk_keywords)) != NULL) {
844 SIMPLEQ_REMOVE_HEAD(&pk->pk_keywords, k_next);
845 free(k);
846 }
847 return -1;
848 }
849
850 static int
851 pkw_init(struct parser *p)
852 {
853 struct kwinst *k;
854 struct pkw *pk = (struct pkw *)p;
855 struct parser *np;
856
857 if (pk->pk_nkwinit == 0 || !SIMPLEQ_EMPTY(&pk->pk_keywords))
858 return 0;
859 if (pkw_setwords(pk, pk->pk_execinit, pk->pk_keyinit, pk->pk_kwinit,
860 pk->pk_nkwinit, pk->pk_nextinit) == -1)
861 return -1;
862 SIMPLEQ_FOREACH(k, &pk->pk_keywords, k_next) {
863 np = k->k_nextparser;
864 if (np != NULL && parser_init(np) == -1)
865 return -1;
866 }
867 return 0;
868 }
869
870 struct pkw *
871 pkw_create(const char *name, parser_exec_t defexec, const char *defkey,
872 const struct kwinst *kws, size_t nkw, struct parser *defnext)
873 {
874 struct pkw *pk;
875
876 if ((pk = calloc(1, sizeof(*pk))) == NULL)
877 return NULL;
878
879 pk->pk_parser.p_methods = &pkw_methods;
880 pk->pk_parser.p_exec = defexec;
881 pk->pk_parser.p_name = name;
882
883 SIMPLEQ_INIT(&pk->pk_keywords);
884
885 if (pkw_setwords(pk, defexec, defkey, kws, nkw, defnext) == -1)
886 goto err;
887
888 return pk;
889 err:
890 free(pk);
891 return NULL;
892 }
893
894 int
895 parse(int argc, char **argv, const struct parser *p0, struct match *matches,
896 size_t *nmatch, int *narg)
897 {
898 int i, rc = 0;
899 struct match *lastm = NULL, *m = matches;
900 const struct parser *p = p0;
901
902 for (i = 0; i < argc && p != NULL; i++) {
903 if (m - matches >= *nmatch) {
904 errno = EFBIG;
905 rc = -1;
906 break;
907 }
908 rc = (*p->p_methods->pm_match)(p, lastm, m, i, argv[i]);
909 if (rc != 0)
910 goto out;
911 p = m->m_nextparser;
912 lastm = m++;
913 }
914 for (; m - matches < *nmatch && p != NULL; ) {
915 rc = (*p->p_methods->pm_match)(p, lastm, m, i, NULL);
916 if (rc != 0)
917 break;
918 p = m->m_nextparser;
919 lastm = m++;
920 }
921 out:
922 *nmatch = m - matches;
923 *narg = i;
924 return rc;
925 }
926
927 int
928 matches_exec(const struct match *matches, prop_dictionary_t xenv, size_t nmatch)
929 {
930 int i, rc = 0;
931 const struct match *m;
932 parser_exec_t pexec;
933 prop_dictionary_t d;
934
935 for (i = 0; i < nmatch; i++) {
936 m = &matches[i];
937 dbg_warnx("%s.%d: i %d", __func__, __LINE__, i);
938 pexec = (m->m_parser->p_exec != NULL)
939 ? m->m_parser->p_exec : m->m_exec;
940 if (pexec == NULL)
941 continue;
942 dbg_warnx("%s.%d: m->m_parser->p_name %s", __func__, __LINE__,
943 m->m_parser->p_name);
944 d = prop_dictionary_augment(m->m_env, xenv);
945 rc = (*pexec)(d, xenv);
946 prop_object_release((prop_object_t)d);
947 if (rc == -1)
948 break;
949 }
950 return rc;
951 }
952