parse.c revision 1.8 1 /* $NetBSD: parse.c,v 1.8 2008/05/19 18:00:31 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 break;
409 case AF_ISO:
410 u.siso.siso_len = sizeof(u.siso);
411 u.siso.siso_family = AF_ISO;
412 /* XXX iso_addr(3) matches ANYTHING! */
413 u.siso.siso_addr = *iso_addr(arg0);
414 sa = &u.sa;
415 break;
416 case AF_LINK:
417 if (parse_linkaddr(arg0, &u.ss) == -1)
418 sa = NULL;
419 else
420 sa = &u.sa;
421 break;
422 }
423
424 if (sa == NULL)
425 return -1;
426
427 len = offsetof(struct paddr_prefix, pfx_addr) + sa->sa_len;
428
429 if ((pfx = malloc(len)) == NULL)
430 return -1;
431
432 #if 0
433 {
434 int i;
435
436 for (i = 0; i < sa->sa_len; i++)
437 printf(" %02x", ((const uint8_t *)sa)[i]);
438 printf("\n");
439 }
440 #endif
441
442 pfx->pfx_len = (int16_t)prefixlen;
443 memcpy(&pfx->pfx_addr, sa, sa->sa_len);
444 af = sa->sa_family;
445
446 if (result != NULL)
447 freeaddrinfo(result);
448
449 o = (prop_object_t)prop_data_create_data(pfx, len);
450
451 free(pfx);
452
453 if (o == NULL)
454 return -1;
455
456 if (match_setenv(im, om, pa->pa_addrkey, o) == -1)
457 return -1;
458
459 if (pa->pa_maskkey != NULL && plen != NULL) {
460 size_t masklen;
461
462 if ((mask = prefixlen_to_mask(af, prefixlen)) == NULL) {
463 err(EXIT_FAILURE, "%s: prefixlen_to_mask(%d, %ld)",
464 __func__, af, prefixlen);
465 return -1;
466 }
467
468 masklen = offsetof(struct paddr_prefix, pfx_addr) +
469 mask->pfx_addr.sa_len;
470
471 d = prop_data_create_data(mask, masklen);
472 free(mask);
473
474 if (d == NULL) {
475 err(EXIT_FAILURE, "%s: prop_data_create_data",
476 __func__);
477 return -1;
478 }
479
480 rc = prop_dictionary_set(om->m_env, pa->pa_maskkey,
481 (prop_object_t)d) ? 0 : -1;
482
483 prop_object_release((prop_object_t)d);
484
485 if (rc != 0) {
486 err(EXIT_FAILURE, "%s: prop_dictionary_set", __func__);
487 return rc;
488 }
489 }
490
491 om->m_argidx = argidx;
492 om->m_parser = p;
493 om->m_nextparser = p->p_nextparser;
494 return 0;
495 }
496
497 static int
498 pterm_match(const struct parser *p, const struct match *im,
499 struct match *om, int argidx, const char *arg)
500 {
501 const struct pterm *pt = (const struct pterm *)p;
502 prop_bool_t b;
503
504 if (arg != NULL) {
505 errno = EINVAL;
506 return -1;
507 }
508 b = prop_bool_create(true);
509
510 if (match_setenv(im, om, pt->pt_key, (prop_object_t)b) == -1)
511 return -1;
512
513 om->m_argidx = argidx;
514 om->m_parser = p;
515 om->m_nextparser = NULL;
516 return 0;
517 }
518
519 static int
520 piface_match(const struct parser *p, const struct match *im,
521 struct match *om, int argidx, const char *arg)
522 {
523 const struct piface *pif = (const struct piface *)p;
524 prop_object_t o;
525
526 if (arg == NULL || strlen(arg) > IFNAMSIZ) {
527 errno = EINVAL;
528 return -1;
529 }
530
531 if ((o = (prop_object_t)prop_string_create_cstring(arg)) == NULL) {
532 errno = ENOMEM;
533 return -1;
534 }
535
536 if (match_setenv(im, om, pif->pif_key, o) == -1)
537 return -1;
538
539 om->m_argidx = argidx;
540 om->m_parser = p;
541 om->m_nextparser = p->p_nextparser;
542 return 0;
543 }
544
545 static void
546 match_cleanup(struct match *dst)
547 {
548 if (dst->m_env != NULL)
549 prop_object_release((prop_object_t)dst->m_env);
550 memset(dst, 0, sizeof(*dst));
551 }
552
553 static void
554 match_copy(struct match *dst, const struct match *src)
555 {
556 match_cleanup(dst);
557
558 prop_object_retain((prop_object_t)src->m_env);
559 *dst = *src;
560 }
561
562 static int
563 pbranch_match(const struct parser *p, const struct match *im,
564 struct match *om, int argidx, const char *arg)
565 {
566 const struct parser *nextp;
567 struct branch *b;
568 const struct pbranch *pb = (const struct pbranch *)p;
569 struct match tmpm;
570 int nforbid = 0, nmatch = 0, rc;
571 parser_match_t matchfunc;
572
573 memset(&tmpm, 0, sizeof(tmpm));
574
575 SIMPLEQ_FOREACH(b, &pb->pb_branches, b_next) {
576 dbg_warnx("%s: b->b_nextparser %p", __func__,
577 (const void *)b->b_nextparser);
578 nextp = b->b_nextparser;
579 if (nextp == NULL) {
580 if (arg == NULL) {
581 nmatch++;
582 match_setenv(im, om, NULL, NULL);
583 om->m_nextparser = NULL;
584 om->m_parser = p;
585 om->m_argidx = argidx;
586 }
587 continue;
588 }
589 matchfunc = nextp->p_methods->pm_match;
590 rc = (*matchfunc)(nextp, im, &tmpm, argidx, arg);
591 if (rc == 0) {
592 match_copy(om, &tmpm);
593 match_cleanup(&tmpm);
594 nmatch++;
595 dbg_warnx("%s: branch %s ok", __func__, nextp->p_name);
596 if (pb->pb_match_first)
597 break;
598 } else if (rc == 1) {
599 nforbid++;
600 if (pb->pb_match_first)
601 break;
602 } else {
603 dbg_warnx("%s: fail branch %s", __func__,
604 nextp->p_name);
605 }
606 }
607 switch (nmatch) {
608 case 0:
609 errno = ENOENT;
610 return (nforbid == 0) ? -1 : 1;
611 case 1:
612 dbg_warnx("%s: branch ok", __func__);
613 return 0;
614 default:
615 match_cleanup(om);
616 errno = EMLINK;
617 return -1;
618 }
619 }
620
621 static int
622 pkw_match(const struct parser *p, const struct match *im,
623 struct match *om, int argidx, const char *arg)
624 {
625 prop_object_t o = NULL;
626 struct kwinst *k;
627 union kwval *u = NULL;
628 const struct pkw *pk = (const struct pkw *)p;
629
630 if (arg == NULL) {
631 errno = EINVAL;
632 return -1;
633 }
634
635 SIMPLEQ_FOREACH(k, &pk->pk_keywords, k_next) {
636 if (k->k_act != NULL &&
637 prop_dictionary_get(im->m_env, k->k_act) == NULL)
638 continue;
639
640 if (k->k_neg && arg[0] == '-' &&
641 strcmp(k->k_word, arg + 1) == 0)
642 u = &k->k_negu;
643 else if (strcmp(k->k_word, arg) == 0)
644 u = &k->k_u;
645 else
646 continue;
647
648 if (k->k_altdeact != NULL &&
649 prop_dictionary_get(im->m_env, k->k_altdeact) != NULL)
650 return 1;
651
652 if (k->k_deact != NULL &&
653 prop_dictionary_get(im->m_env, k->k_deact) != NULL)
654 return 1;
655 break;
656 }
657 if (k == NULL) {
658 errno = ENOENT;
659 return -1;
660 }
661 switch (k->k_type) {
662 case KW_T_NONE:
663 break;
664 case KW_T_BOOL:
665 o = (prop_object_t)prop_bool_create(u->u_bool);
666 if (o == NULL)
667 goto err;
668 break;
669 case KW_T_INT:
670 o = (prop_object_t)prop_number_create_integer(u->u_sint);
671 if (o == NULL)
672 goto err;
673 break;
674 case KW_T_UINT:
675 o = (prop_object_t)prop_number_create_unsigned_integer(
676 u->u_uint);
677 if (o == NULL)
678 goto err;
679 break;
680 case KW_T_OBJ:
681 o = u->u_obj;
682 break;
683 case KW_T_STR:
684 o = (prop_object_t)prop_data_create_data_nocopy(u->u_str,
685 strlen(u->u_str));
686 if (o == NULL)
687 goto err;
688 break;
689 default:
690 errx(EXIT_FAILURE, "unknown keyword type %d", k->k_type);
691 }
692
693 if (match_setenv(im, om, (o == NULL) ? NULL : k->k_key, o) == -1)
694 return -1;
695
696 om->m_argidx = argidx;
697 om->m_parser = p;
698 om->m_nextparser = k->k_nextparser;
699 om->m_exec = k->k_exec;
700 return 0;
701 err:
702 errno = ENOMEM;
703 return -1;
704 }
705
706 struct paddr *
707 paddr_create(const char *name, parser_exec_t pexec, const char *addrkey,
708 const char *maskkey, struct parser *next)
709 {
710 struct paddr *pa;
711
712 if ((pa = calloc(sizeof(*pa), 1)) == NULL)
713 return NULL;
714
715 pa->pa_parser.p_methods = &paddr_methods;
716 pa->pa_parser.p_exec = pexec;
717 pa->pa_parser.p_name = name;
718 pa->pa_parser.p_nextparser = next;
719
720 pa->pa_addrkey = addrkey;
721 pa->pa_maskkey = maskkey;
722
723 return pa;
724 }
725
726 struct piface *
727 piface_create(const char *name, parser_exec_t pexec, const char *defkey,
728 struct parser *defnext)
729 {
730 struct piface *pif;
731
732 if ((pif = calloc(sizeof(*pif), 1)) == NULL)
733 return NULL;
734
735 pif->pif_parser.p_methods = &piface_methods;
736 pif->pif_parser.p_exec = pexec;
737 pif->pif_parser.p_name = name;
738 pif->pif_parser.p_nextparser = defnext;
739
740 pif->pif_key = defkey;
741
742 return pif;
743 }
744
745 int
746 pbranch_setbranches(struct pbranch *pb, const struct branch *brs, size_t nbr)
747 {
748 struct branch *b;
749 int i;
750
751 dbg_warnx("%s: nbr %zu", __func__, nbr);
752
753 while ((b = SIMPLEQ_FIRST(&pb->pb_branches)) != NULL) {
754 SIMPLEQ_REMOVE_HEAD(&pb->pb_branches, b_next);
755 free(b);
756 }
757
758 for (i = 0; i < nbr; i++) {
759 if ((b = malloc(sizeof(*b))) == NULL)
760 goto err;
761 *b = brs[i];
762 dbg_warnx("%s: b->b_nextparser %p", __func__,
763 (const void *)b->b_nextparser);
764 SIMPLEQ_INSERT_TAIL(&pb->pb_branches, b, b_next);
765 }
766
767 return 0;
768 err:
769 while ((b = SIMPLEQ_FIRST(&pb->pb_branches)) != NULL) {
770 SIMPLEQ_REMOVE_HEAD(&pb->pb_branches, b_next);
771 free(b);
772 }
773 return -1;
774 }
775
776 static int
777 pbranch_init(struct parser *p)
778 {
779 struct branch *b;
780 struct pbranch *pb = (struct pbranch *)p;
781 struct parser *np;
782
783 if (pb->pb_nbrinit == 0 || !SIMPLEQ_EMPTY(&pb->pb_branches))
784 return 0;
785
786 if (pbranch_setbranches(pb, pb->pb_brinit, pb->pb_nbrinit) == -1)
787 return -1;
788
789 SIMPLEQ_FOREACH(b, &pb->pb_branches, b_next) {
790 np = b->b_nextparser;
791 if (np != NULL && parser_init(np) == -1)
792 return -1;
793 }
794 return 0;
795 }
796
797 struct pbranch *
798 pbranch_create(const char *name, const struct branch *brs, size_t nbr,
799 bool match_first)
800 {
801 struct pbranch *pb;
802
803 dbg_warnx("%s: nbr %zu", __func__, nbr);
804
805 if ((pb = calloc(1, sizeof(*pb))) == NULL)
806 return NULL;
807
808 pb->pb_parser.p_methods = &pbranch_methods;
809 pb->pb_parser.p_name = name;
810
811 SIMPLEQ_INIT(&pb->pb_branches);
812
813 if (pbranch_setbranches(pb, brs, nbr) == -1)
814 goto post_pb_err;
815
816 pb->pb_match_first = match_first;
817 return pb;
818 post_pb_err:
819 free(pb);
820 return NULL;
821 }
822
823 static int
824 parser_default_init(struct parser *p)
825 {
826 struct parser *np;
827
828 np = p->p_nextparser;
829 if (np != NULL && parser_init(np) == -1)
830 return -1;
831
832 return 0;
833 }
834
835 static int
836 pkw_setwords(struct pkw *pk, parser_exec_t defexec, const char *defkey,
837 const struct kwinst *kws, size_t nkw, struct parser *defnext)
838 {
839 struct kwinst *k;
840 int i;
841
842 for (i = 0; i < nkw; i++) {
843 if ((k = malloc(sizeof(*k))) == NULL)
844 goto post_pk_err;
845 *k = kws[i];
846 if (k->k_nextparser == NULL)
847 k->k_nextparser = defnext;
848 if (k->k_key == NULL)
849 k->k_key = defkey;
850 if (k->k_exec == NULL)
851 k->k_exec = defexec;
852 SIMPLEQ_INSERT_TAIL(&pk->pk_keywords, k, k_next);
853 }
854 return 0;
855
856 post_pk_err:
857 while ((k = SIMPLEQ_FIRST(&pk->pk_keywords)) != NULL) {
858 SIMPLEQ_REMOVE_HEAD(&pk->pk_keywords, k_next);
859 free(k);
860 }
861 return -1;
862 }
863
864 static int
865 pkw_init(struct parser *p)
866 {
867 struct kwinst *k;
868 struct pkw *pk = (struct pkw *)p;
869 struct parser *np;
870
871 if (pk->pk_nkwinit == 0 || !SIMPLEQ_EMPTY(&pk->pk_keywords))
872 return 0;
873 if (pkw_setwords(pk, pk->pk_execinit, pk->pk_keyinit, pk->pk_kwinit,
874 pk->pk_nkwinit, pk->pk_nextinit) == -1)
875 return -1;
876 SIMPLEQ_FOREACH(k, &pk->pk_keywords, k_next) {
877 np = k->k_nextparser;
878 if (np != NULL && parser_init(np) == -1)
879 return -1;
880 }
881 return 0;
882 }
883
884 struct pkw *
885 pkw_create(const char *name, parser_exec_t defexec, const char *defkey,
886 const struct kwinst *kws, size_t nkw, struct parser *defnext)
887 {
888 struct pkw *pk;
889
890 if ((pk = calloc(1, sizeof(*pk))) == NULL)
891 return NULL;
892
893 pk->pk_parser.p_methods = &pkw_methods;
894 pk->pk_parser.p_exec = defexec;
895 pk->pk_parser.p_name = name;
896
897 SIMPLEQ_INIT(&pk->pk_keywords);
898
899 if (pkw_setwords(pk, defexec, defkey, kws, nkw, defnext) == -1)
900 goto err;
901
902 return pk;
903 err:
904 free(pk);
905 return NULL;
906 }
907
908 int
909 parse(int argc, char **argv, const struct parser *p0, struct match *matches,
910 size_t *nmatch, int *narg)
911 {
912 int i, rc = 0;
913 struct match *lastm = NULL, *m = matches;
914 const struct parser *p = p0;
915
916 for (i = 0; i < argc && p != NULL; i++) {
917 if (m - matches >= *nmatch) {
918 errno = EFBIG;
919 rc = -1;
920 break;
921 }
922 rc = (*p->p_methods->pm_match)(p, lastm, m, i, argv[i]);
923 if (rc != 0)
924 goto out;
925 p = m->m_nextparser;
926 lastm = m++;
927 }
928 for (; m - matches < *nmatch && p != NULL; ) {
929 rc = (*p->p_methods->pm_match)(p, lastm, m, i, NULL);
930 if (rc != 0)
931 break;
932 p = m->m_nextparser;
933 lastm = m++;
934 }
935 out:
936 *nmatch = m - matches;
937 *narg = i;
938 return rc;
939 }
940
941 int
942 matches_exec(const struct match *matches, prop_dictionary_t xenv, size_t nmatch)
943 {
944 int i, rc = 0;
945 const struct match *m;
946 parser_exec_t pexec;
947 prop_dictionary_t d;
948
949 for (i = 0; i < nmatch; i++) {
950 m = &matches[i];
951 dbg_warnx("%s.%d: i %d", __func__, __LINE__, i);
952 pexec = (m->m_parser->p_exec != NULL)
953 ? m->m_parser->p_exec : m->m_exec;
954 if (pexec == NULL)
955 continue;
956 dbg_warnx("%s.%d: m->m_parser->p_name %s", __func__, __LINE__,
957 m->m_parser->p_name);
958 d = prop_dictionary_augment(m->m_env, xenv);
959 rc = (*pexec)(d, xenv);
960 prop_object_release((prop_object_t)d);
961 if (rc == -1)
962 break;
963 }
964 return rc;
965 }
966