xref: /netbsd-src/lib/libterminfo/compile.c (revision f236a33b9767db20ab0131dc3afa8e97bb98af79)
1*f236a33bSroy /* $NetBSD: compile.c,v 1.26 2020/06/21 15:05:23 roy Exp $ */
2fde317d2Sroy 
3fde317d2Sroy /*
4aadfdb11Sroy  * Copyright (c) 2009, 2010, 2011, 2020 The NetBSD Foundation, Inc.
5fde317d2Sroy  *
6fde317d2Sroy  * This code is derived from software contributed to The NetBSD Foundation
7fde317d2Sroy  * by Roy Marples.
8fde317d2Sroy  *
9fde317d2Sroy  * Redistribution and use in source and binary forms, with or without
10fde317d2Sroy  * modification, are permitted provided that the following conditions
11fde317d2Sroy  * are met:
12fde317d2Sroy  * 1. Redistributions of source code must retain the above copyright
13fde317d2Sroy  *    notice, this list of conditions and the following disclaimer.
14fde317d2Sroy  * 2. Redistributions in binary form must reproduce the above copyright
15fde317d2Sroy  *    notice, this list of conditions and the following disclaimer in the
16fde317d2Sroy  *    documentation and/or other materials provided with the distribution.
17fde317d2Sroy  *
18fde317d2Sroy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19fde317d2Sroy  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20fde317d2Sroy  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21fde317d2Sroy  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22fde317d2Sroy  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23fde317d2Sroy  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24fde317d2Sroy  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25fde317d2Sroy  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26fde317d2Sroy  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27fde317d2Sroy  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28fde317d2Sroy  */
29fde317d2Sroy 
30fde317d2Sroy #if HAVE_NBTOOL_CONFIG_H
31fde317d2Sroy #include "nbtool_config.h"
32fde317d2Sroy #endif
33fde317d2Sroy 
34fde317d2Sroy #include <sys/cdefs.h>
35*f236a33bSroy __RCSID("$NetBSD: compile.c,v 1.26 2020/06/21 15:05:23 roy Exp $");
365c7d0d1fSdholland 
375c7d0d1fSdholland #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
385c7d0d1fSdholland #include <sys/endian.h>
395c7d0d1fSdholland #endif
40fde317d2Sroy 
41fde317d2Sroy #include <assert.h>
42fde317d2Sroy #include <ctype.h>
43fde317d2Sroy #include <err.h>
44fde317d2Sroy #include <errno.h>
45fde317d2Sroy #include <limits.h>
46fde317d2Sroy #include <stdarg.h>
47fde317d2Sroy #include <stdlib.h>
48fde317d2Sroy #include <stdint.h>
49fde317d2Sroy #include <stdio.h>
50fde317d2Sroy #include <string.h>
51fde317d2Sroy #include <term_private.h>
52fde317d2Sroy #include <term.h>
53fde317d2Sroy 
5493a30e6dSjoerg static void __printflike(2, 3)
dowarn(int flags,const char * fmt,...)55fde317d2Sroy dowarn(int flags, const char *fmt, ...)
56fde317d2Sroy {
57fde317d2Sroy 	va_list va;
58fde317d2Sroy 
59fde317d2Sroy 	errno = EINVAL;
60fde317d2Sroy 	if (flags & TIC_WARNING) {
61fde317d2Sroy 		va_start(va, fmt);
62fde317d2Sroy 		vwarnx(fmt, va);
63fde317d2Sroy 		va_end(va);
64fde317d2Sroy 	}
65fde317d2Sroy }
66fde317d2Sroy 
679e387da6Sroy #ifdef TERMINFO_COMPAT
685159a425Sroy int
_ti_promote(TIC * tic)695159a425Sroy _ti_promote(TIC *tic)
705159a425Sroy {
717f0204b5Sroy 	char *obuf, type, flag, *buf, *delim, *name, *nbuf;
725159a425Sroy 	const char *cap, *code, *str;
735159a425Sroy 	size_t n, entries, strl;
745159a425Sroy 	uint16_t ind;
755159a425Sroy 	int num, ortype, error = 0;
765159a425Sroy 
775159a425Sroy 	ortype = tic->rtype;
785159a425Sroy 	tic->rtype = TERMINFO_RTYPE;
795159a425Sroy 	obuf = tic->name;
805159a425Sroy 	tic->name = _ti_getname(tic->rtype, tic->name);
815159a425Sroy 	if (tic->name == NULL) {
825159a425Sroy 		warn("_ti_getname");
835159a425Sroy 		tic->name = obuf;
845159a425Sroy 		return -1;
855159a425Sroy 	}
865159a425Sroy 	free(obuf);
875159a425Sroy 
887f0204b5Sroy 	n = 0;
897f0204b5Sroy 	obuf = buf = tic->alias;
907f0204b5Sroy 	tic->alias = NULL;
917f0204b5Sroy 	while (buf != NULL) {
927f0204b5Sroy 		delim = strchr(buf, '|');
937f0204b5Sroy 		if (delim != NULL)
947f0204b5Sroy 			*delim++ = '\0';
957f0204b5Sroy 		name = _ti_getname(tic->rtype, buf);
967f0204b5Sroy 		strl = strlen(name) + 1;
977f0204b5Sroy 		nbuf = realloc(tic->alias, n + strl);
987f0204b5Sroy 		if (nbuf == NULL) {
997f0204b5Sroy 			free(name);
1007f0204b5Sroy 			return -1;
1017f0204b5Sroy 		}
1027f0204b5Sroy 		tic->alias = nbuf;
1037f0204b5Sroy 		memcpy(tic->alias + n, name, strl);
1047f0204b5Sroy 		n += strl;
1057f0204b5Sroy 		free(name);
1067f0204b5Sroy 		buf = delim;
1077f0204b5Sroy 	}
1087f0204b5Sroy 	free(obuf);
1097f0204b5Sroy 
1105159a425Sroy 	obuf = tic->nums.buf;
1115159a425Sroy 	cap = obuf;
1125159a425Sroy 	entries = tic->nums.entries;
1135159a425Sroy 	tic->nums.buf = NULL;
1145159a425Sroy 	tic->nums.entries = tic->nums.buflen = tic->nums.bufpos = 0;
1155159a425Sroy 	for (n = entries; n > 0; n--) {
1165159a425Sroy 		ind = _ti_decode_16(&cap);
1175159a425Sroy 		num = _ti_decode_num(&cap, ortype);
1185159a425Sroy 		if (VALID_NUMERIC(num) &&
1195159a425Sroy 		    !_ti_encode_buf_id_num(&tic->nums, ind, num,
1205159a425Sroy 		    _ti_numsize(tic)))
1215159a425Sroy 		{
1225159a425Sroy 			warn("promote num");
1235159a425Sroy 			error = -1;
1245159a425Sroy 			break;
1255159a425Sroy 		}
1265159a425Sroy 	}
1275159a425Sroy 	free(obuf);
1285159a425Sroy 
1295159a425Sroy 	obuf = tic->extras.buf;
1305159a425Sroy 	cap = obuf;
1315159a425Sroy 	entries = tic->extras.entries;
1325159a425Sroy 	tic->extras.buf = NULL;
1335159a425Sroy 	tic->extras.entries = tic->extras.buflen = tic->extras.bufpos = 0;
1345159a425Sroy 	for (n = entries; n > 0; n--) {
1355159a425Sroy 		num = _ti_decode_16(&cap);
1362d748ff8Sroy 		flag = 0; /* satisfy gcc, won't be used for non flag types */
1372d748ff8Sroy 		str = NULL; /* satisfy gcc, won't be used as strl is 0 */
1385159a425Sroy 		strl = 0;
1395159a425Sroy 		code = cap;
1405159a425Sroy 		cap += num;
1415159a425Sroy 		type = *cap++;
1425159a425Sroy 		switch (type) {
1435159a425Sroy 		case 'f':
1445159a425Sroy 			flag = *cap++;
1455159a425Sroy 			break;
1465159a425Sroy 		case 'n':
1475159a425Sroy 			num = _ti_decode_num(&cap, ortype);
1485159a425Sroy 			break;
1495159a425Sroy 		case 's':
1505159a425Sroy 			strl = _ti_decode_16(&cap);
1515159a425Sroy 			str = cap;
1525159a425Sroy 			cap += strl;
1535159a425Sroy 			break;
1545159a425Sroy 		default:
1555159a425Sroy 			errno = EINVAL;
1565159a425Sroy 			break;
1575159a425Sroy 		}
1585159a425Sroy 		if (!_ti_store_extra(tic, 0, code, type, flag, num,
1595159a425Sroy 		    str, strl, TIC_EXTRA))
1605159a425Sroy 		{
1615159a425Sroy 			error = -1;
1625159a425Sroy 			break;
1635159a425Sroy 		}
1645159a425Sroy 	}
1655159a425Sroy 	free(obuf);
1665159a425Sroy 
1675159a425Sroy 	return error;
1685159a425Sroy }
1699e387da6Sroy #endif
1705159a425Sroy 
171fde317d2Sroy char *
_ti_grow_tbuf(TBUF * tbuf,size_t len)172fde317d2Sroy _ti_grow_tbuf(TBUF *tbuf, size_t len)
173fde317d2Sroy {
174fde317d2Sroy 	char *buf;
175fde317d2Sroy 	size_t l;
176fde317d2Sroy 
177fde317d2Sroy 	_DIAGASSERT(tbuf != NULL);
178fde317d2Sroy 
179fde317d2Sroy 	l = tbuf->bufpos + len;
180fde317d2Sroy 	if (l > tbuf->buflen) {
18168a65e1aSjoerg 		if (tbuf->buflen == 0)
182fde317d2Sroy 			buf = malloc(l);
183fde317d2Sroy 		else
184fde317d2Sroy 			buf = realloc(tbuf->buf, l);
185fde317d2Sroy 		if (buf == NULL)
186fde317d2Sroy 			return NULL;
187fde317d2Sroy 		tbuf->buf = buf;
188fde317d2Sroy 		tbuf->buflen = l;
189fde317d2Sroy 	}
190fde317d2Sroy 	return tbuf->buf;
191fde317d2Sroy }
192fde317d2Sroy 
1931d30fdaeSchristos const char *
_ti_find_cap(TIC * tic,TBUF * tbuf,char type,short ind)1943958d16aSchristos _ti_find_cap(TIC *tic, TBUF *tbuf, char type, short ind)
195fde317d2Sroy {
196fde317d2Sroy 	size_t n;
19734c6060fSroy 	uint16_t num;
1981d30fdaeSchristos 	const char *cap;
199fde317d2Sroy 
200fde317d2Sroy 	_DIAGASSERT(tbuf != NULL);
201fde317d2Sroy 
202fde317d2Sroy 	cap = tbuf->buf;
203fde317d2Sroy 	for (n = tbuf->entries; n > 0; n--) {
2041d30fdaeSchristos 		num = _ti_decode_16(&cap);
20534c6060fSroy 		if ((short)num == ind)
206fde317d2Sroy 			return cap;
207fde317d2Sroy 		switch (type) {
208fde317d2Sroy 		case 'f':
209fde317d2Sroy 			cap++;
210fde317d2Sroy 			break;
211fde317d2Sroy 		case 'n':
2123958d16aSchristos 			cap += _ti_numsize(tic);
213fde317d2Sroy 			break;
214fde317d2Sroy 		case 's':
2151d30fdaeSchristos 			num = _ti_decode_16(&cap);
216fde317d2Sroy 			cap += num;
217fde317d2Sroy 			break;
218fde317d2Sroy 		}
219fde317d2Sroy 	}
220fde317d2Sroy 
221fde317d2Sroy 	errno = ESRCH;
222fde317d2Sroy 	return NULL;
223fde317d2Sroy }
224fde317d2Sroy 
2251d30fdaeSchristos const char *
_ti_find_extra(TIC * tic,TBUF * tbuf,const char * code)2263958d16aSchristos _ti_find_extra(TIC *tic, TBUF *tbuf, const char *code)
227fde317d2Sroy {
228fde317d2Sroy 	size_t n;
22934c6060fSroy 	uint16_t num;
2301d30fdaeSchristos 	const char *cap;
231fde317d2Sroy 
232fde317d2Sroy 	_DIAGASSERT(tbuf != NULL);
233fde317d2Sroy 	_DIAGASSERT(code != NULL);
234fde317d2Sroy 
235fde317d2Sroy 	cap = tbuf->buf;
236fde317d2Sroy 	for (n = tbuf->entries; n > 0; n--) {
2371d30fdaeSchristos 		num = _ti_decode_16(&cap);
238fde317d2Sroy 		if (strcmp(cap, code) == 0)
239fde317d2Sroy 			return cap + num;
240fde317d2Sroy 		cap += num;
241fde317d2Sroy 		switch (*cap++) {
242fde317d2Sroy 		case 'f':
243fde317d2Sroy 			cap++;
244fde317d2Sroy 			break;
245fde317d2Sroy 		case 'n':
2463958d16aSchristos 			cap += _ti_numsize(tic);
247fde317d2Sroy 			break;
248fde317d2Sroy 		case 's':
2491d30fdaeSchristos 			num = _ti_decode_16(&cap);
250fde317d2Sroy 			cap += num;
251fde317d2Sroy 			break;
252fde317d2Sroy 		}
253fde317d2Sroy 	}
254fde317d2Sroy 
255fde317d2Sroy 	errno = ESRCH;
256fde317d2Sroy 	return NULL;
257fde317d2Sroy }
258fde317d2Sroy 
2593958d16aSchristos char *
_ti_getname(int rtype,const char * orig)2603958d16aSchristos _ti_getname(int rtype, const char *orig)
2613958d16aSchristos {
2629e387da6Sroy #ifdef TERMINFO_COMPAT
26359ea2669Sroy 	const char *delim;
2643958d16aSchristos 	char *name;
26559ea2669Sroy 	const char *verstr;
26659ea2669Sroy 	size_t diff, vlen;
2673958d16aSchristos 
26859ea2669Sroy 	switch (rtype) {
26959ea2669Sroy 	case TERMINFO_RTYPE:
27059ea2669Sroy 		verstr = TERMINFO_VDELIMSTR "v3";
27159ea2669Sroy 		break;
27259ea2669Sroy 	case TERMINFO_RTYPE_O1:
27359ea2669Sroy 		verstr = "";
27459ea2669Sroy 		break;
27559ea2669Sroy 	default:
27659ea2669Sroy 		errno = EINVAL;
27759ea2669Sroy 		return NULL;
2783958d16aSchristos 	}
27959ea2669Sroy 
28059ea2669Sroy 	delim = orig;
28159ea2669Sroy 	while (*delim != '\0' && *delim != TERMINFO_VDELIM)
28259ea2669Sroy 		delim++;
28359ea2669Sroy 	diff = delim - orig;
28459ea2669Sroy 	vlen = strlen(verstr);
28559ea2669Sroy 	name = malloc(diff + vlen + 1);
28659ea2669Sroy 	if (name == NULL)
28759ea2669Sroy 		return NULL;
28859ea2669Sroy 
28959ea2669Sroy 	memcpy(name, orig, diff);
29059ea2669Sroy 	memcpy(name + diff, verstr, vlen + 1);
2913958d16aSchristos 	return name;
2929e387da6Sroy #else
2939e387da6Sroy 	return strdup(orig);
2949e387da6Sroy #endif
2953958d16aSchristos }
2963958d16aSchristos 
297fde317d2Sroy size_t
_ti_store_extra(TIC * tic,int wrn,const char * id,char type,char flag,int num,const char * str,size_t strl,int flags)2983958d16aSchristos _ti_store_extra(TIC *tic, int wrn, const char *id, char type, char flag,
2993958d16aSchristos     int num, const char *str, size_t strl, int flags)
300fde317d2Sroy {
3015159a425Sroy 	size_t l, capl;
302fde317d2Sroy 
303fde317d2Sroy 	_DIAGASSERT(tic != NULL);
304fde317d2Sroy 
305fde317d2Sroy 	if (strcmp(id, "use") != 0) {
3063958d16aSchristos 		if (_ti_find_extra(tic, &tic->extras, id) != NULL)
307fde317d2Sroy 			return 0;
308fde317d2Sroy 		if (!(flags & TIC_EXTRA)) {
309fde317d2Sroy 			if (wrn != 0)
310fde317d2Sroy 				dowarn(flags, "%s: %s: unknown capability",
311fde317d2Sroy 				    tic->name, id);
312fde317d2Sroy 			return 0;
313fde317d2Sroy 		}
314fde317d2Sroy 	}
315fde317d2Sroy 
316fde317d2Sroy 	l = strlen(id) + 1;
3175159a425Sroy 	if (l > UINT16_MAX) {
318fde317d2Sroy 		dowarn(flags, "%s: %s: cap name is too long", tic->name, id);
319fde317d2Sroy 		return 0;
320fde317d2Sroy 	}
321fde317d2Sroy 
3225159a425Sroy 	capl = sizeof(uint16_t) + l + 1;
3235159a425Sroy 	switch (type) {
3245159a425Sroy 	case 'f':
3255159a425Sroy 		capl++;
3265159a425Sroy 		break;
3275159a425Sroy 	case 'n':
3285159a425Sroy 		capl += _ti_numsize(tic);
3295159a425Sroy 		break;
3305159a425Sroy 	case 's':
3315159a425Sroy 		capl += sizeof(uint16_t) + strl;
3325159a425Sroy 		break;
3335159a425Sroy 	}
3345159a425Sroy 
3355159a425Sroy 	if (!_ti_grow_tbuf(&tic->extras, capl))
336fde317d2Sroy 		return 0;
3371d30fdaeSchristos 	_ti_encode_buf_count_str(&tic->extras, id, l);
338fde317d2Sroy 	tic->extras.buf[tic->extras.bufpos++] = type;
339fde317d2Sroy 	switch (type) {
340fde317d2Sroy 	case 'f':
341fde317d2Sroy 		tic->extras.buf[tic->extras.bufpos++] = flag;
342fde317d2Sroy 		break;
343fde317d2Sroy 	case 'n':
3441d30fdaeSchristos 		_ti_encode_buf_num(&tic->extras, num, tic->rtype);
345fde317d2Sroy 		break;
346fde317d2Sroy 	case 's':
3471d30fdaeSchristos 		_ti_encode_buf_count_str(&tic->extras, str, strl);
348fde317d2Sroy 		break;
349fde317d2Sroy 	}
350fde317d2Sroy 	tic->extras.entries++;
351fde317d2Sroy 	return 1;
352fde317d2Sroy }
353fde317d2Sroy 
3541d30fdaeSchristos static void
_ti_encode_buf(char ** cap,const TBUF * buf)3551d30fdaeSchristos _ti_encode_buf(char **cap, const TBUF *buf)
3561d30fdaeSchristos {
3571d30fdaeSchristos 	if (buf->entries == 0) {
3581d30fdaeSchristos 		_ti_encode_16(cap, 0);
3591d30fdaeSchristos 	} else {
3601d30fdaeSchristos 		_ti_encode_16(cap, buf->bufpos + sizeof(uint16_t));
3611d30fdaeSchristos 		_ti_encode_16(cap, buf->entries);
3621d30fdaeSchristos 		_ti_encode_str(cap, buf->buf, buf->bufpos);
3631d30fdaeSchristos 	}
3641d30fdaeSchristos }
3651d30fdaeSchristos 
366fde317d2Sroy ssize_t
_ti_flatten(uint8_t ** buf,const TIC * tic)367fde317d2Sroy _ti_flatten(uint8_t **buf, const TIC *tic)
368fde317d2Sroy {
369fde317d2Sroy 	size_t buflen, len, alen, dlen;
3701d30fdaeSchristos 	char *cap;
371fde317d2Sroy 
372fde317d2Sroy 	_DIAGASSERT(buf != NULL);
373fde317d2Sroy 	_DIAGASSERT(tic != NULL);
374fde317d2Sroy 
375fde317d2Sroy 	len = strlen(tic->name) + 1;
376fde317d2Sroy 	if (tic->alias == NULL)
377fde317d2Sroy 		alen = 0;
378fde317d2Sroy 	else
379fde317d2Sroy 		alen = strlen(tic->alias) + 1;
380fde317d2Sroy 	if (tic->desc == NULL)
381fde317d2Sroy 		dlen = 0;
382fde317d2Sroy 	else
383fde317d2Sroy 		dlen = strlen(tic->desc) + 1;
3841d30fdaeSchristos 
385fde317d2Sroy 	buflen = sizeof(char) +
386fde317d2Sroy 	    sizeof(uint16_t) + len +
387fde317d2Sroy 	    sizeof(uint16_t) + alen +
388fde317d2Sroy 	    sizeof(uint16_t) + dlen +
389fde317d2Sroy 	    (sizeof(uint16_t) * 2) + tic->flags.bufpos +
390fde317d2Sroy 	    (sizeof(uint16_t) * 2) + tic->nums.bufpos +
391fde317d2Sroy 	    (sizeof(uint16_t) * 2) + tic->strs.bufpos +
392fde317d2Sroy 	    (sizeof(uint16_t) * 2) + tic->extras.bufpos;
3931d30fdaeSchristos 
394fde317d2Sroy 	*buf = malloc(buflen);
395fde317d2Sroy 	if (*buf == NULL)
396fde317d2Sroy 		return -1;
397fde317d2Sroy 
3981d30fdaeSchristos 	cap = (char *)*buf;
3993958d16aSchristos 	*cap++ = tic->rtype;
400fde317d2Sroy 
4011d30fdaeSchristos 	_ti_encode_count_str(&cap, tic->name, len);
4021d30fdaeSchristos 	_ti_encode_count_str(&cap, tic->alias, alen);
4031d30fdaeSchristos 	_ti_encode_count_str(&cap, tic->desc, dlen);
404fde317d2Sroy 
4051d30fdaeSchristos 	_ti_encode_buf(&cap, &tic->flags);
406fde317d2Sroy 
4071d30fdaeSchristos 	_ti_encode_buf(&cap, &tic->nums);
4081d30fdaeSchristos 	_ti_encode_buf(&cap, &tic->strs);
4091d30fdaeSchristos 	_ti_encode_buf(&cap, &tic->extras);
410fde317d2Sroy 
4111d30fdaeSchristos 	return (uint8_t *)cap - *buf;
412fde317d2Sroy }
413fde317d2Sroy 
414fde317d2Sroy static int
encode_string(const char * term,const char * cap,TBUF * tbuf,const char * str,int flags)415fde317d2Sroy encode_string(const char *term, const char *cap, TBUF *tbuf, const char *str,
416fde317d2Sroy     int flags)
417fde317d2Sroy {
418fde317d2Sroy 	int slash, i, num;
419fde317d2Sroy 	char ch, *p, *s, last;
420fde317d2Sroy 
421fde317d2Sroy 	if (_ti_grow_tbuf(tbuf, strlen(str) + 1) == NULL)
422fde317d2Sroy 		return -1;
423fde317d2Sroy 	p = s = tbuf->buf + tbuf->bufpos;
424fde317d2Sroy 	slash = 0;
425fde317d2Sroy 	last = '\0';
426fde317d2Sroy 	/* Convert escape codes */
427fde317d2Sroy 	while ((ch = *str++) != '\0') {
4280fb82a6eSroy 		if (ch == '\n') {
4290fb82a6eSroy 			/* Following a newline, strip leading whitespace from
4300fb82a6eSroy 			 * capability strings. */
4310fb82a6eSroy 			while (isspace((unsigned char)*str))
4320fb82a6eSroy 				str++;
4330fb82a6eSroy 			continue;
4340fb82a6eSroy 		}
435fde317d2Sroy 		if (slash == 0 && ch == '\\') {
436fde317d2Sroy 			slash = 1;
437fde317d2Sroy 			continue;
438fde317d2Sroy 		}
439fde317d2Sroy 		if (slash == 0) {
440fde317d2Sroy 			if (last != '%' && ch == '^') {
441fde317d2Sroy 				ch = *str++;
442fde317d2Sroy 				if (((unsigned char)ch) >= 128)
443fde317d2Sroy 					dowarn(flags,
444fde317d2Sroy 					    "%s: %s: illegal ^ character",
445fde317d2Sroy 					    term, cap);
446fde317d2Sroy 				if (ch == '\0')
447fde317d2Sroy 					break;
448fde317d2Sroy 				if (ch == '?')
449fde317d2Sroy 					ch = '\177';
450fde317d2Sroy 				else if ((ch &= 037) == 0)
451ed684e08Sroy 					ch = (char)128;
4520a316e40Sroy 			} else if (!isprint((unsigned char)ch))
4530a316e40Sroy 				dowarn(flags,
4540a316e40Sroy 				    "%s: %s: unprintable character",
4550a316e40Sroy 				    term, cap);
456fde317d2Sroy 			*p++ = ch;
457fde317d2Sroy 			last = ch;
458fde317d2Sroy 			continue;
459fde317d2Sroy 		}
460fde317d2Sroy 		slash = 0;
461fde317d2Sroy 		if (ch >= '0' && ch <= '7') {
462fde317d2Sroy 			num = ch - '0';
463fde317d2Sroy 			for (i = 0; i < 2; i++) {
464fde317d2Sroy 				if (*str < '0' || *str > '7') {
465fde317d2Sroy 					if (isdigit((unsigned char)*str))
466fde317d2Sroy 						dowarn(flags,
467fde317d2Sroy 						    "%s: %s: non octal"
468fde317d2Sroy 						    " digit", term, cap);
469fde317d2Sroy 					else
470fde317d2Sroy 						break;
471fde317d2Sroy 				}
472fde317d2Sroy 				num = num * 8 + *str++ - '0';
473fde317d2Sroy 			}
474fde317d2Sroy 			if (num == 0)
475fde317d2Sroy 				num = 0200;
476fde317d2Sroy 			*p++ = (char)num;
477fde317d2Sroy 			continue;
478fde317d2Sroy 		}
479fde317d2Sroy 		switch (ch) {
480fde317d2Sroy 		case 'a':
481fde317d2Sroy 			*p++ = '\a';
482fde317d2Sroy 			break;
483fde317d2Sroy 		case 'b':
484fde317d2Sroy 			*p++ = '\b';
485fde317d2Sroy 			break;
486fde317d2Sroy 		case 'e': /* FALLTHROUGH */
487fde317d2Sroy 		case 'E':
488fde317d2Sroy 			*p++ = '\033';
489fde317d2Sroy 			break;
490fde317d2Sroy 		case 'f':
491fde317d2Sroy 			*p++ = '\014';
492fde317d2Sroy 			break;
493fde317d2Sroy 		case 'l': /* FALLTHROUGH */
494fde317d2Sroy 		case 'n':
495fde317d2Sroy 			*p++ = '\n';
496fde317d2Sroy 			break;
497fde317d2Sroy 		case 'r':
498fde317d2Sroy 			*p++ = '\r';
499fde317d2Sroy 			break;
500fde317d2Sroy 		case 's':
501fde317d2Sroy 			*p++ = ' ';
502fde317d2Sroy 			break;
503fde317d2Sroy 		case 't':
504fde317d2Sroy 			*p++ = '\t';
505fde317d2Sroy 			break;
506fde317d2Sroy 		default:
507fde317d2Sroy 			/* We should warn here */
508fde317d2Sroy 		case '^':
509fde317d2Sroy 		case ',':
510fde317d2Sroy 		case ':':
511fde317d2Sroy 		case '|':
512fde317d2Sroy 			*p++ = ch;
513fde317d2Sroy 			break;
514fde317d2Sroy 		}
515fde317d2Sroy 		last = ch;
516fde317d2Sroy 	}
517fde317d2Sroy 	*p++ = '\0';
51834c6060fSroy 	tbuf->bufpos += (size_t)(p - s);
519fde317d2Sroy 	return 0;
520fde317d2Sroy }
521fde317d2Sroy 
5224b2d6106Sroy char *
_ti_get_token(char ** cap,char sep)5234b2d6106Sroy _ti_get_token(char **cap, char sep)
524fde317d2Sroy {
5254b2d6106Sroy 	char esc, *token;
526fde317d2Sroy 
527fde317d2Sroy 	while (isspace((unsigned char)**cap))
528fde317d2Sroy 		(*cap)++;
529fde317d2Sroy 	if (**cap == '\0')
530fde317d2Sroy 		return NULL;
531fde317d2Sroy 
532fde317d2Sroy 	/* We can't use stresep(3) as ^ we need two escape chars */
5334b2d6106Sroy 	esc = '\0';
534fde317d2Sroy 	for (token = *cap;
5354b2d6106Sroy 	     **cap != '\0' && (esc != '\0' || **cap != sep);
536fde317d2Sroy 	     (*cap)++)
537fde317d2Sroy 	{
5384b2d6106Sroy 		if (esc == '\0') {
539fde317d2Sroy 			if (**cap == '\\' || **cap == '^')
5404b2d6106Sroy 				esc = **cap;
5414b2d6106Sroy 		} else {
5424b2d6106Sroy 			/* termcap /E/ is valid */
5434b2d6106Sroy 			if (sep == ':' && esc == '\\' && **cap == 'E')
5444b2d6106Sroy 				esc = 'x';
5454b2d6106Sroy 			else
5464b2d6106Sroy 				esc = '\0';
5474b2d6106Sroy 		}
548fde317d2Sroy 	}
549fde317d2Sroy 
550fde317d2Sroy 	if (**cap != '\0')
551fde317d2Sroy 		*(*cap)++ = '\0';
552fde317d2Sroy 
553fde317d2Sroy 	return token;
554fde317d2Sroy }
555fde317d2Sroy 
5561d30fdaeSchristos int
_ti_encode_buf_id_num(TBUF * tbuf,int ind,int num,size_t len)5571d30fdaeSchristos _ti_encode_buf_id_num(TBUF *tbuf, int ind, int num, size_t len)
5581d30fdaeSchristos {
5591d30fdaeSchristos 	if (!_ti_grow_tbuf(tbuf, sizeof(uint16_t) + len))
5601d30fdaeSchristos 		return 0;
5611d30fdaeSchristos 	_ti_encode_buf_16(tbuf, ind);
5621d30fdaeSchristos 	if (len == sizeof(uint32_t))
563*f236a33bSroy 		_ti_encode_buf_32(tbuf, (uint32_t)num);
5641d30fdaeSchristos 	else
565*f236a33bSroy 		_ti_encode_buf_16(tbuf, (uint16_t)num);
5661d30fdaeSchristos 	tbuf->entries++;
5671d30fdaeSchristos 	return 1;
5681d30fdaeSchristos }
5691d30fdaeSchristos 
5701d30fdaeSchristos int
_ti_encode_buf_id_count_str(TBUF * tbuf,int ind,const void * buf,size_t len)5711d30fdaeSchristos _ti_encode_buf_id_count_str(TBUF *tbuf, int ind, const void *buf, size_t len)
5721d30fdaeSchristos {
5731d30fdaeSchristos 	if (!_ti_grow_tbuf(tbuf, 2 * sizeof(uint16_t) + len))
5741d30fdaeSchristos 		return 0;
5751d30fdaeSchristos 	_ti_encode_buf_16(tbuf, ind);
5761d30fdaeSchristos 	_ti_encode_buf_count_str(tbuf, buf, len);
5771d30fdaeSchristos 	tbuf->entries++;
5781d30fdaeSchristos 	return 1;
5791d30fdaeSchristos }
5801d30fdaeSchristos 
5811d30fdaeSchristos int
_ti_encode_buf_id_flags(TBUF * tbuf,int ind,int flag)5821d30fdaeSchristos _ti_encode_buf_id_flags(TBUF *tbuf, int ind, int flag)
5831d30fdaeSchristos {
5841d30fdaeSchristos 	if (!_ti_grow_tbuf(tbuf, sizeof(uint16_t) + 1))
5851d30fdaeSchristos 		return 0;
5861d30fdaeSchristos 	_ti_encode_buf_16(tbuf, ind);
5871d30fdaeSchristos 	tbuf->buf[tbuf->bufpos++] = flag;
5881d30fdaeSchristos 	tbuf->entries++;
5891d30fdaeSchristos 	return 1;
5901d30fdaeSchristos }
5911d30fdaeSchristos 
592fde317d2Sroy TIC *
_ti_compile(char * cap,int flags)593fde317d2Sroy _ti_compile(char *cap, int flags)
594fde317d2Sroy {
595fde317d2Sroy 	char *token, *p, *e, *name, *desc, *alias;
596fde317d2Sroy 	signed char flag;
597ed684e08Sroy 	long cnum;
598aadfdb11Sroy 	short ind;
599aadfdb11Sroy 	int num;
600fde317d2Sroy 	size_t len;
601fde317d2Sroy 	TBUF buf;
602fde317d2Sroy 	TIC *tic;
603fde317d2Sroy 
604fde317d2Sroy 	_DIAGASSERT(cap != NULL);
605fde317d2Sroy 
6064b2d6106Sroy 	name = _ti_get_token(&cap, ',');
607fde317d2Sroy 	if (name == NULL) {
6083958d16aSchristos 		dowarn(flags, "no separator found: %s", cap);
609fde317d2Sroy 		return NULL;
610fde317d2Sroy 	}
611fde317d2Sroy 	desc = strrchr(name, '|');
612fde317d2Sroy 	if (desc != NULL)
613fde317d2Sroy 		*desc++ = '\0';
614fde317d2Sroy 	alias = strchr(name, '|');
615fde317d2Sroy 	if (alias != NULL)
616fde317d2Sroy 		*alias++ = '\0';
617fde317d2Sroy 
618aadfdb11Sroy 	if (strlen(name) > UINT16_MAX - 1) {
619aadfdb11Sroy 		dowarn(flags, "%s: name too long", name);
620aadfdb11Sroy 		return NULL;
621aadfdb11Sroy 	}
622aadfdb11Sroy 	if (desc != NULL && strlen(desc) > UINT16_MAX - 1) {
623aadfdb11Sroy 		dowarn(flags, "%s: description too long: %s", name, desc);
624aadfdb11Sroy 		return NULL;
625aadfdb11Sroy 	}
626aadfdb11Sroy 	if (alias != NULL && strlen(alias) > UINT16_MAX - 1) {
627aadfdb11Sroy 		dowarn(flags, "%s: alias too long: %s", name, alias);
628aadfdb11Sroy 		return NULL;
629aadfdb11Sroy 	}
630aadfdb11Sroy 
631fde317d2Sroy 	tic = calloc(sizeof(*tic), 1);
632fde317d2Sroy 	if (tic == NULL)
633fde317d2Sroy 		return NULL;
634fde317d2Sroy 
6359e387da6Sroy #ifdef TERMINFO_COMPAT
6365159a425Sroy 	tic->rtype = TERMINFO_RTYPE_O1; /* will promote if needed */
6379e387da6Sroy #else
6389e387da6Sroy 	tic->rtype = TERMINFO_RTYPE;
6399e387da6Sroy #endif
640fde317d2Sroy 	buf.buf = NULL;
641fde317d2Sroy 	buf.buflen = 0;
642fde317d2Sroy 
6433958d16aSchristos 	tic->name = _ti_getname(tic->rtype, name);
644fde317d2Sroy 	if (tic->name == NULL)
645fde317d2Sroy 		goto error;
646fde317d2Sroy 	if (alias != NULL && flags & TIC_ALIAS) {
6473958d16aSchristos 		tic->alias = _ti_getname(tic->rtype, alias);
648fde317d2Sroy 		if (tic->alias == NULL)
649fde317d2Sroy 			goto error;
650fde317d2Sroy 	}
651fde317d2Sroy 	if (desc != NULL && flags & TIC_DESCRIPTION) {
652fde317d2Sroy 		tic->desc = strdup(desc);
653fde317d2Sroy 		if (tic->desc == NULL)
654fde317d2Sroy 			goto error;
655fde317d2Sroy 	}
656fde317d2Sroy 
6574b2d6106Sroy 	for (token = _ti_get_token(&cap, ',');
658fde317d2Sroy 	     token != NULL && *token != '\0';
6594b2d6106Sroy 	     token = _ti_get_token(&cap, ','))
660fde317d2Sroy 	{
661fde317d2Sroy 		/* Skip commented caps */
662fde317d2Sroy 		if (!(flags & TIC_COMMENT) && token[0] == '.')
663fde317d2Sroy 			continue;
664fde317d2Sroy 
665fde317d2Sroy 		/* Obsolete entries */
666fde317d2Sroy 		if (token[0] == 'O' && token[1] == 'T') {
667fde317d2Sroy 			if (!(flags & TIC_EXTRA))
668fde317d2Sroy 				continue;
669fde317d2Sroy 			token += 2;
670fde317d2Sroy 		}
671fde317d2Sroy 
672fde317d2Sroy 		/* str cap */
673fde317d2Sroy 		p = strchr(token, '=');
674fde317d2Sroy 		if (p != NULL) {
675fde317d2Sroy 			*p++ = '\0';
676fde317d2Sroy 			/* Don't use the string if we already have it */
67734c6060fSroy 			ind = (short)_ti_strindex(token);
678fde317d2Sroy 			if (ind != -1 &&
6793958d16aSchristos 			    _ti_find_cap(tic, &tic->strs, 's', ind) != NULL)
680fde317d2Sroy 				continue;
681fde317d2Sroy 
682fde317d2Sroy 			/* Encode the string to our scratch buffer */
683fde317d2Sroy 			buf.bufpos = 0;
684fde317d2Sroy 			if (encode_string(tic->name, token,
685fde317d2Sroy 				&buf, p, flags) == -1)
686fde317d2Sroy 				goto error;
687aadfdb11Sroy 			if (buf.bufpos > UINT16_MAX - 1) {
688fde317d2Sroy 				dowarn(flags, "%s: %s: string is too long",
689fde317d2Sroy 				    tic->name, token);
690fde317d2Sroy 				continue;
691fde317d2Sroy 			}
692fde317d2Sroy 			if (!VALID_STRING(buf.buf)) {
693fde317d2Sroy 				dowarn(flags, "%s: %s: invalid string",
694fde317d2Sroy 				    tic->name, token);
695fde317d2Sroy 				continue;
696fde317d2Sroy 			}
697fde317d2Sroy 
6981d30fdaeSchristos 			if (ind == -1) {
6991d30fdaeSchristos 				if (!_ti_store_extra(tic, 1, token, 's', -1, -2,
7001d30fdaeSchristos 				    buf.buf, buf.bufpos, flags))
701fde317d2Sroy 					goto error;
7021d30fdaeSchristos 			} else {
7031d30fdaeSchristos 				if (!_ti_encode_buf_id_count_str(&tic->strs,
7041d30fdaeSchristos 				    ind, buf.buf, buf.bufpos))
7051d30fdaeSchristos 					goto error;
706fde317d2Sroy 			}
707fde317d2Sroy 			continue;
708fde317d2Sroy 		}
709fde317d2Sroy 
710fde317d2Sroy 		/* num cap */
711fde317d2Sroy 		p = strchr(token, '#');
712fde317d2Sroy 		if (p != NULL) {
713fde317d2Sroy 			*p++ = '\0';
714fde317d2Sroy 			/* Don't use the number if we already have it */
71534c6060fSroy 			ind = (short)_ti_numindex(token);
716fde317d2Sroy 			if (ind != -1 &&
7173958d16aSchristos 			    _ti_find_cap(tic, &tic->nums, 'n', ind) != NULL)
718fde317d2Sroy 				continue;
719fde317d2Sroy 
720ed684e08Sroy 			cnum = strtol(p, &e, 0);
721fde317d2Sroy 			if (*e != '\0') {
722fde317d2Sroy 				dowarn(flags, "%s: %s: not a number",
723fde317d2Sroy 				    tic->name, token);
724fde317d2Sroy 				continue;
725fde317d2Sroy 			}
726aadfdb11Sroy 			if (!VALID_NUMERIC(cnum) || cnum > INT32_MAX) {
727aadfdb11Sroy 				dowarn(flags, "%s: %s: number %ld out of range",
728aadfdb11Sroy 				    tic->name, token, cnum);
729fde317d2Sroy 				continue;
730fde317d2Sroy 			}
7315159a425Sroy 			if (cnum > INT16_MAX) {
7325159a425Sroy 				if (flags & TIC_COMPAT_V1)
7335159a425Sroy 					cnum = INT16_MAX;
7345159a425Sroy 				else if (tic->rtype == TERMINFO_RTYPE_O1)
7355159a425Sroy 					if (_ti_promote(tic) == -1)
7365159a425Sroy 						goto error;
7375159a425Sroy 			}
73862c320f6Sroy 
739aadfdb11Sroy 			num = (int)cnum;
7401d30fdaeSchristos 			if (ind == -1) {
7411d30fdaeSchristos 				if (!_ti_store_extra(tic, 1, token, 'n', -1,
7421d30fdaeSchristos 				    num, NULL, 0, flags))
743fde317d2Sroy 					goto error;
7441d30fdaeSchristos 			} else {
7451d30fdaeSchristos 				if (!_ti_encode_buf_id_num(&tic->nums,
7461d30fdaeSchristos 				    ind, num, _ti_numsize(tic)))
7471d30fdaeSchristos 					    goto error;
748fde317d2Sroy 			}
749fde317d2Sroy 			continue;
750fde317d2Sroy 		}
751fde317d2Sroy 
752fde317d2Sroy 		flag = 1;
753fde317d2Sroy 		len = strlen(token) - 1;
754fde317d2Sroy 		if (token[len] == '@') {
755fde317d2Sroy 			flag = CANCELLED_BOOLEAN;
756fde317d2Sroy 			token[len] = '\0';
757fde317d2Sroy 		}
75834c6060fSroy 		ind = (short)_ti_flagindex(token);
759fde317d2Sroy 		if (ind == -1 && flag == CANCELLED_BOOLEAN) {
76034c6060fSroy 			if ((ind = (short)_ti_numindex(token)) != -1) {
7613958d16aSchristos 				if (_ti_find_cap(tic, &tic->nums, 'n', ind)
7623958d16aSchristos 				    != NULL)
763fde317d2Sroy 					continue;
7641d30fdaeSchristos 				if (!_ti_encode_buf_id_num(&tic->nums, ind,
7651d30fdaeSchristos 				    CANCELLED_NUMERIC, _ti_numsize(tic)))
766fde317d2Sroy 					goto error;
767fde317d2Sroy 				continue;
76834c6060fSroy 			} else if ((ind = (short)_ti_strindex(token)) != -1) {
7693958d16aSchristos 				if (_ti_find_cap(tic, &tic->strs, 's', ind)
7703958d16aSchristos 				    != NULL)
771fde317d2Sroy 					continue;
7721d30fdaeSchristos 				if (!_ti_encode_buf_id_num(
7731d30fdaeSchristos 				    &tic->strs, ind, 0, sizeof(uint16_t)))
774fde317d2Sroy 					goto error;
775fde317d2Sroy 				continue;
776fde317d2Sroy 			}
777fde317d2Sroy 		}
7781d30fdaeSchristos 		if (ind == -1) {
7791d30fdaeSchristos 			if (!_ti_store_extra(tic, 1, token, 'f', flag, 0, NULL,
7801d30fdaeSchristos 			    0, flags))
781fde317d2Sroy 				goto error;
7821d30fdaeSchristos 		} else if (_ti_find_cap(tic, &tic->flags, 'f', ind) == NULL) {
783e2a9896bSchristos 			if (!_ti_encode_buf_id_flags(&tic->flags, ind, flag))
7841d30fdaeSchristos 				goto error;
785fde317d2Sroy 		}
786fde317d2Sroy 	}
787fde317d2Sroy 
788fde317d2Sroy 	free(buf.buf);
789fde317d2Sroy 	return tic;
790fde317d2Sroy 
791fde317d2Sroy error:
792fde317d2Sroy 	free(buf.buf);
793fde317d2Sroy 	_ti_freetic(tic);
794fde317d2Sroy 	return NULL;
795fde317d2Sroy }
796fde317d2Sroy 
797fde317d2Sroy void
_ti_freetic(TIC * tic)798fde317d2Sroy _ti_freetic(TIC *tic)
799fde317d2Sroy {
800fde317d2Sroy 
801fde317d2Sroy 	if (tic != NULL) {
802fde317d2Sroy 		free(tic->name);
803fde317d2Sroy 		free(tic->alias);
804fde317d2Sroy 		free(tic->desc);
80568a65e1aSjoerg 		free(tic->extras.buf);
806fde317d2Sroy 		free(tic->flags.buf);
807fde317d2Sroy 		free(tic->nums.buf);
808fde317d2Sroy 		free(tic->strs.buf);
809fde317d2Sroy 		free(tic);
810fde317d2Sroy 	}
811fde317d2Sroy }
812