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