xref: /minix3/lib/libterminfo/compile.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /* $NetBSD: compile.c,v 1.9 2013/06/07 13:16:18 roy Exp $ */
251e66a47SVivek Prakash 
351e66a47SVivek Prakash /*
40c3ae37fSLionel Sambuc  * Copyright (c) 2009, 2010, 2011 The NetBSD Foundation, Inc.
551e66a47SVivek Prakash  *
651e66a47SVivek Prakash  * This code is derived from software contributed to The NetBSD Foundation
751e66a47SVivek Prakash  * by Roy Marples.
851e66a47SVivek Prakash  *
951e66a47SVivek Prakash  * Redistribution and use in source and binary forms, with or without
1051e66a47SVivek Prakash  * modification, are permitted provided that the following conditions
1151e66a47SVivek Prakash  * are met:
1251e66a47SVivek Prakash  * 1. Redistributions of source code must retain the above copyright
1351e66a47SVivek Prakash  *    notice, this list of conditions and the following disclaimer.
1451e66a47SVivek Prakash  * 2. Redistributions in binary form must reproduce the above copyright
1551e66a47SVivek Prakash  *    notice, this list of conditions and the following disclaimer in the
1651e66a47SVivek Prakash  *    documentation and/or other materials provided with the distribution.
1751e66a47SVivek Prakash  *
1851e66a47SVivek Prakash  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1951e66a47SVivek Prakash  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2051e66a47SVivek Prakash  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2151e66a47SVivek Prakash  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2251e66a47SVivek Prakash  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2351e66a47SVivek Prakash  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2451e66a47SVivek Prakash  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2551e66a47SVivek Prakash  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2651e66a47SVivek Prakash  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2751e66a47SVivek Prakash  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2851e66a47SVivek Prakash  */
2951e66a47SVivek Prakash 
3051e66a47SVivek Prakash #if HAVE_NBTOOL_CONFIG_H
3151e66a47SVivek Prakash #include "nbtool_config.h"
3251e66a47SVivek Prakash #endif
3351e66a47SVivek Prakash 
3451e66a47SVivek Prakash #include <sys/cdefs.h>
35*84d9c625SLionel Sambuc __RCSID("$NetBSD: compile.c,v 1.9 2013/06/07 13:16:18 roy Exp $");
3651e66a47SVivek Prakash 
3751e66a47SVivek Prakash #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
3851e66a47SVivek Prakash #include <sys/endian.h>
3951e66a47SVivek Prakash #endif
4051e66a47SVivek Prakash 
4151e66a47SVivek Prakash #include <assert.h>
4251e66a47SVivek Prakash #include <ctype.h>
4351e66a47SVivek Prakash #include <err.h>
4451e66a47SVivek Prakash #include <errno.h>
4551e66a47SVivek Prakash #include <limits.h>
4651e66a47SVivek Prakash #include <stdarg.h>
4751e66a47SVivek Prakash #include <stdlib.h>
4851e66a47SVivek Prakash #include <stdint.h>
4951e66a47SVivek Prakash #include <stdio.h>
5051e66a47SVivek Prakash #include <string.h>
5151e66a47SVivek Prakash #include <term_private.h>
5251e66a47SVivek Prakash #include <term.h>
5351e66a47SVivek Prakash 
540c3ae37fSLionel Sambuc static void __printflike(2, 3)
dowarn(int flags,const char * fmt,...)5551e66a47SVivek Prakash dowarn(int flags, const char *fmt, ...)
5651e66a47SVivek Prakash {
5751e66a47SVivek Prakash 	va_list va;
5851e66a47SVivek Prakash 
5951e66a47SVivek Prakash 	errno = EINVAL;
6051e66a47SVivek Prakash 	if (flags & TIC_WARNING) {
6151e66a47SVivek Prakash 		va_start(va, fmt);
6251e66a47SVivek Prakash 		vwarnx(fmt, va);
6351e66a47SVivek Prakash 		va_end(va);
6451e66a47SVivek Prakash 	}
6551e66a47SVivek Prakash }
6651e66a47SVivek Prakash 
6751e66a47SVivek Prakash char *
_ti_grow_tbuf(TBUF * tbuf,size_t len)6851e66a47SVivek Prakash _ti_grow_tbuf(TBUF *tbuf, size_t len)
6951e66a47SVivek Prakash {
7051e66a47SVivek Prakash 	char *buf;
7151e66a47SVivek Prakash 	size_t l;
7251e66a47SVivek Prakash 
7351e66a47SVivek Prakash 	_DIAGASSERT(tbuf != NULL);
7451e66a47SVivek Prakash 
7551e66a47SVivek Prakash 	l = tbuf->bufpos + len;
7651e66a47SVivek Prakash 	if (l > tbuf->buflen) {
770c3ae37fSLionel Sambuc 		if (tbuf->buflen == 0)
7851e66a47SVivek Prakash 			buf = malloc(l);
7951e66a47SVivek Prakash 		else
8051e66a47SVivek Prakash 			buf = realloc(tbuf->buf, l);
8151e66a47SVivek Prakash 		if (buf == NULL)
8251e66a47SVivek Prakash 			return NULL;
8351e66a47SVivek Prakash 		tbuf->buf = buf;
8451e66a47SVivek Prakash 		tbuf->buflen = l;
8551e66a47SVivek Prakash 	}
8651e66a47SVivek Prakash 	return tbuf->buf;
8751e66a47SVivek Prakash }
8851e66a47SVivek Prakash 
8951e66a47SVivek Prakash char *
_ti_find_cap(TBUF * tbuf,char type,short ind)9051e66a47SVivek Prakash _ti_find_cap(TBUF *tbuf, char type, short ind)
9151e66a47SVivek Prakash {
9251e66a47SVivek Prakash 	size_t n;
9351e66a47SVivek Prakash 	short num;
9451e66a47SVivek Prakash 	char *cap;
9551e66a47SVivek Prakash 
9651e66a47SVivek Prakash 	_DIAGASSERT(tbuf != NULL);
9751e66a47SVivek Prakash 
9851e66a47SVivek Prakash 	cap = tbuf->buf;
9951e66a47SVivek Prakash 	for (n = tbuf->entries; n > 0; n--) {
10051e66a47SVivek Prakash 		num = le16dec(cap);
10151e66a47SVivek Prakash 		cap += sizeof(uint16_t);
10251e66a47SVivek Prakash 		if (num == ind)
10351e66a47SVivek Prakash 			return cap;
10451e66a47SVivek Prakash 		switch (type) {
10551e66a47SVivek Prakash 		case 'f':
10651e66a47SVivek Prakash 			cap++;
10751e66a47SVivek Prakash 			break;
10851e66a47SVivek Prakash 		case 'n':
10951e66a47SVivek Prakash 			cap += sizeof(uint16_t);
11051e66a47SVivek Prakash 			break;
11151e66a47SVivek Prakash 		case 's':
11251e66a47SVivek Prakash 			num = le16dec(cap);
11351e66a47SVivek Prakash 			cap += sizeof(uint16_t);
11451e66a47SVivek Prakash 			cap += num;
11551e66a47SVivek Prakash 			break;
11651e66a47SVivek Prakash 		}
11751e66a47SVivek Prakash 	}
11851e66a47SVivek Prakash 
11951e66a47SVivek Prakash 	errno = ESRCH;
12051e66a47SVivek Prakash 	return NULL;
12151e66a47SVivek Prakash }
12251e66a47SVivek Prakash 
12351e66a47SVivek Prakash char *
_ti_find_extra(TBUF * tbuf,const char * code)12451e66a47SVivek Prakash _ti_find_extra(TBUF *tbuf, const char *code)
12551e66a47SVivek Prakash {
12651e66a47SVivek Prakash 	size_t n;
12751e66a47SVivek Prakash 	short num;
12851e66a47SVivek Prakash 	char *cap;
12951e66a47SVivek Prakash 
13051e66a47SVivek Prakash 	_DIAGASSERT(tbuf != NULL);
13151e66a47SVivek Prakash 	_DIAGASSERT(code != NULL);
13251e66a47SVivek Prakash 
13351e66a47SVivek Prakash 	cap = tbuf->buf;
13451e66a47SVivek Prakash 	for (n = tbuf->entries; n > 0; n--) {
13551e66a47SVivek Prakash 		num = le16dec(cap);
13651e66a47SVivek Prakash 		cap += sizeof(uint16_t);
13751e66a47SVivek Prakash 		if (strcmp(cap, code) == 0)
13851e66a47SVivek Prakash 			return cap + num;
13951e66a47SVivek Prakash 		cap += num;
14051e66a47SVivek Prakash 		switch (*cap++) {
14151e66a47SVivek Prakash 		case 'f':
14251e66a47SVivek Prakash 			cap++;
14351e66a47SVivek Prakash 			break;
14451e66a47SVivek Prakash 		case 'n':
14551e66a47SVivek Prakash 			cap += sizeof(uint16_t);
14651e66a47SVivek Prakash 			break;
14751e66a47SVivek Prakash 		case 's':
14851e66a47SVivek Prakash 			num = le16dec(cap);
14951e66a47SVivek Prakash 			cap += sizeof(uint16_t);
15051e66a47SVivek Prakash 			cap += num;
15151e66a47SVivek Prakash 			break;
15251e66a47SVivek Prakash 		}
15351e66a47SVivek Prakash 	}
15451e66a47SVivek Prakash 
15551e66a47SVivek Prakash 	errno = ESRCH;
15651e66a47SVivek Prakash 	return NULL;
15751e66a47SVivek Prakash }
15851e66a47SVivek Prakash 
15951e66a47SVivek Prakash size_t
_ti_store_extra(TIC * tic,int wrn,char * id,char type,char flag,short num,char * str,size_t strl,int flags)16051e66a47SVivek Prakash _ti_store_extra(TIC *tic, int wrn, char *id, char type, char flag, short num,
16151e66a47SVivek Prakash     char *str, size_t strl, int flags)
16251e66a47SVivek Prakash {
16351e66a47SVivek Prakash 	size_t l;
16451e66a47SVivek Prakash 
16551e66a47SVivek Prakash 	_DIAGASSERT(tic != NULL);
16651e66a47SVivek Prakash 
16751e66a47SVivek Prakash 	if (strcmp(id, "use") != 0) {
16851e66a47SVivek Prakash 		if (_ti_find_extra(&tic->extras, id) != NULL)
16951e66a47SVivek Prakash 			return 0;
17051e66a47SVivek Prakash 		if (!(flags & TIC_EXTRA)) {
17151e66a47SVivek Prakash 			if (wrn != 0)
17251e66a47SVivek Prakash 				dowarn(flags, "%s: %s: unknown capability",
17351e66a47SVivek Prakash 				    tic->name, id);
17451e66a47SVivek Prakash 			return 0;
17551e66a47SVivek Prakash 		}
17651e66a47SVivek Prakash 	}
17751e66a47SVivek Prakash 
17851e66a47SVivek Prakash 	l = strlen(id) + 1;
17951e66a47SVivek Prakash 	if (l > UINT16_T_MAX) {
18051e66a47SVivek Prakash 		dowarn(flags, "%s: %s: cap name is too long", tic->name, id);
18151e66a47SVivek Prakash 		return 0;
18251e66a47SVivek Prakash 	}
18351e66a47SVivek Prakash 
18451e66a47SVivek Prakash 	if (!_ti_grow_tbuf(&tic->extras,
18551e66a47SVivek Prakash 		l + strl + (sizeof(uint16_t) * 2) + 1))
18651e66a47SVivek Prakash 		return 0;
18751e66a47SVivek Prakash 	le16enc(tic->extras.buf + tic->extras.bufpos, l);
18851e66a47SVivek Prakash 	tic->extras.bufpos += sizeof(uint16_t);
18951e66a47SVivek Prakash 	memcpy(tic->extras.buf + tic->extras.bufpos, id, l);
19051e66a47SVivek Prakash 	tic->extras.bufpos += l;
19151e66a47SVivek Prakash 	tic->extras.buf[tic->extras.bufpos++] = type;
19251e66a47SVivek Prakash 	switch (type) {
19351e66a47SVivek Prakash 	case 'f':
19451e66a47SVivek Prakash 		tic->extras.buf[tic->extras.bufpos++] = flag;
19551e66a47SVivek Prakash 		break;
19651e66a47SVivek Prakash 	case 'n':
19751e66a47SVivek Prakash 		le16enc(tic->extras.buf + tic->extras.bufpos, num);
19851e66a47SVivek Prakash 		tic->extras.bufpos += sizeof(uint16_t);
19951e66a47SVivek Prakash 		break;
20051e66a47SVivek Prakash 	case 's':
20151e66a47SVivek Prakash 		le16enc(tic->extras.buf + tic->extras.bufpos, strl);
20251e66a47SVivek Prakash 		tic->extras.bufpos += sizeof(uint16_t);
20351e66a47SVivek Prakash 		memcpy(tic->extras.buf + tic->extras.bufpos, str, strl);
20451e66a47SVivek Prakash 		tic->extras.bufpos += strl;
20551e66a47SVivek Prakash 		break;
20651e66a47SVivek Prakash 	}
20751e66a47SVivek Prakash 	tic->extras.entries++;
20851e66a47SVivek Prakash 	return 1;
20951e66a47SVivek Prakash }
21051e66a47SVivek Prakash 
21151e66a47SVivek Prakash ssize_t
_ti_flatten(uint8_t ** buf,const TIC * tic)21251e66a47SVivek Prakash _ti_flatten(uint8_t **buf, const TIC *tic)
21351e66a47SVivek Prakash {
21451e66a47SVivek Prakash 	size_t buflen, len, alen, dlen;
21551e66a47SVivek Prakash 	uint8_t *cap;
21651e66a47SVivek Prakash 
21751e66a47SVivek Prakash 	_DIAGASSERT(buf != NULL);
21851e66a47SVivek Prakash 	_DIAGASSERT(tic != NULL);
21951e66a47SVivek Prakash 
22051e66a47SVivek Prakash 	len = strlen(tic->name) + 1;
22151e66a47SVivek Prakash 	if (tic->alias == NULL)
22251e66a47SVivek Prakash 		alen = 0;
22351e66a47SVivek Prakash 	else
22451e66a47SVivek Prakash 		alen = strlen(tic->alias) + 1;
22551e66a47SVivek Prakash 	if (tic->desc == NULL)
22651e66a47SVivek Prakash 		dlen = 0;
22751e66a47SVivek Prakash 	else
22851e66a47SVivek Prakash 		dlen = strlen(tic->desc) + 1;
22951e66a47SVivek Prakash 	buflen = sizeof(char) +
23051e66a47SVivek Prakash 	    sizeof(uint16_t) + len +
23151e66a47SVivek Prakash 	    sizeof(uint16_t) + alen +
23251e66a47SVivek Prakash 	    sizeof(uint16_t) + dlen +
23351e66a47SVivek Prakash 	    (sizeof(uint16_t) * 2) + tic->flags.bufpos +
23451e66a47SVivek Prakash 	    (sizeof(uint16_t) * 2) + tic->nums.bufpos +
23551e66a47SVivek Prakash 	    (sizeof(uint16_t) * 2) + tic->strs.bufpos +
23651e66a47SVivek Prakash 	    (sizeof(uint16_t) * 2) + tic->extras.bufpos;
23751e66a47SVivek Prakash 	*buf = malloc(buflen);
23851e66a47SVivek Prakash 	if (*buf == NULL)
23951e66a47SVivek Prakash 		return -1;
24051e66a47SVivek Prakash 
24151e66a47SVivek Prakash 	cap = *buf;
2420c3ae37fSLionel Sambuc 	*cap++ = 1;
24351e66a47SVivek Prakash 	le16enc(cap, len);
24451e66a47SVivek Prakash 	cap += sizeof(uint16_t);
24551e66a47SVivek Prakash 	memcpy(cap, tic->name, len);
24651e66a47SVivek Prakash 	cap += len;
24751e66a47SVivek Prakash 
24851e66a47SVivek Prakash 	le16enc(cap, alen);
24951e66a47SVivek Prakash 	cap += sizeof(uint16_t);
25051e66a47SVivek Prakash 	if (tic->alias != NULL) {
25151e66a47SVivek Prakash 		memcpy(cap, tic->alias, alen);
25251e66a47SVivek Prakash 		cap += alen;
25351e66a47SVivek Prakash 	}
25451e66a47SVivek Prakash 	le16enc(cap, dlen);
25551e66a47SVivek Prakash 	cap += sizeof(uint16_t);
25651e66a47SVivek Prakash 	if (tic->desc != NULL) {
25751e66a47SVivek Prakash 		memcpy(cap, tic->desc, dlen);
25851e66a47SVivek Prakash 		cap += dlen;
25951e66a47SVivek Prakash 	}
26051e66a47SVivek Prakash 
26151e66a47SVivek Prakash 	if (tic->flags.entries == 0) {
26251e66a47SVivek Prakash 		le16enc(cap, 0);
26351e66a47SVivek Prakash 		cap += sizeof(uint16_t);
26451e66a47SVivek Prakash 	} else {
26551e66a47SVivek Prakash 		le16enc(cap, (tic->flags.bufpos + sizeof(uint16_t)));
26651e66a47SVivek Prakash 		cap += sizeof(uint16_t);
26751e66a47SVivek Prakash 		le16enc(cap, tic->flags.entries);
26851e66a47SVivek Prakash 		cap += sizeof(uint16_t);
26951e66a47SVivek Prakash 		memcpy(cap, tic->flags.buf, tic->flags.bufpos);
27051e66a47SVivek Prakash 		cap += tic->flags.bufpos;
27151e66a47SVivek Prakash 	}
27251e66a47SVivek Prakash 
27351e66a47SVivek Prakash 	if (tic->nums.entries == 0) {
27451e66a47SVivek Prakash 		le16enc(cap, 0);
27551e66a47SVivek Prakash 		cap += sizeof(uint16_t);
27651e66a47SVivek Prakash 	} else {
27751e66a47SVivek Prakash 		le16enc(cap, (tic->nums.bufpos + sizeof(uint16_t)));
27851e66a47SVivek Prakash 		cap += sizeof(uint16_t);
27951e66a47SVivek Prakash 		le16enc(cap, tic->nums.entries);
28051e66a47SVivek Prakash 		cap += sizeof(uint16_t);
28151e66a47SVivek Prakash 		memcpy(cap, tic->nums.buf, tic->nums.bufpos);
28251e66a47SVivek Prakash 		cap += tic->nums.bufpos;
28351e66a47SVivek Prakash 	}
28451e66a47SVivek Prakash 
28551e66a47SVivek Prakash 	if (tic->strs.entries == 0) {
28651e66a47SVivek Prakash 		le16enc(cap, 0);
28751e66a47SVivek Prakash 		cap += sizeof(uint16_t);
28851e66a47SVivek Prakash 	} else {
28951e66a47SVivek Prakash 		le16enc(cap, (tic->strs.bufpos + sizeof(uint16_t)));
29051e66a47SVivek Prakash 		cap += sizeof(uint16_t);
29151e66a47SVivek Prakash 		le16enc(cap, tic->strs.entries);
29251e66a47SVivek Prakash 		cap += sizeof(uint16_t);
29351e66a47SVivek Prakash 		memcpy(cap, tic->strs.buf, tic->strs.bufpos);
29451e66a47SVivek Prakash 		cap += tic->strs.bufpos;
29551e66a47SVivek Prakash 	}
29651e66a47SVivek Prakash 
29751e66a47SVivek Prakash 	if (tic->extras.entries == 0) {
29851e66a47SVivek Prakash 		le16enc(cap, 0);
29951e66a47SVivek Prakash 		cap += sizeof(uint16_t);
30051e66a47SVivek Prakash 	} else {
30151e66a47SVivek Prakash 		le16enc(cap, (tic->extras.bufpos + sizeof(uint16_t)));
30251e66a47SVivek Prakash 		cap += sizeof(uint16_t);
30351e66a47SVivek Prakash 		le16enc(cap, tic->extras.entries);
30451e66a47SVivek Prakash 		cap += sizeof(uint16_t);
30551e66a47SVivek Prakash 		memcpy(cap, tic->extras.buf, tic->extras.bufpos);
30651e66a47SVivek Prakash 		cap += tic->extras.bufpos;
30751e66a47SVivek Prakash 	}
30851e66a47SVivek Prakash 
30951e66a47SVivek Prakash 	return cap - *buf;
31051e66a47SVivek Prakash }
31151e66a47SVivek Prakash 
31251e66a47SVivek Prakash static int
encode_string(const char * term,const char * cap,TBUF * tbuf,const char * str,int flags)31351e66a47SVivek Prakash encode_string(const char *term, const char *cap, TBUF *tbuf, const char *str,
31451e66a47SVivek Prakash     int flags)
31551e66a47SVivek Prakash {
31651e66a47SVivek Prakash 	int slash, i, num;
31751e66a47SVivek Prakash 	char ch, *p, *s, last;
31851e66a47SVivek Prakash 
31951e66a47SVivek Prakash 	if (_ti_grow_tbuf(tbuf, strlen(str) + 1) == NULL)
32051e66a47SVivek Prakash 		return -1;
32151e66a47SVivek Prakash 	p = s = tbuf->buf + tbuf->bufpos;
32251e66a47SVivek Prakash 	slash = 0;
32351e66a47SVivek Prakash 	last = '\0';
32451e66a47SVivek Prakash 	/* Convert escape codes */
32551e66a47SVivek Prakash 	while ((ch = *str++) != '\0') {
32651e66a47SVivek Prakash 		if (slash == 0 && ch == '\\') {
32751e66a47SVivek Prakash 			slash = 1;
32851e66a47SVivek Prakash 			continue;
32951e66a47SVivek Prakash 		}
33051e66a47SVivek Prakash 		if (slash == 0) {
33151e66a47SVivek Prakash 			if (last != '%' && ch == '^') {
33251e66a47SVivek Prakash 				ch = *str++;
33351e66a47SVivek Prakash 				if (((unsigned char)ch) >= 128)
33451e66a47SVivek Prakash 					dowarn(flags,
33551e66a47SVivek Prakash 					    "%s: %s: illegal ^ character",
33651e66a47SVivek Prakash 					    term, cap);
33751e66a47SVivek Prakash 				if (ch == '\0')
33851e66a47SVivek Prakash 					break;
33951e66a47SVivek Prakash 				if (ch == '?')
34051e66a47SVivek Prakash 					ch = '\177';
34151e66a47SVivek Prakash 				else if ((ch &= 037) == 0)
3420c3ae37fSLionel Sambuc 					ch = (char)128;
34351e66a47SVivek Prakash 			}
34451e66a47SVivek Prakash 			*p++ = ch;
34551e66a47SVivek Prakash 			last = ch;
34651e66a47SVivek Prakash 			continue;
34751e66a47SVivek Prakash 		}
34851e66a47SVivek Prakash 		slash = 0;
34951e66a47SVivek Prakash 		if (ch >= '0' && ch <= '7') {
35051e66a47SVivek Prakash 			num = ch - '0';
35151e66a47SVivek Prakash 			for (i = 0; i < 2; i++) {
35251e66a47SVivek Prakash 				if (*str < '0' || *str > '7') {
35351e66a47SVivek Prakash 					if (isdigit((unsigned char)*str))
35451e66a47SVivek Prakash 						dowarn(flags,
35551e66a47SVivek Prakash 						    "%s: %s: non octal"
35651e66a47SVivek Prakash 						    " digit", term, cap);
35751e66a47SVivek Prakash 					else
35851e66a47SVivek Prakash 						break;
35951e66a47SVivek Prakash 				}
36051e66a47SVivek Prakash 				num = num * 8 + *str++ - '0';
36151e66a47SVivek Prakash 			}
36251e66a47SVivek Prakash 			if (num == 0)
36351e66a47SVivek Prakash 				num = 0200;
36451e66a47SVivek Prakash 			*p++ = (char)num;
36551e66a47SVivek Prakash 			continue;
36651e66a47SVivek Prakash 		}
36751e66a47SVivek Prakash 		switch (ch) {
36851e66a47SVivek Prakash 		case 'a':
36951e66a47SVivek Prakash 			*p++ = '\a';
37051e66a47SVivek Prakash 			break;
37151e66a47SVivek Prakash 		case 'b':
37251e66a47SVivek Prakash 			*p++ = '\b';
37351e66a47SVivek Prakash 			break;
37451e66a47SVivek Prakash 		case 'e': /* FALLTHROUGH */
37551e66a47SVivek Prakash 		case 'E':
37651e66a47SVivek Prakash 			*p++ = '\033';
37751e66a47SVivek Prakash 			break;
37851e66a47SVivek Prakash 		case 'f':
37951e66a47SVivek Prakash 			*p++ = '\014';
38051e66a47SVivek Prakash 			break;
38151e66a47SVivek Prakash 		case 'l': /* FALLTHROUGH */
38251e66a47SVivek Prakash 		case 'n':
38351e66a47SVivek Prakash 			*p++ = '\n';
38451e66a47SVivek Prakash 			break;
38551e66a47SVivek Prakash 		case 'r':
38651e66a47SVivek Prakash 			*p++ = '\r';
38751e66a47SVivek Prakash 			break;
38851e66a47SVivek Prakash 		case 's':
38951e66a47SVivek Prakash 			*p++ = ' ';
39051e66a47SVivek Prakash 			break;
39151e66a47SVivek Prakash 		case 't':
39251e66a47SVivek Prakash 			*p++ = '\t';
39351e66a47SVivek Prakash 			break;
39451e66a47SVivek Prakash 		default:
39551e66a47SVivek Prakash 			/* We should warn here */
39651e66a47SVivek Prakash 		case '^':
39751e66a47SVivek Prakash 		case ',':
39851e66a47SVivek Prakash 		case ':':
39951e66a47SVivek Prakash 		case '|':
40051e66a47SVivek Prakash 			*p++ = ch;
40151e66a47SVivek Prakash 			break;
40251e66a47SVivek Prakash 		}
40351e66a47SVivek Prakash 		last = ch;
40451e66a47SVivek Prakash 	}
40551e66a47SVivek Prakash 	*p++ = '\0';
40651e66a47SVivek Prakash 	tbuf->bufpos += p - s;
40751e66a47SVivek Prakash 	return 0;
40851e66a47SVivek Prakash }
40951e66a47SVivek Prakash 
41051e66a47SVivek Prakash char *
_ti_get_token(char ** cap,char sep)41151e66a47SVivek Prakash _ti_get_token(char **cap, char sep)
41251e66a47SVivek Prakash {
41351e66a47SVivek Prakash 	char esc, *token;
41451e66a47SVivek Prakash 
41551e66a47SVivek Prakash 	while (isspace((unsigned char)**cap))
41651e66a47SVivek Prakash 		(*cap)++;
41751e66a47SVivek Prakash 	if (**cap == '\0')
41851e66a47SVivek Prakash 		return NULL;
41951e66a47SVivek Prakash 
42051e66a47SVivek Prakash 	/* We can't use stresep(3) as ^ we need two escape chars */
42151e66a47SVivek Prakash 	esc = '\0';
42251e66a47SVivek Prakash 	for (token = *cap;
42351e66a47SVivek Prakash 	     **cap != '\0' && (esc != '\0' || **cap != sep);
42451e66a47SVivek Prakash 	     (*cap)++)
42551e66a47SVivek Prakash 	{
42651e66a47SVivek Prakash 		if (esc == '\0') {
42751e66a47SVivek Prakash 			if (**cap == '\\' || **cap == '^')
42851e66a47SVivek Prakash 				esc = **cap;
42951e66a47SVivek Prakash 		} else {
43051e66a47SVivek Prakash 			/* termcap /E/ is valid */
43151e66a47SVivek Prakash 			if (sep == ':' && esc == '\\' && **cap == 'E')
43251e66a47SVivek Prakash 				esc = 'x';
43351e66a47SVivek Prakash 			else
43451e66a47SVivek Prakash 				esc = '\0';
43551e66a47SVivek Prakash 		}
43651e66a47SVivek Prakash 	}
43751e66a47SVivek Prakash 
43851e66a47SVivek Prakash 	if (**cap != '\0')
43951e66a47SVivek Prakash 		*(*cap)++ = '\0';
44051e66a47SVivek Prakash 
44151e66a47SVivek Prakash 	return token;
44251e66a47SVivek Prakash }
44351e66a47SVivek Prakash 
44451e66a47SVivek Prakash TIC *
_ti_compile(char * cap,int flags)44551e66a47SVivek Prakash _ti_compile(char *cap, int flags)
44651e66a47SVivek Prakash {
44751e66a47SVivek Prakash 	char *token, *p, *e, *name, *desc, *alias;
44851e66a47SVivek Prakash 	signed char flag;
4490c3ae37fSLionel Sambuc 	long cnum;
4500c3ae37fSLionel Sambuc 	short num;
45151e66a47SVivek Prakash 	ssize_t ind;
45251e66a47SVivek Prakash 	size_t len;
45351e66a47SVivek Prakash 	TBUF buf;
45451e66a47SVivek Prakash 	TIC *tic;
45551e66a47SVivek Prakash 
45651e66a47SVivek Prakash 	_DIAGASSERT(cap != NULL);
45751e66a47SVivek Prakash 
45851e66a47SVivek Prakash 	name = _ti_get_token(&cap, ',');
45951e66a47SVivek Prakash 	if (name == NULL) {
46051e66a47SVivek Prakash 		dowarn(flags, "no seperator found: %s", cap);
46151e66a47SVivek Prakash 		return NULL;
46251e66a47SVivek Prakash 	}
46351e66a47SVivek Prakash 	desc = strrchr(name, '|');
46451e66a47SVivek Prakash 	if (desc != NULL)
46551e66a47SVivek Prakash 		*desc++ = '\0';
46651e66a47SVivek Prakash 	alias = strchr(name, '|');
46751e66a47SVivek Prakash 	if (alias != NULL)
46851e66a47SVivek Prakash 		*alias++ = '\0';
46951e66a47SVivek Prakash 
47051e66a47SVivek Prakash 	tic = calloc(sizeof(*tic), 1);
47151e66a47SVivek Prakash 	if (tic == NULL)
47251e66a47SVivek Prakash 		return NULL;
47351e66a47SVivek Prakash 
47451e66a47SVivek Prakash 	buf.buf = NULL;
47551e66a47SVivek Prakash 	buf.buflen = 0;
47651e66a47SVivek Prakash 
47751e66a47SVivek Prakash 	tic->name = strdup(name);
47851e66a47SVivek Prakash 	if (tic->name == NULL)
47951e66a47SVivek Prakash 		goto error;
48051e66a47SVivek Prakash 	if (alias != NULL && flags & TIC_ALIAS) {
48151e66a47SVivek Prakash 		tic->alias = strdup(alias);
48251e66a47SVivek Prakash 		if (tic->alias == NULL)
48351e66a47SVivek Prakash 			goto error;
48451e66a47SVivek Prakash 	}
48551e66a47SVivek Prakash 	if (desc != NULL && flags & TIC_DESCRIPTION) {
48651e66a47SVivek Prakash 		tic->desc = strdup(desc);
48751e66a47SVivek Prakash 		if (tic->desc == NULL)
48851e66a47SVivek Prakash 			goto error;
48951e66a47SVivek Prakash 	}
49051e66a47SVivek Prakash 
49151e66a47SVivek Prakash 	for (token = _ti_get_token(&cap, ',');
49251e66a47SVivek Prakash 	     token != NULL && *token != '\0';
49351e66a47SVivek Prakash 	     token = _ti_get_token(&cap, ','))
49451e66a47SVivek Prakash 	{
49551e66a47SVivek Prakash 		/* Skip commented caps */
49651e66a47SVivek Prakash 		if (!(flags & TIC_COMMENT) && token[0] == '.')
49751e66a47SVivek Prakash 			continue;
49851e66a47SVivek Prakash 
49951e66a47SVivek Prakash 		/* Obsolete entries */
50051e66a47SVivek Prakash 		if (token[0] == 'O' && token[1] == 'T') {
50151e66a47SVivek Prakash 			if (!(flags & TIC_EXTRA))
50251e66a47SVivek Prakash 				continue;
50351e66a47SVivek Prakash 			token += 2;
50451e66a47SVivek Prakash 		}
50551e66a47SVivek Prakash 
50651e66a47SVivek Prakash 		/* str cap */
50751e66a47SVivek Prakash 		p = strchr(token, '=');
50851e66a47SVivek Prakash 		if (p != NULL) {
50951e66a47SVivek Prakash 			*p++ = '\0';
51051e66a47SVivek Prakash 			/* Don't use the string if we already have it */
51151e66a47SVivek Prakash 			ind = _ti_strindex(token);
51251e66a47SVivek Prakash 			if (ind != -1 &&
51351e66a47SVivek Prakash 			    _ti_find_cap(&tic->strs, 's', ind) != NULL)
51451e66a47SVivek Prakash 				continue;
51551e66a47SVivek Prakash 
51651e66a47SVivek Prakash 			/* Encode the string to our scratch buffer */
51751e66a47SVivek Prakash 			buf.bufpos = 0;
51851e66a47SVivek Prakash 			if (encode_string(tic->name, token,
51951e66a47SVivek Prakash 				&buf, p, flags) == -1)
52051e66a47SVivek Prakash 				goto error;
52151e66a47SVivek Prakash 			if (buf.bufpos > UINT16_T_MAX) {
52251e66a47SVivek Prakash 				dowarn(flags, "%s: %s: string is too long",
52351e66a47SVivek Prakash 				    tic->name, token);
52451e66a47SVivek Prakash 				continue;
52551e66a47SVivek Prakash 			}
52651e66a47SVivek Prakash 			if (!VALID_STRING(buf.buf)) {
52751e66a47SVivek Prakash 				dowarn(flags, "%s: %s: invalid string",
52851e66a47SVivek Prakash 				    tic->name, token);
52951e66a47SVivek Prakash 				continue;
53051e66a47SVivek Prakash 			}
53151e66a47SVivek Prakash 
53251e66a47SVivek Prakash 			if (ind == -1)
53351e66a47SVivek Prakash 				_ti_store_extra(tic, 1, token, 's', -1, -2,
53451e66a47SVivek Prakash 				    buf.buf, buf.bufpos, flags);
53551e66a47SVivek Prakash 			else {
53651e66a47SVivek Prakash 				if (!_ti_grow_tbuf(&tic->strs,
53751e66a47SVivek Prakash 					(sizeof(uint16_t) * 2) + buf.bufpos))
53851e66a47SVivek Prakash 					goto error;
53951e66a47SVivek Prakash 				le16enc(tic->strs.buf + tic->strs.bufpos, ind);
54051e66a47SVivek Prakash 				tic->strs.bufpos += sizeof(uint16_t);
54151e66a47SVivek Prakash 				le16enc(tic->strs.buf + tic->strs.bufpos,
54251e66a47SVivek Prakash 				    buf.bufpos);
54351e66a47SVivek Prakash 				tic->strs.bufpos += sizeof(uint16_t);
54451e66a47SVivek Prakash 				memcpy(tic->strs.buf + tic->strs.bufpos,
54551e66a47SVivek Prakash 				    buf.buf, buf.bufpos);
54651e66a47SVivek Prakash 				tic->strs.bufpos += buf.bufpos;
54751e66a47SVivek Prakash 				tic->strs.entries++;
54851e66a47SVivek Prakash 			}
54951e66a47SVivek Prakash 			continue;
55051e66a47SVivek Prakash 		}
55151e66a47SVivek Prakash 
55251e66a47SVivek Prakash 		/* num cap */
55351e66a47SVivek Prakash 		p = strchr(token, '#');
55451e66a47SVivek Prakash 		if (p != NULL) {
55551e66a47SVivek Prakash 			*p++ = '\0';
55651e66a47SVivek Prakash 			/* Don't use the number if we already have it */
55751e66a47SVivek Prakash 			ind = _ti_numindex(token);
55851e66a47SVivek Prakash 			if (ind != -1 &&
55951e66a47SVivek Prakash 			    _ti_find_cap(&tic->nums, 'n', ind) != NULL)
56051e66a47SVivek Prakash 				continue;
56151e66a47SVivek Prakash 
5620c3ae37fSLionel Sambuc 			cnum = strtol(p, &e, 0);
56351e66a47SVivek Prakash 			if (*e != '\0') {
56451e66a47SVivek Prakash 				dowarn(flags, "%s: %s: not a number",
56551e66a47SVivek Prakash 				    tic->name, token);
56651e66a47SVivek Prakash 				continue;
56751e66a47SVivek Prakash 			}
5680c3ae37fSLionel Sambuc 			if (!VALID_NUMERIC(cnum)) {
56951e66a47SVivek Prakash 				dowarn(flags, "%s: %s: number out of range",
57051e66a47SVivek Prakash 				    tic->name, token);
57151e66a47SVivek Prakash 				continue;
57251e66a47SVivek Prakash 			}
5730c3ae37fSLionel Sambuc 			num = (short)cnum;
57451e66a47SVivek Prakash 			if (ind == -1)
57551e66a47SVivek Prakash 				_ti_store_extra(tic, 1, token, 'n', -1,
57651e66a47SVivek Prakash 				    num, NULL, 0, flags);
57751e66a47SVivek Prakash 			else {
57851e66a47SVivek Prakash 				if (_ti_grow_tbuf(&tic->nums,
57951e66a47SVivek Prakash 					sizeof(uint16_t) * 2) == NULL)
58051e66a47SVivek Prakash 					goto error;
58151e66a47SVivek Prakash 				le16enc(tic->nums.buf + tic->nums.bufpos, ind);
58251e66a47SVivek Prakash 				tic->nums.bufpos += sizeof(uint16_t);
58351e66a47SVivek Prakash 				le16enc(tic->nums.buf + tic->nums.bufpos, num);
58451e66a47SVivek Prakash 				tic->nums.bufpos += sizeof(uint16_t);
58551e66a47SVivek Prakash 				tic->nums.entries++;
58651e66a47SVivek Prakash 			}
58751e66a47SVivek Prakash 			continue;
58851e66a47SVivek Prakash 		}
58951e66a47SVivek Prakash 
59051e66a47SVivek Prakash 		flag = 1;
59151e66a47SVivek Prakash 		len = strlen(token) - 1;
59251e66a47SVivek Prakash 		if (token[len] == '@') {
59351e66a47SVivek Prakash 			flag = CANCELLED_BOOLEAN;
59451e66a47SVivek Prakash 			token[len] = '\0';
59551e66a47SVivek Prakash 		}
59651e66a47SVivek Prakash 		ind = _ti_flagindex(token);
59751e66a47SVivek Prakash 		if (ind == -1 && flag == CANCELLED_BOOLEAN) {
59851e66a47SVivek Prakash 			if ((ind = _ti_numindex(token)) != -1) {
59951e66a47SVivek Prakash 				if (_ti_find_cap(&tic->nums, 'n', ind) != NULL)
60051e66a47SVivek Prakash 					continue;
60151e66a47SVivek Prakash 				if (_ti_grow_tbuf(&tic->nums,
60251e66a47SVivek Prakash 					sizeof(uint16_t) * 2) == NULL)
60351e66a47SVivek Prakash 					goto error;
60451e66a47SVivek Prakash 				le16enc(tic->nums.buf + tic->nums.bufpos, ind);
60551e66a47SVivek Prakash 				tic->nums.bufpos += sizeof(uint16_t);
60651e66a47SVivek Prakash 				le16enc(tic->nums.buf + tic->nums.bufpos,
6070c3ae37fSLionel Sambuc 					(uint16_t)CANCELLED_NUMERIC);
60851e66a47SVivek Prakash 				tic->nums.bufpos += sizeof(uint16_t);
60951e66a47SVivek Prakash 				tic->nums.entries++;
61051e66a47SVivek Prakash 				continue;
61151e66a47SVivek Prakash 			} else if ((ind = _ti_strindex(token)) != -1) {
61251e66a47SVivek Prakash 				if (_ti_find_cap(&tic->strs, 's', ind) != NULL)
61351e66a47SVivek Prakash 					continue;
61451e66a47SVivek Prakash 				if (_ti_grow_tbuf(&tic->strs,
61551e66a47SVivek Prakash 					(sizeof(uint16_t) * 2) + 1) == NULL)
61651e66a47SVivek Prakash 					goto error;
61751e66a47SVivek Prakash 				le16enc(tic->strs.buf + tic->strs.bufpos, ind);
61851e66a47SVivek Prakash 				tic->strs.bufpos += sizeof(uint16_t);
61951e66a47SVivek Prakash 				le16enc(tic->strs.buf + tic->strs.bufpos, 0);
62051e66a47SVivek Prakash 				tic->strs.bufpos += sizeof(uint16_t);
62151e66a47SVivek Prakash 				tic->strs.entries++;
62251e66a47SVivek Prakash 				continue;
62351e66a47SVivek Prakash 			}
62451e66a47SVivek Prakash 		}
62551e66a47SVivek Prakash 		if (ind == -1)
62651e66a47SVivek Prakash 			_ti_store_extra(tic, 1, token, 'f', flag, 0, NULL, 0,
62751e66a47SVivek Prakash 			    flags);
62851e66a47SVivek Prakash 		else if (_ti_find_cap(&tic->flags, 'f', ind) == NULL) {
62951e66a47SVivek Prakash 			if (_ti_grow_tbuf(&tic->flags, sizeof(uint16_t) + 1)
63051e66a47SVivek Prakash 			    == NULL)
63151e66a47SVivek Prakash 				goto error;
63251e66a47SVivek Prakash 			le16enc(tic->flags.buf + tic->flags.bufpos, ind);
63351e66a47SVivek Prakash 			tic->flags.bufpos += sizeof(uint16_t);
63451e66a47SVivek Prakash 			tic->flags.buf[tic->flags.bufpos++] = flag;
63551e66a47SVivek Prakash 			tic->flags.entries++;
63651e66a47SVivek Prakash 		}
63751e66a47SVivek Prakash 	}
63851e66a47SVivek Prakash 
63951e66a47SVivek Prakash 	free(buf.buf);
64051e66a47SVivek Prakash 	return tic;
64151e66a47SVivek Prakash 
64251e66a47SVivek Prakash error:
64351e66a47SVivek Prakash 	free(buf.buf);
64451e66a47SVivek Prakash 	_ti_freetic(tic);
64551e66a47SVivek Prakash 	return NULL;
64651e66a47SVivek Prakash }
64751e66a47SVivek Prakash 
64851e66a47SVivek Prakash void
_ti_freetic(TIC * tic)64951e66a47SVivek Prakash _ti_freetic(TIC *tic)
65051e66a47SVivek Prakash {
65151e66a47SVivek Prakash 
65251e66a47SVivek Prakash 	if (tic != NULL) {
65351e66a47SVivek Prakash 		free(tic->name);
65451e66a47SVivek Prakash 		free(tic->alias);
65551e66a47SVivek Prakash 		free(tic->desc);
6560c3ae37fSLionel Sambuc 		free(tic->extras.buf);
65751e66a47SVivek Prakash 		free(tic->flags.buf);
65851e66a47SVivek Prakash 		free(tic->nums.buf);
65951e66a47SVivek Prakash 		free(tic->strs.buf);
66051e66a47SVivek Prakash 		free(tic);
66151e66a47SVivek Prakash 	}
66251e66a47SVivek Prakash }
663