xref: /netbsd-src/lib/libterminfo/termcap.c (revision 96dad784b6981dc66764d4228964ee225c914a5c)
1*96dad784Sandvar /* $NetBSD: termcap.c,v 1.25 2023/01/31 21:11:24 andvar Exp $ */
24ca00e00Sroy 
34ca00e00Sroy /*
44ca00e00Sroy  * Copyright (c) 2009 The NetBSD Foundation, Inc.
54ca00e00Sroy  *
64ca00e00Sroy  * This code is derived from software contributed to The NetBSD Foundation
74ca00e00Sroy  * by Roy Marples.
84ca00e00Sroy  *
94ca00e00Sroy  * Redistribution and use in source and binary forms, with or without
104ca00e00Sroy  * modification, are permitted provided that the following conditions
114ca00e00Sroy  * are met:
124ca00e00Sroy  * 1. Redistributions of source code must retain the above copyright
134ca00e00Sroy  *    notice, this list of conditions and the following disclaimer.
144ca00e00Sroy  * 2. Redistributions in binary form must reproduce the above copyright
154ca00e00Sroy  *    notice, this list of conditions and the following disclaimer in the
164ca00e00Sroy  *    documentation and/or other materials provided with the distribution.
174ca00e00Sroy  *
184ca00e00Sroy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
194ca00e00Sroy  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
204ca00e00Sroy  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
214ca00e00Sroy  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
224ca00e00Sroy  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
234ca00e00Sroy  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
244ca00e00Sroy  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
254ca00e00Sroy  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
264ca00e00Sroy  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
274ca00e00Sroy  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
284ca00e00Sroy  */
294ca00e00Sroy 
304ca00e00Sroy #include <sys/cdefs.h>
31*96dad784Sandvar __RCSID("$NetBSD: termcap.c,v 1.25 2023/01/31 21:11:24 andvar Exp $");
324ca00e00Sroy 
334ca00e00Sroy #include <assert.h>
34007ba6f7Sroy #include <ctype.h>
35007ba6f7Sroy #include <errno.h>
3604f58b48Sroy #include <stdbool.h>
37eedd9adeSroy #include <stdint.h>
384ca00e00Sroy #include <string.h>
394ca00e00Sroy #include <term_private.h>
404ca00e00Sroy #include <term.h>
414ca00e00Sroy #include <termcap.h>
424ca00e00Sroy #include <unistd.h>
434ca00e00Sroy #include <stdio.h>
444ca00e00Sroy 
454ca00e00Sroy #include "termcap_map.c"
464ca00e00Sroy #include "termcap_hash.c"
474ca00e00Sroy 
484ca00e00Sroy char *UP;
494ca00e00Sroy char *BC;
504ca00e00Sroy 
514ca00e00Sroy /* ARGSUSED */
524ca00e00Sroy int
tgetent(__unused char * bp,const char * name)534ca00e00Sroy tgetent(__unused char *bp, const char *name)
544ca00e00Sroy {
554ca00e00Sroy 	int errret;
564ca00e00Sroy 	static TERMINAL *last = NULL;
574ca00e00Sroy 
584ca00e00Sroy 	_DIAGASSERT(name != NULL);
594ca00e00Sroy 
604ca00e00Sroy 	/* Free the old term */
618b22ec00Schristos 	if (cur_term != NULL) {
628b22ec00Schristos 		if (last != NULL && cur_term != last)
634ca00e00Sroy 			del_curterm(last);
648b22ec00Schristos 		last = cur_term;
654ca00e00Sroy 	}
664ca00e00Sroy 	errret = -1;
674ca00e00Sroy 	if (setupterm(name, STDOUT_FILENO, &errret) != 0)
684ca00e00Sroy 		return errret;
698b22ec00Schristos 
708b22ec00Schristos 	if (last == NULL)
714ca00e00Sroy 		last = cur_term;
724ca00e00Sroy 
734ca00e00Sroy 	if (pad_char != NULL)
744ca00e00Sroy 		PC = pad_char[0];
754ca00e00Sroy 	UP = __UNCONST(cursor_up);
764ca00e00Sroy 	BC = __UNCONST(cursor_left);
774ca00e00Sroy 	return 1;
784ca00e00Sroy }
794ca00e00Sroy 
804ca00e00Sroy int
tgetflag(const char * id2)81cc9ecc5eSchristos tgetflag(const char *id2)
824ca00e00Sroy {
834ca00e00Sroy 	uint32_t ind;
844ca00e00Sroy 	size_t i;
854ca00e00Sroy 	TERMUSERDEF *ud;
86b9c2e080Schristos 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
874ca00e00Sroy 
884ca00e00Sroy 	if (cur_term == NULL)
894ca00e00Sroy 		return 0;
904ca00e00Sroy 
914ca00e00Sroy 	ind = _t_flaghash((const unsigned char *)id, strlen(id));
9253035e70Sroy 	if (ind < __arraycount(_ti_cap_flagids)) {
934ca00e00Sroy 		if (strcmp(id, _ti_cap_flagids[ind].id) == 0)
944ca00e00Sroy 			return cur_term->flags[_ti_cap_flagids[ind].ti];
954ca00e00Sroy 	}
964ca00e00Sroy 	for (i = 0; i < cur_term->_nuserdefs; i++) {
974ca00e00Sroy 		ud = &cur_term->_userdefs[i];
984ca00e00Sroy 		if (ud->type == 'f' && strcmp(ud->id, id) == 0)
994ca00e00Sroy 			return ud->flag;
1004ca00e00Sroy 	}
1014ca00e00Sroy 	return 0;
1024ca00e00Sroy }
1034ca00e00Sroy 
1044ca00e00Sroy int
tgetnum(const char * id2)105cc9ecc5eSchristos tgetnum(const char *id2)
1064ca00e00Sroy {
1074ca00e00Sroy 	uint32_t ind;
1084ca00e00Sroy 	size_t i;
1094ca00e00Sroy 	TERMUSERDEF *ud;
1104ca00e00Sroy 	const TENTRY *te;
111b9c2e080Schristos 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
1124ca00e00Sroy 
1134ca00e00Sroy 	if (cur_term == NULL)
1144ca00e00Sroy 		return -1;
1154ca00e00Sroy 
1164ca00e00Sroy 	ind = _t_numhash((const unsigned char *)id, strlen(id));
11753035e70Sroy 	if (ind < __arraycount(_ti_cap_numids)) {
1184ca00e00Sroy 		te = &_ti_cap_numids[ind];
1194ca00e00Sroy 		if (strcmp(id, te->id) == 0) {
1204ca00e00Sroy 			if (!VALID_NUMERIC(cur_term->nums[te->ti]))
1214ca00e00Sroy 				return ABSENT_NUMERIC;
1224ca00e00Sroy 			return cur_term->nums[te->ti];
1234ca00e00Sroy 		}
1244ca00e00Sroy 	}
1254ca00e00Sroy 	for (i = 0; i < cur_term->_nuserdefs; i++) {
1264ca00e00Sroy 		ud = &cur_term->_userdefs[i];
1274ca00e00Sroy 		if (ud->type == 'n' && strcmp(ud->id, id) == 0) {
1284ca00e00Sroy 			if (!VALID_NUMERIC(ud->num))
1294ca00e00Sroy 				return ABSENT_NUMERIC;
1304ca00e00Sroy 			return ud->num;
1314ca00e00Sroy 		}
1324ca00e00Sroy 	}
1334ca00e00Sroy 	return -1;
1344ca00e00Sroy }
1354ca00e00Sroy 
1364ca00e00Sroy char *
tgetstr(const char * id2,char ** area)137cc9ecc5eSchristos tgetstr(const char *id2, char **area)
1384ca00e00Sroy {
1394ca00e00Sroy 	uint32_t ind;
1404ca00e00Sroy 	size_t i;
1414ca00e00Sroy 	TERMUSERDEF *ud;
1424ca00e00Sroy 	const char *str;
143b9c2e080Schristos 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
1444ca00e00Sroy 
1454ca00e00Sroy 	if (cur_term == NULL)
1464ca00e00Sroy 		return NULL;
1474ca00e00Sroy 
1484ca00e00Sroy 	str = NULL;
1494ca00e00Sroy 	ind = _t_strhash((const unsigned char *)id, strlen(id));
15053035e70Sroy 	if (ind < __arraycount(_ti_cap_strids)) {
1514ca00e00Sroy 		if (strcmp(id, _ti_cap_strids[ind].id) == 0) {
1524ca00e00Sroy 			str = cur_term->strs[_ti_cap_strids[ind].ti];
1534ca00e00Sroy 			if (str == NULL)
1544ca00e00Sroy 				return NULL;
1554ca00e00Sroy 		}
1564ca00e00Sroy 	}
1574ca00e00Sroy 	if (str != NULL)
1584ca00e00Sroy 		for (i = 0; i < cur_term->_nuserdefs; i++) {
1594ca00e00Sroy 			ud = &cur_term->_userdefs[i];
1604ca00e00Sroy 			if (ud->type == 's' && strcmp(ud->id, id) == 0)
1614ca00e00Sroy 				str = ud->str;
1624ca00e00Sroy 		}
1634ca00e00Sroy 
164*96dad784Sandvar 	/* XXX: FIXME
1654ca00e00Sroy 	 * We should fix sgr0(me) as it has a slightly different meaning
1664ca00e00Sroy 	 * for termcap. */
1674ca00e00Sroy 
1684ca00e00Sroy 	if (str != NULL && area != NULL && *area != NULL) {
1694ca00e00Sroy 		char *s;
1704ca00e00Sroy 		s = *area;
1714ca00e00Sroy 		strcpy(*area, str);
1724ca00e00Sroy 		*area += strlen(*area) + 1;
1734ca00e00Sroy 		return s;
1744ca00e00Sroy 	}
1754ca00e00Sroy 
1764ca00e00Sroy 	return __UNCONST(str);
1774ca00e00Sroy }
1784ca00e00Sroy 
1794ca00e00Sroy char *
tgoto(const char * cm,int destcol,int destline)1804ca00e00Sroy tgoto(const char *cm, int destcol, int destline)
1814ca00e00Sroy {
1824ca00e00Sroy 	_DIAGASSERT(cm != NULL);
18339aae097Sroy 	return tiparm(cm, destline, destcol);
1844ca00e00Sroy }
185007ba6f7Sroy 
186b6924e8aSmartin #ifdef TERMINFO_COMPILE
187007ba6f7Sroy static const char *
flagname(const char * key)188007ba6f7Sroy flagname(const char *key)
189007ba6f7Sroy {
190007ba6f7Sroy 	uint32_t idx;
191007ba6f7Sroy 
192007ba6f7Sroy 	idx = _t_flaghash((const unsigned char *)key, strlen(key));
19353035e70Sroy 	if (idx < __arraycount(_ti_cap_flagids) &&
194007ba6f7Sroy 	    strcmp(key, _ti_cap_flagids[idx].id) == 0)
195007ba6f7Sroy 		return _ti_flagid(_ti_cap_flagids[idx].ti);
196007ba6f7Sroy 	return key;
197007ba6f7Sroy }
198007ba6f7Sroy 
199007ba6f7Sroy static const char *
numname(const char * key)200007ba6f7Sroy numname(const char *key)
201007ba6f7Sroy {
202007ba6f7Sroy 	uint32_t idx;
203007ba6f7Sroy 
204007ba6f7Sroy 	idx = _t_numhash((const unsigned char *)key, strlen(key));
20553035e70Sroy 	if (idx < __arraycount(_ti_cap_numids) &&
206007ba6f7Sroy 	    strcmp(key, _ti_cap_numids[idx].id) == 0)
207007ba6f7Sroy 		return _ti_numid(_ti_cap_numids[idx].ti);
208007ba6f7Sroy 	return key;
209007ba6f7Sroy }
210007ba6f7Sroy 
211007ba6f7Sroy static const char *
strname(const char * key)212007ba6f7Sroy strname(const char *key)
213007ba6f7Sroy {
214007ba6f7Sroy 	uint32_t idx;
215007ba6f7Sroy 
216007ba6f7Sroy 	idx = _t_strhash((const unsigned char *)key, strlen(key));
21753035e70Sroy 	if (idx < __arraycount(_ti_cap_strids) &&
218007ba6f7Sroy 	    strcmp(key, _ti_cap_strids[idx].id) == 0)
219007ba6f7Sroy 		return _ti_strid(_ti_cap_strids[idx].ti);
220007ba6f7Sroy 
221007ba6f7Sroy 	if (strcmp(key, "tc") == 0)
222007ba6f7Sroy 		return "use";
223007ba6f7Sroy 
224007ba6f7Sroy 	return key;
225007ba6f7Sroy }
226007ba6f7Sroy 
227f42fd8d0Sroy /* Print a parameter if needed */
22804f58b48Sroy static size_t
printparam(char ** dst,char p,bool * nop)22904f58b48Sroy printparam(char **dst, char p, bool *nop)
230f42fd8d0Sroy {
23104f58b48Sroy 	if (*nop) {
23204f58b48Sroy 		*nop = false;
233f42fd8d0Sroy 		return 0;
234f42fd8d0Sroy 	}
235f42fd8d0Sroy 
236f42fd8d0Sroy 	*(*dst)++ = '%';
237f42fd8d0Sroy 	*(*dst)++ = 'p';
238f42fd8d0Sroy 	*(*dst)++ = '0' + p;
239f42fd8d0Sroy 	return 3;
240f42fd8d0Sroy }
241f42fd8d0Sroy 
24240109496Sroy /* Convert a termcap character into terminfo equivalents */
24304f58b48Sroy static size_t
printchar(char ** dst,const char ** src)24440109496Sroy printchar(char **dst, const char **src)
24540109496Sroy {
24604f58b48Sroy 	char v;
24704f58b48Sroy 	size_t l;
24840109496Sroy 
24940109496Sroy 	l = 4;
25004f58b48Sroy 	v = *++(*src);
25140109496Sroy 	if (v == '\\') {
25204f58b48Sroy 		v = *++(*src);
25340109496Sroy 		switch (v) {
25440109496Sroy 		case '0':
25540109496Sroy 		case '1':
25640109496Sroy 		case '2':
25740109496Sroy 		case '3':
25840109496Sroy 			v = 0;
25940109496Sroy 			while (isdigit((unsigned char) **src))
26004f58b48Sroy 				v = 8 * v + (*(*src)++ - '0');
26140109496Sroy 			(*src)--;
26240109496Sroy 			break;
26340109496Sroy 		case '\0':
26440109496Sroy 			v = '\\';
26540109496Sroy 			break;
26640109496Sroy 		}
26740109496Sroy 	} else if (v == '^')
26804f58b48Sroy 		v = *++(*src) & 0x1f;
26940109496Sroy 	*(*dst)++ = '%';
27004f58b48Sroy 	if (isgraph((unsigned char )v) &&
27104f58b48Sroy 	    v != ',' && v != '\'' && v != '\\' && v != ':')
27204f58b48Sroy 	{
27340109496Sroy 		*(*dst)++ = '\'';
27440109496Sroy 		*(*dst)++ = v;
27540109496Sroy 		*(*dst)++ = '\'';
27640109496Sroy 	} else {
27740109496Sroy 		*(*dst)++ = '{';
27840109496Sroy 		if (v > 99) {
27940109496Sroy 			*(*dst)++ = '0'+ v / 100;
28040109496Sroy 			l++;
28140109496Sroy 		}
28240109496Sroy 		if (v > 9) {
28340109496Sroy 			*(*dst)++ = '0' + ((int) (v / 10)) % 10;
28440109496Sroy 			l++;
28540109496Sroy 		}
28640109496Sroy 		*(*dst)++ = '0' + v % 10;
28740109496Sroy 		*(*dst)++ = '}';
28840109496Sroy 	}
28940109496Sroy 	return l;
29040109496Sroy }
29140109496Sroy 
29240109496Sroy /* Convert termcap commands into terminfo commands */
293f42fd8d0Sroy static const char fmtB[] = "%p0%{10}%/%{16}%*%p0%{10}%m%+";
294f42fd8d0Sroy static const char fmtD[] = "%p0%p0%{2}%*%-";
295f42fd8d0Sroy static const char fmtIf[] = "%p0%p0%?";
296f42fd8d0Sroy static const char fmtThen[] = "%>%t";
297f42fd8d0Sroy static const char fmtElse[] = "%+%;";
298f42fd8d0Sroy 
299007ba6f7Sroy static char *
strval(const char * val)300007ba6f7Sroy strval(const char *val)
301007ba6f7Sroy {
30204f58b48Sroy 	char *info, *ip, c, p;
3036855db0fSroy 	const char *ps, *pe;
30404f58b48Sroy 	bool nop;
305e6dabc3cSchristos 	size_t len, l;
306007ba6f7Sroy 
307007ba6f7Sroy 	len = 1024; /* no single string should be bigger */
308007ba6f7Sroy 	info = ip = malloc(len);
309007ba6f7Sroy 	if (info == NULL)
310007ba6f7Sroy 		return 0;
311007ba6f7Sroy 
3126855db0fSroy 	/* Move the = */
3136855db0fSroy 	*ip++ = *val++;
3146855db0fSroy 
3156855db0fSroy 	/* Set ps and pe to point to the start and end of the padding */
3166855db0fSroy 	if (isdigit((unsigned char)*val)) {
3176855db0fSroy 		for (ps = pe = val;
3186855db0fSroy 		     isdigit((unsigned char)*val) || *val == '.';
3196855db0fSroy 		     val++)
3206855db0fSroy 			pe++;
3216855db0fSroy 		if (*val == '*') {
3226855db0fSroy 			val++;
3236855db0fSroy 			pe++;
3246855db0fSroy 		}
3256855db0fSroy 	} else
3266855db0fSroy 		ps = pe  = NULL;
3276855db0fSroy 
32804f58b48Sroy 	nop = false;
32904f58b48Sroy 	l = 0;
330007ba6f7Sroy 	p = 1;
331007ba6f7Sroy 	for (; *val != '\0'; val++) {
332007ba6f7Sroy 		if (l + 2 > len)
333007ba6f7Sroy 			goto elen;
334007ba6f7Sroy 		if (*val != '%') {
335c6aefd4dSroy 			if (*val == ',') {
336c6aefd4dSroy 				if (l + 3 > len)
337c6aefd4dSroy 					goto elen;
338c6aefd4dSroy 				*ip++ = '\\';
339c6aefd4dSroy 				l++;
340c6aefd4dSroy 			}
341007ba6f7Sroy 			*ip++ = *val;
342007ba6f7Sroy 			l++;
343007ba6f7Sroy 			continue;
344007ba6f7Sroy 		}
34540109496Sroy 		switch (c = *++(val)) {
34640109496Sroy 		case 'B':
347f42fd8d0Sroy 			if (l + sizeof(fmtB) > len)
34840109496Sroy 				goto elen;
349f42fd8d0Sroy 			memcpy(ip, fmtB, sizeof(fmtB) - 1);
350f42fd8d0Sroy 			/* Replace the embedded parameters with real ones */
351f42fd8d0Sroy 			ip[2] += p;
352f42fd8d0Sroy 			ip[19] += p;
353f42fd8d0Sroy 			ip += sizeof(fmtB) - 1;
354f42fd8d0Sroy 			l += sizeof(fmtB) - 1;
35504f58b48Sroy 			nop = true;
35640109496Sroy 			continue;
35740109496Sroy 		case 'D':
358f42fd8d0Sroy 			if (l + sizeof(fmtD) > len)
359007ba6f7Sroy 				goto elen;
360f42fd8d0Sroy 			memcpy(ip, fmtD, sizeof(fmtD) - 1);
361f42fd8d0Sroy 			/* Replace the embedded parameters with real ones */
362f42fd8d0Sroy 			ip[2] += p;
363f42fd8d0Sroy 			ip[5] += p;
364f42fd8d0Sroy 			ip += sizeof(fmtD) - 1;
365f42fd8d0Sroy 			l += sizeof(fmtD) - 1;
36604f58b48Sroy 			nop = true;
36740109496Sroy 			continue;
368007ba6f7Sroy 		case 'r':
36940109496Sroy 			/* non op as switched below */
37040109496Sroy 			break;
37140109496Sroy 		case '2': /* FALLTHROUGH */
37240109496Sroy 		case '3': /* FALLTHROUGH */
37340109496Sroy 		case 'd':
37440109496Sroy 			if (l + 7 > len)
37540109496Sroy 				goto elen;
376f42fd8d0Sroy 			l += printparam(&ip, p, &nop);
37740109496Sroy 			*ip++ = '%';
37840109496Sroy 			if (c != 'd') {
37940109496Sroy 				*ip++ = c;
38040109496Sroy 				l++;
38140109496Sroy 			}
38240109496Sroy 			*ip++ = 'd';
38340109496Sroy 			l += 2;
38440109496Sroy 			break;
38540109496Sroy 		case '+':
38640109496Sroy 			if (l + 13 > len)
38740109496Sroy 				goto elen;
388f42fd8d0Sroy 			l += printparam(&ip, p, &nop);
38940109496Sroy 			l += printchar(&ip, &val);
39040109496Sroy 			*ip++ = '%';
39140109496Sroy 			*ip++ = c;
39240109496Sroy 			*ip++ = '%';
39340109496Sroy 			*ip++ = 'c';
39440109496Sroy 			l += 7;
39540109496Sroy 			break;
39640109496Sroy 		case '>':
397f42fd8d0Sroy 			if (l + sizeof(fmtIf) + sizeof(fmtThen) +
398f42fd8d0Sroy 			    sizeof(fmtElse) + (6 * 2) > len)
39940109496Sroy 				goto elen;
400f42fd8d0Sroy 
401f42fd8d0Sroy 			memcpy(ip, fmtIf, sizeof(fmtIf) - 1);
402f42fd8d0Sroy 			/* Replace the embedded parameters with real ones */
403f42fd8d0Sroy 			ip[2] += p;
404f42fd8d0Sroy 			ip[5] += p;
405f42fd8d0Sroy 			ip += sizeof(fmtIf) - 1;
406f42fd8d0Sroy 			l += sizeof(fmtIf) - 1;
40740109496Sroy 			l += printchar(&ip, &val);
408f42fd8d0Sroy 			memcpy(ip, fmtThen, sizeof(fmtThen) - 1);
409f42fd8d0Sroy 			ip += sizeof(fmtThen) - 1;
410f42fd8d0Sroy 			l += sizeof(fmtThen) - 1;
41140109496Sroy 			l += printchar(&ip, &val);
412f42fd8d0Sroy 			memcpy(ip, fmtElse, sizeof(fmtElse) - 1);
413f42fd8d0Sroy 			ip += sizeof(fmtElse) - 1;
414f42fd8d0Sroy 			l += sizeof(fmtElse) - 1;
41540109496Sroy 			l += 16;
41604f58b48Sroy 			nop = true;
41740109496Sroy 			continue;
41840109496Sroy 		case '.':
41940109496Sroy 			if (l + 6 > len)
42040109496Sroy 				goto elen;
421f42fd8d0Sroy 			l += printparam(&ip, p, &nop);
42240109496Sroy 			*ip++ = '%';
42340109496Sroy 			*ip++ = 'c';
42440109496Sroy 			l += 2;
425007ba6f7Sroy 			break;
426007ba6f7Sroy 		default:
427007ba6f7Sroy 			/* Hope it matches a terminfo command. */
428007ba6f7Sroy 			*ip++ = '%';
429007ba6f7Sroy 			*ip++ = c;
430007ba6f7Sroy 			l += 2;
43140109496Sroy 			if (c == 'i')
43240109496Sroy 				continue;
433007ba6f7Sroy 			break;
434007ba6f7Sroy 		}
43540109496Sroy 		/* Swap p1 and p2 */
43640109496Sroy 		p = 3 - p;
437007ba6f7Sroy 	}
438007ba6f7Sroy 
4394b2d6106Sroy 	/* \E\ is valid termcap.
4404b2d6106Sroy 	 * We need to escape the final \ for terminfo. */
4414b2d6106Sroy 	if (l > 2 && info[l - 1] == '\\' &&
4424b2d6106Sroy 	    (info[l - 2] != '\\' && info[l - 2] != '^'))
4434b2d6106Sroy 	{
4444b2d6106Sroy 		if (l + 1 > len)
4454b2d6106Sroy 			goto elen;
4464b2d6106Sroy 		*ip++ = '\\';
4474b2d6106Sroy 	}
4484b2d6106Sroy 
4496855db0fSroy 	/* Add our padding at the end. */
4506855db0fSroy 	if (ps != NULL) {
45104f58b48Sroy 		size_t n = (size_t)(pe - ps);
4526855db0fSroy 		if (l + n + 4 > len)
4536855db0fSroy 			goto elen;
4546855db0fSroy 		*ip++ = '$';
4556855db0fSroy 		*ip++ = '<';
4566855db0fSroy 		strncpy(ip, ps, n);
4576855db0fSroy 		ip += n;
4586855db0fSroy 		*ip++ = '/';
4596855db0fSroy 		*ip++ = '>';
4606855db0fSroy 	}
4616855db0fSroy 
462007ba6f7Sroy 	*ip = '\0';
463007ba6f7Sroy 	return info;
464007ba6f7Sroy 
465007ba6f7Sroy elen:
466007ba6f7Sroy 	free(info);
467007ba6f7Sroy 	errno = ENOMEM;
468007ba6f7Sroy 	return NULL;
469007ba6f7Sroy }
470007ba6f7Sroy 
471215c5976Sroy typedef struct {
4726855db0fSroy 	const char *name;
4736855db0fSroy 	const char *cap;
474215c5976Sroy } DEF_INFO;
475215c5976Sroy 
476215c5976Sroy static DEF_INFO def_infos[] = {
4776855db0fSroy 	{ "bel",	"^G" },
4786855db0fSroy 	{ "cr",		"^M" },
4796855db0fSroy 	{ "cud1",	"^J" },
4806855db0fSroy 	{ "ht",		"^I" },
4816855db0fSroy 	{ "ind",	"^J" },
4826855db0fSroy 	{ "kbs",	"^H" },
4836855db0fSroy 	{ "kcub1",	"^H" },
4846855db0fSroy 	{ "kcud1",	"^J" },
4856855db0fSroy 	{ "nel",	"^M^J" }
4866855db0fSroy };
4876855db0fSroy 
488007ba6f7Sroy char *
captoinfo(char * cap)489007ba6f7Sroy captoinfo(char *cap)
490007ba6f7Sroy {
491007ba6f7Sroy 	char *info, *ip, *token, *val, *p, tok[3];
492007ba6f7Sroy 	const char *name;
493007ba6f7Sroy 	size_t len, lp, nl, vl, rl;
4941f27d9b1Sroy 	int defs[__arraycount(def_infos)], fv;
495007ba6f7Sroy 
496007ba6f7Sroy 	_DIAGASSERT(cap != NULL);
497007ba6f7Sroy 
498007ba6f7Sroy 	len = strlen(cap) * 2;
4996855db0fSroy 	len += __arraycount(def_infos) * (5 + 4 + 3); /* reserve for defs */
500007ba6f7Sroy 	info = ip = malloc(len);
501007ba6f7Sroy 	if (info == NULL)
502007ba6f7Sroy 		return NULL;
503007ba6f7Sroy 
5046855db0fSroy 	memset(defs, 0, sizeof(defs));
505007ba6f7Sroy 	lp = 0;
506007ba6f7Sroy 	tok[2] = '\0';
5074b2d6106Sroy 	for (token = _ti_get_token(&cap, ':');
5084b2d6106Sroy 	     token != NULL;
5094b2d6106Sroy 	     token = _ti_get_token(&cap, ':'))
5104b2d6106Sroy 	{
511007ba6f7Sroy 		if (token[0] == '\0')
512007ba6f7Sroy 			continue;
513007ba6f7Sroy 		name = token;
5141f27d9b1Sroy 		val = p = NULL;
5151d30fdaeSchristos 		fv = 0;
5161d30fdaeSchristos 		nl = 0;
517007ba6f7Sroy 		if (token[1] != '\0') {
518007ba6f7Sroy 			tok[0] = token[0];
519007ba6f7Sroy 			tok[1] = token[1];
5201f27d9b1Sroy 			nl = 1;
521007ba6f7Sroy 			if (token[2] == '\0') {
522007ba6f7Sroy 				name = flagname(tok);
523007ba6f7Sroy 				val = NULL;
524007ba6f7Sroy 			} else if (token[2] == '#') {
525007ba6f7Sroy 				name = numname(tok);
526007ba6f7Sroy 				val = token + 2;
527007ba6f7Sroy 			} else if (token[2] == '=') {
528007ba6f7Sroy 				name = strname(tok);
529007ba6f7Sroy 				val = strval(token + 2);
5301f27d9b1Sroy 				fv = 1;
5311f27d9b1Sroy 			} else
5321f27d9b1Sroy 				nl = 0;
5331f27d9b1Sroy 		}
5341f27d9b1Sroy 		/* If not matched we may need to convert padding still. */
5351f27d9b1Sroy 		if (nl == 0) {
5361f27d9b1Sroy 			p = strchr(name, '=');
5371f27d9b1Sroy 			if (p != NULL) {
5381f27d9b1Sroy 				val = strval(p);
5391f27d9b1Sroy 				*p = '\0';
5401f27d9b1Sroy 				fv = 1;
541007ba6f7Sroy 			}
542007ba6f7Sroy 		}
5436855db0fSroy 
5446855db0fSroy 		/* See if this sets a default. */
5456855db0fSroy 		for (nl = 0; nl < __arraycount(def_infos); nl++) {
5466855db0fSroy 			if (strcmp(name, def_infos[nl].name) == 0) {
5476855db0fSroy 				defs[nl] = 1;
5486855db0fSroy 				break;
5496855db0fSroy 			}
5506855db0fSroy 		}
5516855db0fSroy 
552007ba6f7Sroy 		nl = strlen(name);
553007ba6f7Sroy 		if (val == NULL)
554007ba6f7Sroy 			vl = 0;
555007ba6f7Sroy 		else
556007ba6f7Sroy 			vl = strlen(val);
557007ba6f7Sroy 		rl = nl + vl + 3; /* , \0 */
558007ba6f7Sroy 
559007ba6f7Sroy 		if (lp + rl > len) {
560007ba6f7Sroy 			if (rl < 256)
561007ba6f7Sroy 				len += 256;
562007ba6f7Sroy 			else
563007ba6f7Sroy 				len += rl;
564007ba6f7Sroy 			p = realloc(info, len);
565db71acfdSchristos 			if (p == NULL) {
566db71acfdSchristos 				if (fv == 1)
567db71acfdSchristos 					free(val);
568007ba6f7Sroy 				return NULL;
569db71acfdSchristos 			}
570007ba6f7Sroy 			info = p;
571007ba6f7Sroy 		}
572007ba6f7Sroy 
573007ba6f7Sroy 		if (ip != info) {
574007ba6f7Sroy 			*ip++ = ',';
575007ba6f7Sroy 			*ip++ = ' ';
576007ba6f7Sroy 		}
577007ba6f7Sroy 
578007ba6f7Sroy 		strcpy(ip, name);
579007ba6f7Sroy 		ip += nl;
580007ba6f7Sroy 		if (val != NULL) {
581007ba6f7Sroy 			strcpy(ip, val);
582007ba6f7Sroy 			ip += vl;
5831f27d9b1Sroy 			if (fv == 1)
584007ba6f7Sroy 				free(val);
585007ba6f7Sroy 		}
586007ba6f7Sroy 	}
587007ba6f7Sroy 
5886855db0fSroy 	/* Add any defaults not set above. */
5896855db0fSroy 	for (nl = 0; nl < __arraycount(def_infos); nl++) {
5906855db0fSroy 		if (defs[nl] == 0) {
5916855db0fSroy 			*ip++ = ',';
5926855db0fSroy 			*ip++ = ' ';
5936855db0fSroy 			strcpy(ip, def_infos[nl].name);
5946855db0fSroy 			ip += strlen(def_infos[nl].name);
5956855db0fSroy 			*ip++ = '=';
5966855db0fSroy 			strcpy(ip, def_infos[nl].cap);
5976855db0fSroy 			ip += strlen(def_infos[nl].cap);
5986855db0fSroy 		}
5996855db0fSroy 	}
6006855db0fSroy 
601007ba6f7Sroy 	*ip = '\0';
602007ba6f7Sroy 	return info;
603007ba6f7Sroy }
604b6924e8aSmartin #endif
605