xref: /minix3/lib/libterminfo/termcap.c (revision 0c3ae37f525eceade8dc047e551f5c9cb33faeb1)
1*0c3ae37fSLionel Sambuc /* $NetBSD: termcap.c,v 1.17 2011/11/13 15:24:04 christos Exp $ */
251e66a47SVivek Prakash 
351e66a47SVivek Prakash /*
451e66a47SVivek Prakash  * Copyright (c) 2009 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 #include <sys/cdefs.h>
31*0c3ae37fSLionel Sambuc __RCSID("$NetBSD: termcap.c,v 1.17 2011/11/13 15:24:04 christos Exp $");
3251e66a47SVivek Prakash 
3351e66a47SVivek Prakash #include <assert.h>
3451e66a47SVivek Prakash #include <ctype.h>
3551e66a47SVivek Prakash #include <errno.h>
3651e66a47SVivek Prakash #include <stdint.h>
3751e66a47SVivek Prakash #include <string.h>
3851e66a47SVivek Prakash #include <term_private.h>
3951e66a47SVivek Prakash #include <term.h>
4051e66a47SVivek Prakash #include <termcap.h>
4151e66a47SVivek Prakash #include <unistd.h>
4251e66a47SVivek Prakash #include <stdio.h>
4351e66a47SVivek Prakash 
4451e66a47SVivek Prakash #include "termcap_map.c"
4551e66a47SVivek Prakash #include "termcap_hash.c"
4651e66a47SVivek Prakash 
4751e66a47SVivek Prakash char *UP;
4851e66a47SVivek Prakash char *BC;
4951e66a47SVivek Prakash 
5051e66a47SVivek Prakash /* ARGSUSED */
5151e66a47SVivek Prakash int
tgetent(__unused char * bp,const char * name)5251e66a47SVivek Prakash tgetent(__unused char *bp, const char *name)
5351e66a47SVivek Prakash {
5451e66a47SVivek Prakash 	int errret;
5551e66a47SVivek Prakash 	static TERMINAL *last = NULL;
5651e66a47SVivek Prakash 
5751e66a47SVivek Prakash 	_DIAGASSERT(name != NULL);
5851e66a47SVivek Prakash 
5951e66a47SVivek Prakash 	/* Free the old term */
6051e66a47SVivek Prakash 	if (last != NULL) {
6151e66a47SVivek Prakash 		del_curterm(last);
6251e66a47SVivek Prakash 		last = NULL;
6351e66a47SVivek Prakash 	}
6451e66a47SVivek Prakash 	errret = -1;
6551e66a47SVivek Prakash 	if (setupterm(name, STDOUT_FILENO, &errret) != 0)
6651e66a47SVivek Prakash 		return errret;
6751e66a47SVivek Prakash 	last = cur_term;
6851e66a47SVivek Prakash 
6951e66a47SVivek Prakash 	if (pad_char != NULL)
7051e66a47SVivek Prakash 		PC = pad_char[0];
7151e66a47SVivek Prakash 	UP = __UNCONST(cursor_up);
7251e66a47SVivek Prakash 	BC = __UNCONST(cursor_left);
7351e66a47SVivek Prakash 	return 1;
7451e66a47SVivek Prakash }
7551e66a47SVivek Prakash 
7651e66a47SVivek Prakash int
tgetflag(const char * id2)77*0c3ae37fSLionel Sambuc tgetflag(const char *id2)
7851e66a47SVivek Prakash {
7951e66a47SVivek Prakash 	uint32_t ind;
8051e66a47SVivek Prakash 	size_t i;
8151e66a47SVivek Prakash 	TERMUSERDEF *ud;
82*0c3ae37fSLionel Sambuc 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
8351e66a47SVivek Prakash 
8451e66a47SVivek Prakash 	if (cur_term == NULL)
8551e66a47SVivek Prakash 		return 0;
8651e66a47SVivek Prakash 
8751e66a47SVivek Prakash 	ind = _t_flaghash((const unsigned char *)id, strlen(id));
8851e66a47SVivek Prakash 	if (ind <= __arraycount(_ti_cap_flagids)) {
8951e66a47SVivek Prakash 		if (strcmp(id, _ti_cap_flagids[ind].id) == 0)
9051e66a47SVivek Prakash 			return cur_term->flags[_ti_cap_flagids[ind].ti];
9151e66a47SVivek Prakash 	}
9251e66a47SVivek Prakash 	for (i = 0; i < cur_term->_nuserdefs; i++) {
9351e66a47SVivek Prakash 		ud = &cur_term->_userdefs[i];
9451e66a47SVivek Prakash 		if (ud->type == 'f' && strcmp(ud->id, id) == 0)
9551e66a47SVivek Prakash 			return ud->flag;
9651e66a47SVivek Prakash 	}
9751e66a47SVivek Prakash 	return 0;
9851e66a47SVivek Prakash }
9951e66a47SVivek Prakash 
10051e66a47SVivek Prakash int
tgetnum(const char * id2)101*0c3ae37fSLionel Sambuc tgetnum(const char *id2)
10251e66a47SVivek Prakash {
10351e66a47SVivek Prakash 	uint32_t ind;
10451e66a47SVivek Prakash 	size_t i;
10551e66a47SVivek Prakash 	TERMUSERDEF *ud;
10651e66a47SVivek Prakash 	const TENTRY *te;
107*0c3ae37fSLionel Sambuc 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
10851e66a47SVivek Prakash 
10951e66a47SVivek Prakash 	if (cur_term == NULL)
11051e66a47SVivek Prakash 		return -1;
11151e66a47SVivek Prakash 
11251e66a47SVivek Prakash 	ind = _t_numhash((const unsigned char *)id, strlen(id));
11351e66a47SVivek Prakash 	if (ind <= __arraycount(_ti_cap_numids)) {
11451e66a47SVivek Prakash 		te = &_ti_cap_numids[ind];
11551e66a47SVivek Prakash 		if (strcmp(id, te->id) == 0) {
11651e66a47SVivek Prakash 			if (!VALID_NUMERIC(cur_term->nums[te->ti]))
11751e66a47SVivek Prakash 				return ABSENT_NUMERIC;
11851e66a47SVivek Prakash 			return cur_term->nums[te->ti];
11951e66a47SVivek Prakash 		}
12051e66a47SVivek Prakash 	}
12151e66a47SVivek Prakash 	for (i = 0; i < cur_term->_nuserdefs; i++) {
12251e66a47SVivek Prakash 		ud = &cur_term->_userdefs[i];
12351e66a47SVivek Prakash 		if (ud->type == 'n' && strcmp(ud->id, id) == 0) {
12451e66a47SVivek Prakash 			if (!VALID_NUMERIC(ud->num))
12551e66a47SVivek Prakash 				return ABSENT_NUMERIC;
12651e66a47SVivek Prakash 			return ud->num;
12751e66a47SVivek Prakash 		}
12851e66a47SVivek Prakash 	}
12951e66a47SVivek Prakash 	return -1;
13051e66a47SVivek Prakash }
13151e66a47SVivek Prakash 
13251e66a47SVivek Prakash char *
tgetstr(const char * id2,char ** area)133*0c3ae37fSLionel Sambuc tgetstr(const char *id2, char **area)
13451e66a47SVivek Prakash {
13551e66a47SVivek Prakash 	uint32_t ind;
13651e66a47SVivek Prakash 	size_t i;
13751e66a47SVivek Prakash 	TERMUSERDEF *ud;
13851e66a47SVivek Prakash 	const char *str;
139*0c3ae37fSLionel Sambuc 	const char id[] = { id2[0], id2[0] ? id2[1] : '\0', '\0' };
14051e66a47SVivek Prakash 
14151e66a47SVivek Prakash 	if (cur_term == NULL)
14251e66a47SVivek Prakash 		return NULL;
14351e66a47SVivek Prakash 
14451e66a47SVivek Prakash 	str = NULL;
14551e66a47SVivek Prakash 	ind = _t_strhash((const unsigned char *)id, strlen(id));
14651e66a47SVivek Prakash 	if (ind <= __arraycount(_ti_cap_strids)) {
14751e66a47SVivek Prakash 		if (strcmp(id, _ti_cap_strids[ind].id) == 0) {
14851e66a47SVivek Prakash 			str = cur_term->strs[_ti_cap_strids[ind].ti];
14951e66a47SVivek Prakash 			if (str == NULL)
15051e66a47SVivek Prakash 				return NULL;
15151e66a47SVivek Prakash 		}
15251e66a47SVivek Prakash 	}
15351e66a47SVivek Prakash 	if (str != NULL)
15451e66a47SVivek Prakash 		for (i = 0; i < cur_term->_nuserdefs; i++) {
15551e66a47SVivek Prakash 			ud = &cur_term->_userdefs[i];
15651e66a47SVivek Prakash 			if (ud->type == 's' && strcmp(ud->id, id) == 0)
15751e66a47SVivek Prakash 				str = ud->str;
15851e66a47SVivek Prakash 		}
15951e66a47SVivek Prakash 
16051e66a47SVivek Prakash 	/* XXX: FXIXME
16151e66a47SVivek Prakash 	 * We should fix sgr0(me) as it has a slightly different meaning
16251e66a47SVivek Prakash 	 * for termcap. */
16351e66a47SVivek Prakash 
16451e66a47SVivek Prakash 	if (str != NULL && area != NULL && *area != NULL) {
16551e66a47SVivek Prakash 		char *s;
16651e66a47SVivek Prakash 		s = *area;
16751e66a47SVivek Prakash 		strcpy(*area, str);
16851e66a47SVivek Prakash 		*area += strlen(*area) + 1;
16951e66a47SVivek Prakash 		return s;
17051e66a47SVivek Prakash 	}
17151e66a47SVivek Prakash 
17251e66a47SVivek Prakash 	return __UNCONST(str);
17351e66a47SVivek Prakash }
17451e66a47SVivek Prakash 
17551e66a47SVivek Prakash char *
tgoto(const char * cm,int destcol,int destline)17651e66a47SVivek Prakash tgoto(const char *cm, int destcol, int destline)
17751e66a47SVivek Prakash {
17851e66a47SVivek Prakash 	_DIAGASSERT(cm != NULL);
179*0c3ae37fSLionel Sambuc 	return tiparm(cm, destline, destcol);
18051e66a47SVivek Prakash }
18151e66a47SVivek Prakash 
18251e66a47SVivek Prakash static const char *
flagname(const char * key)18351e66a47SVivek Prakash flagname(const char *key)
18451e66a47SVivek Prakash {
18551e66a47SVivek Prakash 	uint32_t idx;
18651e66a47SVivek Prakash 
18751e66a47SVivek Prakash 	idx = _t_flaghash((const unsigned char *)key, strlen(key));
18851e66a47SVivek Prakash 	if (idx <= __arraycount(_ti_cap_flagids) &&
18951e66a47SVivek Prakash 	    strcmp(key, _ti_cap_flagids[idx].id) == 0)
19051e66a47SVivek Prakash 		return _ti_flagid(_ti_cap_flagids[idx].ti);
19151e66a47SVivek Prakash 	return key;
19251e66a47SVivek Prakash }
19351e66a47SVivek Prakash 
19451e66a47SVivek Prakash static const char *
numname(const char * key)19551e66a47SVivek Prakash numname(const char *key)
19651e66a47SVivek Prakash {
19751e66a47SVivek Prakash 	uint32_t idx;
19851e66a47SVivek Prakash 
19951e66a47SVivek Prakash 	idx = _t_numhash((const unsigned char *)key, strlen(key));
20051e66a47SVivek Prakash 	if (idx <= __arraycount(_ti_cap_numids) &&
20151e66a47SVivek Prakash 	    strcmp(key, _ti_cap_numids[idx].id) == 0)
20251e66a47SVivek Prakash 		return _ti_numid(_ti_cap_numids[idx].ti);
20351e66a47SVivek Prakash 	return key;
20451e66a47SVivek Prakash }
20551e66a47SVivek Prakash 
20651e66a47SVivek Prakash static const char *
strname(const char * key)20751e66a47SVivek Prakash strname(const char *key)
20851e66a47SVivek Prakash {
20951e66a47SVivek Prakash 	uint32_t idx;
21051e66a47SVivek Prakash 
21151e66a47SVivek Prakash 	idx = _t_strhash((const unsigned char *)key, strlen(key));
21251e66a47SVivek Prakash 	if (idx <= __arraycount(_ti_cap_strids) &&
21351e66a47SVivek Prakash 	    strcmp(key, _ti_cap_strids[idx].id) == 0)
21451e66a47SVivek Prakash 		return _ti_strid(_ti_cap_strids[idx].ti);
21551e66a47SVivek Prakash 
21651e66a47SVivek Prakash 	if (strcmp(key, "tc") == 0)
21751e66a47SVivek Prakash 		return "use";
21851e66a47SVivek Prakash 
21951e66a47SVivek Prakash 	return key;
22051e66a47SVivek Prakash }
22151e66a47SVivek Prakash 
222*0c3ae37fSLionel Sambuc /* Print a parameter if needed */
223*0c3ae37fSLionel Sambuc static int
printparam(char ** dst,char p,int * nop)224*0c3ae37fSLionel Sambuc printparam(char **dst, char p, int *nop)
225*0c3ae37fSLionel Sambuc {
226*0c3ae37fSLionel Sambuc 	if (*nop != 0) {
227*0c3ae37fSLionel Sambuc 		*nop = 0;
228*0c3ae37fSLionel Sambuc 		return 0;
229*0c3ae37fSLionel Sambuc 	}
230*0c3ae37fSLionel Sambuc 
231*0c3ae37fSLionel Sambuc 	*(*dst)++ = '%';
232*0c3ae37fSLionel Sambuc 	*(*dst)++ = 'p';
233*0c3ae37fSLionel Sambuc 	*(*dst)++ = '0' + p;
234*0c3ae37fSLionel Sambuc 	return 3;
235*0c3ae37fSLionel Sambuc }
236*0c3ae37fSLionel Sambuc 
237*0c3ae37fSLionel Sambuc /* Convert a termcap character into terminfo equivalents */
238*0c3ae37fSLionel Sambuc static int
printchar(char ** dst,const char ** src)239*0c3ae37fSLionel Sambuc printchar(char **dst, const char **src)
240*0c3ae37fSLionel Sambuc {
241*0c3ae37fSLionel Sambuc 	unsigned char v;
242*0c3ae37fSLionel Sambuc 	int l;
243*0c3ae37fSLionel Sambuc 
244*0c3ae37fSLionel Sambuc 	l = 4;
245*0c3ae37fSLionel Sambuc 	v = (unsigned char) *++(*src);
246*0c3ae37fSLionel Sambuc 	if (v == '\\') {
247*0c3ae37fSLionel Sambuc 		v = (unsigned char) *++(*src);
248*0c3ae37fSLionel Sambuc 		switch (v) {
249*0c3ae37fSLionel Sambuc 		case '0':
250*0c3ae37fSLionel Sambuc 		case '1':
251*0c3ae37fSLionel Sambuc 		case '2':
252*0c3ae37fSLionel Sambuc 		case '3':
253*0c3ae37fSLionel Sambuc 			v = 0;
254*0c3ae37fSLionel Sambuc 			while (isdigit((unsigned char) **src))
255*0c3ae37fSLionel Sambuc 				v = 8 * v + ((unsigned char) *(*src)++ - '0');
256*0c3ae37fSLionel Sambuc 			(*src)--;
257*0c3ae37fSLionel Sambuc 			break;
258*0c3ae37fSLionel Sambuc 		case '\0':
259*0c3ae37fSLionel Sambuc 			v = '\\';
260*0c3ae37fSLionel Sambuc 			break;
261*0c3ae37fSLionel Sambuc 		}
262*0c3ae37fSLionel Sambuc 	} else if (v == '^')
263*0c3ae37fSLionel Sambuc 		v = (unsigned char) (*++(*src) & 0x1f);
264*0c3ae37fSLionel Sambuc 	*(*dst)++ = '%';
265*0c3ae37fSLionel Sambuc 	if (isgraph(v) && v != ',' && v != '\'' && v != '\\' && v != ':') {
266*0c3ae37fSLionel Sambuc 		*(*dst)++ = '\'';
267*0c3ae37fSLionel Sambuc 		*(*dst)++ = v;
268*0c3ae37fSLionel Sambuc 		*(*dst)++ = '\'';
269*0c3ae37fSLionel Sambuc 	} else {
270*0c3ae37fSLionel Sambuc 		*(*dst)++ = '{';
271*0c3ae37fSLionel Sambuc 		if (v > 99) {
272*0c3ae37fSLionel Sambuc 			*(*dst)++ = '0'+ v / 100;
273*0c3ae37fSLionel Sambuc 			l++;
274*0c3ae37fSLionel Sambuc 		}
275*0c3ae37fSLionel Sambuc 		if (v > 9) {
276*0c3ae37fSLionel Sambuc 			*(*dst)++ = '0' + ((int) (v / 10)) % 10;
277*0c3ae37fSLionel Sambuc 			l++;
278*0c3ae37fSLionel Sambuc 		}
279*0c3ae37fSLionel Sambuc 		*(*dst)++ = '0' + v % 10;
280*0c3ae37fSLionel Sambuc 		*(*dst)++ = '}';
281*0c3ae37fSLionel Sambuc 	}
282*0c3ae37fSLionel Sambuc 	return l;
283*0c3ae37fSLionel Sambuc }
284*0c3ae37fSLionel Sambuc 
285*0c3ae37fSLionel Sambuc /* Convert termcap commands into terminfo commands */
286*0c3ae37fSLionel Sambuc static const char fmtB[] = "%p0%{10}%/%{16}%*%p0%{10}%m%+";
287*0c3ae37fSLionel Sambuc static const char fmtD[] = "%p0%p0%{2}%*%-";
288*0c3ae37fSLionel Sambuc static const char fmtIf[] = "%p0%p0%?";
289*0c3ae37fSLionel Sambuc static const char fmtThen[] = "%>%t";
290*0c3ae37fSLionel Sambuc static const char fmtElse[] = "%+%;";
291*0c3ae37fSLionel Sambuc 
29251e66a47SVivek Prakash static char *
strval(const char * val)29351e66a47SVivek Prakash strval(const char *val)
29451e66a47SVivek Prakash {
29551e66a47SVivek Prakash 	char *info, *ip, c;
29651e66a47SVivek Prakash 	const char *ps, *pe;
297*0c3ae37fSLionel Sambuc 	int p, nop;
29851e66a47SVivek Prakash 	size_t len, l;
29951e66a47SVivek Prakash 
30051e66a47SVivek Prakash 	len = 1024; /* no single string should be bigger */
30151e66a47SVivek Prakash 	info = ip = malloc(len);
30251e66a47SVivek Prakash 	if (info == NULL)
30351e66a47SVivek Prakash 		return 0;
30451e66a47SVivek Prakash 
30551e66a47SVivek Prakash 	/* Move the = */
30651e66a47SVivek Prakash 	*ip++ = *val++;
30751e66a47SVivek Prakash 
30851e66a47SVivek Prakash 	/* Set ps and pe to point to the start and end of the padding */
30951e66a47SVivek Prakash 	if (isdigit((unsigned char)*val)) {
31051e66a47SVivek Prakash 		for (ps = pe = val;
31151e66a47SVivek Prakash 		     isdigit((unsigned char)*val) || *val == '.';
31251e66a47SVivek Prakash 		     val++)
31351e66a47SVivek Prakash 			pe++;
31451e66a47SVivek Prakash 		if (*val == '*') {
31551e66a47SVivek Prakash 			val++;
31651e66a47SVivek Prakash 			pe++;
31751e66a47SVivek Prakash 		}
31851e66a47SVivek Prakash 	} else
31951e66a47SVivek Prakash 		ps = pe  = NULL;
32051e66a47SVivek Prakash 
321*0c3ae37fSLionel Sambuc 	l = nop = 0;
32251e66a47SVivek Prakash 	p = 1;
32351e66a47SVivek Prakash 	for (; *val != '\0'; val++) {
32451e66a47SVivek Prakash 		if (l + 2 > len)
32551e66a47SVivek Prakash 			goto elen;
32651e66a47SVivek Prakash 		if (*val != '%') {
32751e66a47SVivek Prakash 			if (*val == ',') {
32851e66a47SVivek Prakash 				if (l + 3 > len)
32951e66a47SVivek Prakash 					goto elen;
33051e66a47SVivek Prakash 				*ip++ = '\\';
33151e66a47SVivek Prakash 				l++;
33251e66a47SVivek Prakash 			}
33351e66a47SVivek Prakash 			*ip++ = *val;
33451e66a47SVivek Prakash 			l++;
33551e66a47SVivek Prakash 			continue;
33651e66a47SVivek Prakash 		}
337*0c3ae37fSLionel Sambuc 		switch (c = *++(val)) {
338*0c3ae37fSLionel Sambuc 		case 'B':
339*0c3ae37fSLionel Sambuc 			if (l + sizeof(fmtB) > len)
340*0c3ae37fSLionel Sambuc 				goto elen;
341*0c3ae37fSLionel Sambuc 			memcpy(ip, fmtB, sizeof(fmtB) - 1);
342*0c3ae37fSLionel Sambuc 			/* Replace the embedded parameters with real ones */
343*0c3ae37fSLionel Sambuc 			ip[2] += p;
344*0c3ae37fSLionel Sambuc 			ip[19] += p;
345*0c3ae37fSLionel Sambuc 			ip += sizeof(fmtB) - 1;
346*0c3ae37fSLionel Sambuc 			l += sizeof(fmtB) - 1;
347*0c3ae37fSLionel Sambuc 			nop = 1;
348*0c3ae37fSLionel Sambuc 			continue;
349*0c3ae37fSLionel Sambuc 		case 'D':
350*0c3ae37fSLionel Sambuc 			if (l + sizeof(fmtD) > len)
351*0c3ae37fSLionel Sambuc 				goto elen;
352*0c3ae37fSLionel Sambuc 			memcpy(ip, fmtD, sizeof(fmtD) - 1);
353*0c3ae37fSLionel Sambuc 			/* Replace the embedded parameters with real ones */
354*0c3ae37fSLionel Sambuc 			ip[2] += p;
355*0c3ae37fSLionel Sambuc 			ip[5] += p;
356*0c3ae37fSLionel Sambuc 			ip += sizeof(fmtD) - 1;
357*0c3ae37fSLionel Sambuc 			l += sizeof(fmtD) - 1;
358*0c3ae37fSLionel Sambuc 			nop = 1;
359*0c3ae37fSLionel Sambuc 			continue;
360*0c3ae37fSLionel Sambuc 		case 'r':
361*0c3ae37fSLionel Sambuc 			/* non op as switched below */
362*0c3ae37fSLionel Sambuc 			break;
363*0c3ae37fSLionel Sambuc 		case '2': /* FALLTHROUGH */
364*0c3ae37fSLionel Sambuc 		case '3': /* FALLTHROUGH */
36551e66a47SVivek Prakash 		case 'd':
366*0c3ae37fSLionel Sambuc 			if (l + 7 > len)
367*0c3ae37fSLionel Sambuc 				goto elen;
368*0c3ae37fSLionel Sambuc 			l += printparam(&ip, p, &nop);
369*0c3ae37fSLionel Sambuc 			*ip++ = '%';
370*0c3ae37fSLionel Sambuc 			if (c != 'd') {
371*0c3ae37fSLionel Sambuc 				*ip++ = c;
372*0c3ae37fSLionel Sambuc 				l++;
373*0c3ae37fSLionel Sambuc 			}
374*0c3ae37fSLionel Sambuc 			*ip++ = 'd';
375*0c3ae37fSLionel Sambuc 			l += 2;
376*0c3ae37fSLionel Sambuc 			break;
377*0c3ae37fSLionel Sambuc 		case '+':
378*0c3ae37fSLionel Sambuc 			if (l + 13 > len)
379*0c3ae37fSLionel Sambuc 				goto elen;
380*0c3ae37fSLionel Sambuc 			l += printparam(&ip, p, &nop);
381*0c3ae37fSLionel Sambuc 			l += printchar(&ip, &val);
382*0c3ae37fSLionel Sambuc 			*ip++ = '%';
383*0c3ae37fSLionel Sambuc 			*ip++ = c;
384*0c3ae37fSLionel Sambuc 			*ip++ = '%';
385*0c3ae37fSLionel Sambuc 			*ip++ = 'c';
386*0c3ae37fSLionel Sambuc 			l += 7;
387*0c3ae37fSLionel Sambuc 			break;
388*0c3ae37fSLionel Sambuc 		case '>':
389*0c3ae37fSLionel Sambuc 			if (l + sizeof(fmtIf) + sizeof(fmtThen) +
390*0c3ae37fSLionel Sambuc 			    sizeof(fmtElse) + (6 * 2) > len)
391*0c3ae37fSLionel Sambuc 				goto elen;
392*0c3ae37fSLionel Sambuc 
393*0c3ae37fSLionel Sambuc 			memcpy(ip, fmtIf, sizeof(fmtIf) - 1);
394*0c3ae37fSLionel Sambuc 			/* Replace the embedded parameters with real ones */
395*0c3ae37fSLionel Sambuc 			ip[2] += p;
396*0c3ae37fSLionel Sambuc 			ip[5] += p;
397*0c3ae37fSLionel Sambuc 			ip += sizeof(fmtIf) - 1;
398*0c3ae37fSLionel Sambuc 			l += sizeof(fmtIf) - 1;
399*0c3ae37fSLionel Sambuc 			l += printchar(&ip, &val);
400*0c3ae37fSLionel Sambuc 			memcpy(ip, fmtThen, sizeof(fmtThen) - 1);
401*0c3ae37fSLionel Sambuc 			ip += sizeof(fmtThen) - 1;
402*0c3ae37fSLionel Sambuc 			l += sizeof(fmtThen) - 1;
403*0c3ae37fSLionel Sambuc 			l += printchar(&ip, &val);
404*0c3ae37fSLionel Sambuc 			memcpy(ip, fmtElse, sizeof(fmtElse) - 1);
405*0c3ae37fSLionel Sambuc 			ip += sizeof(fmtElse) - 1;
406*0c3ae37fSLionel Sambuc 			l += sizeof(fmtElse) - 1;
407*0c3ae37fSLionel Sambuc 			l += 16;
408*0c3ae37fSLionel Sambuc 			nop = 1;
409*0c3ae37fSLionel Sambuc 			continue;
410*0c3ae37fSLionel Sambuc 		case '.':
41151e66a47SVivek Prakash 			if (l + 6 > len)
41251e66a47SVivek Prakash 				goto elen;
413*0c3ae37fSLionel Sambuc 			l += printparam(&ip, p, &nop);
41451e66a47SVivek Prakash 			*ip++ = '%';
415*0c3ae37fSLionel Sambuc 			*ip++ = 'c';
416*0c3ae37fSLionel Sambuc 			l += 2;
41751e66a47SVivek Prakash 			break;
41851e66a47SVivek Prakash 		default:
41951e66a47SVivek Prakash 			/* Hope it matches a terminfo command. */
42051e66a47SVivek Prakash 			*ip++ = '%';
42151e66a47SVivek Prakash 			*ip++ = c;
42251e66a47SVivek Prakash 			l += 2;
423*0c3ae37fSLionel Sambuc 			if (c == 'i')
424*0c3ae37fSLionel Sambuc 				continue;
42551e66a47SVivek Prakash 			break;
42651e66a47SVivek Prakash 		}
427*0c3ae37fSLionel Sambuc 		/* Swap p1 and p2 */
428*0c3ae37fSLionel Sambuc 		p = 3 - p;
42951e66a47SVivek Prakash 	}
43051e66a47SVivek Prakash 
43151e66a47SVivek Prakash 	/* \E\ is valid termcap.
43251e66a47SVivek Prakash 	 * We need to escape the final \ for terminfo. */
43351e66a47SVivek Prakash 	if (l > 2 && info[l - 1] == '\\' &&
43451e66a47SVivek Prakash 	    (info[l - 2] != '\\' && info[l - 2] != '^'))
43551e66a47SVivek Prakash 	{
43651e66a47SVivek Prakash 		if (l + 1 > len)
43751e66a47SVivek Prakash 			goto elen;
43851e66a47SVivek Prakash 		*ip++ = '\\';
43951e66a47SVivek Prakash 	}
44051e66a47SVivek Prakash 
44151e66a47SVivek Prakash 	/* Add our padding at the end. */
44251e66a47SVivek Prakash 	if (ps != NULL) {
44351e66a47SVivek Prakash 		size_t n = pe - ps;
44451e66a47SVivek Prakash 		if (l + n + 4 > len)
44551e66a47SVivek Prakash 			goto elen;
44651e66a47SVivek Prakash 		*ip++ = '$';
44751e66a47SVivek Prakash 		*ip++ = '<';
44851e66a47SVivek Prakash 		strncpy(ip, ps, n);
44951e66a47SVivek Prakash 		ip += n;
45051e66a47SVivek Prakash 		*ip++ = '/';
45151e66a47SVivek Prakash 		*ip++ = '>';
45251e66a47SVivek Prakash 	}
45351e66a47SVivek Prakash 
45451e66a47SVivek Prakash 	*ip = '\0';
45551e66a47SVivek Prakash 	return info;
45651e66a47SVivek Prakash 
45751e66a47SVivek Prakash elen:
45851e66a47SVivek Prakash 	free(info);
45951e66a47SVivek Prakash 	errno = ENOMEM;
46051e66a47SVivek Prakash 	return NULL;
46151e66a47SVivek Prakash }
46251e66a47SVivek Prakash 
46351e66a47SVivek Prakash typedef struct {
46451e66a47SVivek Prakash 	const char *name;
46551e66a47SVivek Prakash 	const char *cap;
46651e66a47SVivek Prakash } DEF_INFO;
46751e66a47SVivek Prakash 
46851e66a47SVivek Prakash static DEF_INFO def_infos[] = {
46951e66a47SVivek Prakash 	{ "bel",	"^G" },
47051e66a47SVivek Prakash 	{ "cr",		"^M" },
47151e66a47SVivek Prakash 	{ "cud1",	"^J" },
47251e66a47SVivek Prakash 	{ "ht",		"^I" },
47351e66a47SVivek Prakash 	{ "ind",	"^J" },
47451e66a47SVivek Prakash 	{ "kbs",	"^H" },
47551e66a47SVivek Prakash 	{ "kcub1",	"^H" },
47651e66a47SVivek Prakash 	{ "kcud1",	"^J" },
47751e66a47SVivek Prakash 	{ "nel",	"^M^J" }
47851e66a47SVivek Prakash };
47951e66a47SVivek Prakash 
48051e66a47SVivek Prakash char *
captoinfo(char * cap)48151e66a47SVivek Prakash captoinfo(char *cap)
48251e66a47SVivek Prakash {
48351e66a47SVivek Prakash 	char *info, *ip, *token, *val, *p, tok[3];
48451e66a47SVivek Prakash 	const char *name;
48551e66a47SVivek Prakash 	size_t len, lp, nl, vl, rl;
48651e66a47SVivek Prakash 	int defs[__arraycount(def_infos)], fv;
48751e66a47SVivek Prakash 
48851e66a47SVivek Prakash 	_DIAGASSERT(cap != NULL);
48951e66a47SVivek Prakash 
49051e66a47SVivek Prakash 	len = strlen(cap) * 2;
49151e66a47SVivek Prakash 	len += __arraycount(def_infos) * (5 + 4 + 3); /* reserve for defs */
49251e66a47SVivek Prakash 	info = ip = malloc(len);
49351e66a47SVivek Prakash 	if (info == NULL)
49451e66a47SVivek Prakash 		return NULL;
49551e66a47SVivek Prakash 
49651e66a47SVivek Prakash 	memset(defs, 0, sizeof(defs));
49751e66a47SVivek Prakash 	lp = 0;
49851e66a47SVivek Prakash 	tok[2] = '\0';
49951e66a47SVivek Prakash 	for (token = _ti_get_token(&cap, ':');
50051e66a47SVivek Prakash 	     token != NULL;
50151e66a47SVivek Prakash 	     token = _ti_get_token(&cap, ':'))
50251e66a47SVivek Prakash 	{
50351e66a47SVivek Prakash 		if (token[0] == '\0')
50451e66a47SVivek Prakash 			continue;
50551e66a47SVivek Prakash 		name = token;
50651e66a47SVivek Prakash 		val = p = NULL;
50751e66a47SVivek Prakash 		fv = nl = 0;
50851e66a47SVivek Prakash 		if (token[1] != '\0') {
50951e66a47SVivek Prakash 			tok[0] = token[0];
51051e66a47SVivek Prakash 			tok[1] = token[1];
51151e66a47SVivek Prakash 			nl = 1;
51251e66a47SVivek Prakash 			if (token[2] == '\0') {
51351e66a47SVivek Prakash 				name = flagname(tok);
51451e66a47SVivek Prakash 				val = NULL;
51551e66a47SVivek Prakash 			} else if (token[2] == '#') {
51651e66a47SVivek Prakash 				name = numname(tok);
51751e66a47SVivek Prakash 				val = token + 2;
51851e66a47SVivek Prakash 			} else if (token[2] == '=') {
51951e66a47SVivek Prakash 				name = strname(tok);
52051e66a47SVivek Prakash 				val = strval(token + 2);
52151e66a47SVivek Prakash 				fv = 1;
52251e66a47SVivek Prakash 			} else
52351e66a47SVivek Prakash 				nl = 0;
52451e66a47SVivek Prakash 		}
52551e66a47SVivek Prakash 		/* If not matched we may need to convert padding still. */
52651e66a47SVivek Prakash 		if (nl == 0) {
52751e66a47SVivek Prakash 			p = strchr(name, '=');
52851e66a47SVivek Prakash 			if (p != NULL) {
52951e66a47SVivek Prakash 				val = strval(p);
53051e66a47SVivek Prakash 				*p = '\0';
53151e66a47SVivek Prakash 				fv = 1;
53251e66a47SVivek Prakash 			}
53351e66a47SVivek Prakash 		}
53451e66a47SVivek Prakash 
53551e66a47SVivek Prakash 		/* See if this sets a default. */
53651e66a47SVivek Prakash 		for (nl = 0; nl < __arraycount(def_infos); nl++) {
53751e66a47SVivek Prakash 			if (strcmp(name, def_infos[nl].name) == 0) {
53851e66a47SVivek Prakash 				defs[nl] = 1;
53951e66a47SVivek Prakash 				break;
54051e66a47SVivek Prakash 			}
54151e66a47SVivek Prakash 		}
54251e66a47SVivek Prakash 
54351e66a47SVivek Prakash 		nl = strlen(name);
54451e66a47SVivek Prakash 		if (val == NULL)
54551e66a47SVivek Prakash 			vl = 0;
54651e66a47SVivek Prakash 		else
54751e66a47SVivek Prakash 			vl = strlen(val);
54851e66a47SVivek Prakash 		rl = nl + vl + 3; /* , \0 */
54951e66a47SVivek Prakash 
55051e66a47SVivek Prakash 		if (lp + rl > len) {
55151e66a47SVivek Prakash 			if (rl < 256)
55251e66a47SVivek Prakash 				len += 256;
55351e66a47SVivek Prakash 			else
55451e66a47SVivek Prakash 				len += rl;
55551e66a47SVivek Prakash 			p = realloc(info, len);
55651e66a47SVivek Prakash 			if (p == NULL)
55751e66a47SVivek Prakash 				return NULL;
55851e66a47SVivek Prakash 			info = p;
55951e66a47SVivek Prakash 		}
56051e66a47SVivek Prakash 
56151e66a47SVivek Prakash 		if (ip != info) {
56251e66a47SVivek Prakash 			*ip++ = ',';
56351e66a47SVivek Prakash 			*ip++ = ' ';
56451e66a47SVivek Prakash 		}
56551e66a47SVivek Prakash 
56651e66a47SVivek Prakash 		strcpy(ip, name);
56751e66a47SVivek Prakash 		ip += nl;
56851e66a47SVivek Prakash 		if (val != NULL) {
56951e66a47SVivek Prakash 			strcpy(ip, val);
57051e66a47SVivek Prakash 			ip += vl;
57151e66a47SVivek Prakash 			if (fv == 1)
57251e66a47SVivek Prakash 				free(val);
57351e66a47SVivek Prakash 		}
57451e66a47SVivek Prakash 	}
57551e66a47SVivek Prakash 
57651e66a47SVivek Prakash 	/* Add any defaults not set above. */
57751e66a47SVivek Prakash 	for (nl = 0; nl < __arraycount(def_infos); nl++) {
57851e66a47SVivek Prakash 		if (defs[nl] == 0) {
57951e66a47SVivek Prakash 			*ip++ = ',';
58051e66a47SVivek Prakash 			*ip++ = ' ';
58151e66a47SVivek Prakash 			strcpy(ip, def_infos[nl].name);
58251e66a47SVivek Prakash 			ip += strlen(def_infos[nl].name);
58351e66a47SVivek Prakash 			*ip++ = '=';
58451e66a47SVivek Prakash 			strcpy(ip, def_infos[nl].cap);
58551e66a47SVivek Prakash 			ip += strlen(def_infos[nl].cap);
58651e66a47SVivek Prakash 		}
58751e66a47SVivek Prakash 	}
58851e66a47SVivek Prakash 
58951e66a47SVivek Prakash 	*ip = '\0';
59051e66a47SVivek Prakash 	return info;
59151e66a47SVivek Prakash }
59251e66a47SVivek Prakash 
593