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