xref: /freebsd/contrib/ncurses/ncurses/tinfo/captoinfo.c (revision 21817992b3314c908ab50f0bb88d2ee750b9c4ac)
10e3d5408SPeter Wemm /****************************************************************************
2*21817992SBaptiste Daroussin  * Copyright 2018-2020,2021 Thomas E. Dickey                                *
3e1865124SBaptiste Daroussin  * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
40e3d5408SPeter Wemm  *                                                                          *
50e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
60e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
70e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
80e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
90e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
100e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
110e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
120e3d5408SPeter Wemm  *                                                                          *
130e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
140e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
150e3d5408SPeter Wemm  *                                                                          *
160e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
170e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
180e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
190e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
200e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
210e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
220e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
230e3d5408SPeter Wemm  *                                                                          *
240e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
250e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
260e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
270e3d5408SPeter Wemm  * authorization.                                                           *
280e3d5408SPeter Wemm  ****************************************************************************/
290e3d5408SPeter Wemm 
300e3d5408SPeter Wemm /****************************************************************************
310e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
320e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
334a1a9510SRong-En Fan  *     and: Thomas E. Dickey                        1996-on                 *
340e3d5408SPeter Wemm  ****************************************************************************/
350e3d5408SPeter Wemm 
360e3d5408SPeter Wemm /*
37aae38d10SBaptiste Daroussin  *	captoinfo.c
38aae38d10SBaptiste Daroussin  *
39aae38d10SBaptiste Daroussin  *	Provide conversion in both directions between termcap and terminfo.
40aae38d10SBaptiste Daroussin  *
41aae38d10SBaptiste Daroussin  * cap-to-info --- conversion between termcap and terminfo formats
420e3d5408SPeter Wemm  *
430e3d5408SPeter Wemm  *	The captoinfo() code was swiped from Ross Ridge's mytinfo package,
440e3d5408SPeter Wemm  *	adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>.
450e3d5408SPeter Wemm  *
46aae38d10SBaptiste Daroussin  *	It has just one entry point:
470e3d5408SPeter Wemm  *
484a1a9510SRong-En Fan  *	char *_nc_captoinfo(n, s, parameterized)
490e3d5408SPeter Wemm  *
500e3d5408SPeter Wemm  *	Convert value s for termcap string capability named n into terminfo
510e3d5408SPeter Wemm  *	format.
520e3d5408SPeter Wemm  *
530e3d5408SPeter Wemm  *	This code recognizes all the standard 4.4BSD %-escapes:
540e3d5408SPeter Wemm  *
550e3d5408SPeter Wemm  *	%%       output `%'
560e3d5408SPeter Wemm  *	%d       output value as in printf %d
570e3d5408SPeter Wemm  *	%2       output value as in printf %2d
580e3d5408SPeter Wemm  *	%3       output value as in printf %3d
590e3d5408SPeter Wemm  *	%.       output value as in printf %c
600e3d5408SPeter Wemm  *	%+x      add x to value, then do %.
610e3d5408SPeter Wemm  *	%>xy     if value > x then add y, no output
620e3d5408SPeter Wemm  *	%r       reverse order of two parameters, no output
630e3d5408SPeter Wemm  *	%i       increment by one, no output
640e3d5408SPeter Wemm  *	%n       exclusive-or all parameters with 0140 (Datamedia 2500)
650e3d5408SPeter Wemm  *	%B       BCD (16*(value/10)) + (value%10), no output
660e3d5408SPeter Wemm  *	%D       Reverse coding (value - 2*(value%16)), no output (Delta Data).
670e3d5408SPeter Wemm  *
680e3d5408SPeter Wemm  *	Also, %02 and %03 are accepted as synonyms for %2 and %3.
690e3d5408SPeter Wemm  *
700e3d5408SPeter Wemm  *	Besides all the standard termcap escapes, this translator understands
710e3d5408SPeter Wemm  *	the following extended escapes:
720e3d5408SPeter Wemm  *
730e3d5408SPeter Wemm  *	used by GNU Emacs termcap libraries
740e3d5408SPeter Wemm  *		%a[+*-/=][cp]x	GNU arithmetic.
750e3d5408SPeter Wemm  *		%m		xor the first two parameters by 0177
760e3d5408SPeter Wemm  *		%b		backup to previous parameter
770e3d5408SPeter Wemm  *		%f		skip this parameter
780e3d5408SPeter Wemm  *
790e3d5408SPeter Wemm  *	used by the University of Waterloo (MFCF) termcap libraries
800e3d5408SPeter Wemm  *		%-x	 subtract parameter FROM char x and output it as a char
810e3d5408SPeter Wemm  *		%ax	 add the character x to parameter
820e3d5408SPeter Wemm  *
830e3d5408SPeter Wemm  *	If #define WATERLOO is on, also enable these translations:
840e3d5408SPeter Wemm  *
850e3d5408SPeter Wemm  *		%sx	 subtract parameter FROM the character x
860e3d5408SPeter Wemm  *
870e3d5408SPeter Wemm  *	By default, this Waterloo translations are not compiled in, because
880e3d5408SPeter Wemm  *	the Waterloo %s conflicts with the way terminfo uses %s in strings for
890e3d5408SPeter Wemm  *	function programming.
900e3d5408SPeter Wemm  *
910e3d5408SPeter Wemm  *	Note the two definitions of %a: the GNU definition is translated if the
920e3d5408SPeter Wemm  *	characters after the 'a' are valid for it, otherwise the UW definition
930e3d5408SPeter Wemm  *	is translated.
940e3d5408SPeter Wemm  */
950e3d5408SPeter Wemm 
960e3d5408SPeter Wemm #include <curses.priv.h>
970e3d5408SPeter Wemm 
980e3d5408SPeter Wemm #include <ctype.h>
990e3d5408SPeter Wemm #include <tic.h>
1000e3d5408SPeter Wemm 
101*21817992SBaptiste Daroussin MODULE_ID("$Id: captoinfo.c,v 1.102 2021/09/04 10:29:15 tom Exp $")
102aae38d10SBaptiste Daroussin 
103aae38d10SBaptiste Daroussin #if 0
104aae38d10SBaptiste Daroussin #define DEBUG_THIS(p) DEBUG(9, p)
105aae38d10SBaptiste Daroussin #else
106aae38d10SBaptiste Daroussin #define DEBUG_THIS(p)		/* nothing */
107aae38d10SBaptiste Daroussin #endif
1080e3d5408SPeter Wemm 
1090e3d5408SPeter Wemm #define MAX_PUSHED	16	/* max # args we can push onto the stack */
1100e3d5408SPeter Wemm 
1110e3d5408SPeter Wemm static int stack[MAX_PUSHED];	/* the stack */
1120e3d5408SPeter Wemm static int stackptr;		/* the next empty place on the stack */
1130e3d5408SPeter Wemm static int onstack;		/* the top of stack */
1140e3d5408SPeter Wemm static int seenm;		/* seen a %m */
1150e3d5408SPeter Wemm static int seenn;		/* seen a %n */
1160e3d5408SPeter Wemm static int seenr;		/* seen a %r */
1170e3d5408SPeter Wemm static int param;		/* current parameter */
1180e3d5408SPeter Wemm static char *dp;		/* pointer to end of the converted string */
1190e3d5408SPeter Wemm 
1200e3d5408SPeter Wemm static char *my_string;
1210e3d5408SPeter Wemm static size_t my_length;
1220e3d5408SPeter Wemm 
12315589c42SPeter Wemm static char *
init_string(void)12415589c42SPeter Wemm init_string(void)
1250e3d5408SPeter Wemm /* initialize 'my_string', 'my_length' */
1260e3d5408SPeter Wemm {
1270e3d5408SPeter Wemm     if (my_string == 0)
12873f0a83dSXin LI 	TYPE_MALLOC(char, my_length = 256, my_string);
1290e3d5408SPeter Wemm 
1300e3d5408SPeter Wemm     *my_string = '\0';
1310e3d5408SPeter Wemm     return my_string;
1320e3d5408SPeter Wemm }
1330e3d5408SPeter Wemm 
13415589c42SPeter Wemm static char *
save_string(char * d,const char * const s)13515589c42SPeter Wemm save_string(char *d, const char *const s)
1360e3d5408SPeter Wemm {
13706bfebdeSXin LI     size_t have = (size_t) (d - my_string);
1380e3d5408SPeter Wemm     size_t need = have + strlen(s) + 2;
1390e3d5408SPeter Wemm     if (need > my_length) {
14006bfebdeSXin LI 	my_string = (char *) _nc_doalloc(my_string, my_length = (need + need));
1410e3d5408SPeter Wemm 	if (my_string == 0)
1424a1a9510SRong-En Fan 	    _nc_err_abort(MSG_NO_MEMORY);
1430e3d5408SPeter Wemm 	d = my_string + have;
1440e3d5408SPeter Wemm     }
14573f0a83dSXin LI     _nc_STRCPY(d, s, my_length - have);
1460e3d5408SPeter Wemm     return d + strlen(d);
1470e3d5408SPeter Wemm }
1480e3d5408SPeter Wemm 
1494a1a9510SRong-En Fan static NCURSES_INLINE char *
save_char(char * s,int c)1504a1a9510SRong-En Fan save_char(char *s, int c)
1510e3d5408SPeter Wemm {
1520e3d5408SPeter Wemm     static char temp[2];
1534a1a9510SRong-En Fan     temp[0] = (char) c;
1540e3d5408SPeter Wemm     return save_string(s, temp);
1550e3d5408SPeter Wemm }
1560e3d5408SPeter Wemm 
15715589c42SPeter Wemm static void
push(void)15815589c42SPeter Wemm push(void)
1590e3d5408SPeter Wemm /* push onstack on to the stack */
1600e3d5408SPeter Wemm {
1615d08fb1fSRong-En Fan     if (stackptr >= MAX_PUSHED)
1620e3d5408SPeter Wemm 	_nc_warning("string too complex to convert");
1630e3d5408SPeter Wemm     else
1640e3d5408SPeter Wemm 	stack[stackptr++] = onstack;
1650e3d5408SPeter Wemm }
1660e3d5408SPeter Wemm 
16715589c42SPeter Wemm static void
pop(void)16815589c42SPeter Wemm pop(void)
1690e3d5408SPeter Wemm /* pop the top of the stack into onstack */
1700e3d5408SPeter Wemm {
1710e3d5408SPeter Wemm     if (stackptr == 0) {
1720e3d5408SPeter Wemm 	if (onstack == 0)
1730e3d5408SPeter Wemm 	    _nc_warning("I'm confused");
1740e3d5408SPeter Wemm 	else
1750e3d5408SPeter Wemm 	    onstack = 0;
17615589c42SPeter Wemm     } else
1770e3d5408SPeter Wemm 	onstack = stack[--stackptr];
1780e3d5408SPeter Wemm     param++;
1790e3d5408SPeter Wemm }
1800e3d5408SPeter Wemm 
18115589c42SPeter Wemm static int
cvtchar(register const char * sp)18215589c42SPeter Wemm cvtchar(register const char *sp)
1830e3d5408SPeter Wemm /* convert a character to a terminfo push */
1840e3d5408SPeter Wemm {
1850e3d5408SPeter Wemm     unsigned char c = 0;
1860e3d5408SPeter Wemm     int len;
1870e3d5408SPeter Wemm 
1880e3d5408SPeter Wemm     switch (*sp) {
1890e3d5408SPeter Wemm     case '\\':
1900e3d5408SPeter Wemm 	switch (*++sp) {
1910e3d5408SPeter Wemm 	case '\'':
1920e3d5408SPeter Wemm 	case '$':
1930e3d5408SPeter Wemm 	case '\\':
1940e3d5408SPeter Wemm 	case '%':
195aae38d10SBaptiste Daroussin 	    c = UChar(*sp);
1960e3d5408SPeter Wemm 	    len = 2;
1970e3d5408SPeter Wemm 	    break;
1980e3d5408SPeter Wemm 	case '\0':
1990e3d5408SPeter Wemm 	    c = '\\';
2000e3d5408SPeter Wemm 	    len = 1;
2010e3d5408SPeter Wemm 	    break;
2020e3d5408SPeter Wemm 	case '0':
2030e3d5408SPeter Wemm 	case '1':
2040e3d5408SPeter Wemm 	case '2':
2050e3d5408SPeter Wemm 	case '3':
2060e3d5408SPeter Wemm 	    len = 1;
20739f2269fSPeter Wemm 	    while (isdigit(UChar(*sp))) {
208aae38d10SBaptiste Daroussin 		c = UChar(8 * c + (*sp++ - '0'));
2090e3d5408SPeter Wemm 		len++;
2100e3d5408SPeter Wemm 	    }
2110e3d5408SPeter Wemm 	    break;
2120e3d5408SPeter Wemm 	default:
213aae38d10SBaptiste Daroussin 	    c = UChar(*sp);
214aae38d10SBaptiste Daroussin 	    len = (c != '\0') ? 2 : 1;
2150e3d5408SPeter Wemm 	    break;
2160e3d5408SPeter Wemm 	}
2170e3d5408SPeter Wemm 	break;
2180e3d5408SPeter Wemm     case '^':
2190e3d5408SPeter Wemm 	len = 2;
2207a656419SBaptiste Daroussin 	c = UChar(*++sp);
2217a656419SBaptiste Daroussin 	if (c == '?') {
2227a656419SBaptiste Daroussin 	    c = 127;
2237a656419SBaptiste Daroussin 	} else if (c == '\0') {
2247a656419SBaptiste Daroussin 	    len = 1;
2257a656419SBaptiste Daroussin 	} else {
2267a656419SBaptiste Daroussin 	    c &= 0x1f;
2277a656419SBaptiste Daroussin 	}
2280e3d5408SPeter Wemm 	break;
2290e3d5408SPeter Wemm     default:
230aae38d10SBaptiste Daroussin 	c = UChar(*sp);
231aae38d10SBaptiste Daroussin 	len = (c != '\0') ? 1 : 0;
2320e3d5408SPeter Wemm     }
2330e3d5408SPeter Wemm     if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
23415589c42SPeter Wemm 	dp = save_string(dp, "%\'");
23515589c42SPeter Wemm 	dp = save_char(dp, c);
23615589c42SPeter Wemm 	dp = save_char(dp, '\'');
237aae38d10SBaptiste Daroussin     } else if (c != '\0') {
23815589c42SPeter Wemm 	dp = save_string(dp, "%{");
2390e3d5408SPeter Wemm 	if (c > 99)
24015589c42SPeter Wemm 	    dp = save_char(dp, c / 100 + '0');
2410e3d5408SPeter Wemm 	if (c > 9)
24215589c42SPeter Wemm 	    dp = save_char(dp, ((int) (c / 10)) % 10 + '0');
24315589c42SPeter Wemm 	dp = save_char(dp, c % 10 + '0');
24415589c42SPeter Wemm 	dp = save_char(dp, '}');
2450e3d5408SPeter Wemm     }
2460e3d5408SPeter Wemm     return len;
2470e3d5408SPeter Wemm }
2480e3d5408SPeter Wemm 
24915589c42SPeter Wemm static void
getparm(int parm,int n)25015589c42SPeter Wemm getparm(int parm, int n)
2510e3d5408SPeter Wemm /* push n copies of param on the terminfo stack if not already there */
2520e3d5408SPeter Wemm {
253aae38d10SBaptiste Daroussin     int nn;
254aae38d10SBaptiste Daroussin 
2550e3d5408SPeter Wemm     if (seenr) {
2560e3d5408SPeter Wemm 	if (parm == 1)
2570e3d5408SPeter Wemm 	    parm = 2;
2580e3d5408SPeter Wemm 	else if (parm == 2)
2590e3d5408SPeter Wemm 	    parm = 1;
2600e3d5408SPeter Wemm     }
26173f0a83dSXin LI 
262aae38d10SBaptiste Daroussin     for (nn = 0; nn < n; ++nn) {
26373f0a83dSXin LI 	dp = save_string(dp, "%p");
26473f0a83dSXin LI 	dp = save_char(dp, '0' + parm);
26573f0a83dSXin LI     }
26673f0a83dSXin LI 
2670e3d5408SPeter Wemm     if (onstack == parm) {
2680e3d5408SPeter Wemm 	if (n > 1) {
2690e3d5408SPeter Wemm 	    _nc_warning("string may not be optimal");
27015589c42SPeter Wemm 	    dp = save_string(dp, "%Pa");
271aae38d10SBaptiste Daroussin 	    while (n-- > 0) {
27215589c42SPeter Wemm 		dp = save_string(dp, "%ga");
2730e3d5408SPeter Wemm 	    }
2740e3d5408SPeter Wemm 	}
2750e3d5408SPeter Wemm 	return;
2760e3d5408SPeter Wemm     }
2770e3d5408SPeter Wemm     if (onstack != 0)
2780e3d5408SPeter Wemm 	push();
2790e3d5408SPeter Wemm 
2800e3d5408SPeter Wemm     onstack = parm;
2810e3d5408SPeter Wemm 
28215589c42SPeter Wemm     if (seenn && parm < 3) {
28315589c42SPeter Wemm 	dp = save_string(dp, "%{96}%^");
2840e3d5408SPeter Wemm     }
2850e3d5408SPeter Wemm 
28615589c42SPeter Wemm     if (seenm && parm < 3) {
28715589c42SPeter Wemm 	dp = save_string(dp, "%{127}%^");
2880e3d5408SPeter Wemm     }
2890e3d5408SPeter Wemm }
2900e3d5408SPeter Wemm 
2917a69bbfbSPeter Wemm /*
2927a69bbfbSPeter Wemm  * Convert a termcap string to terminfo format.
2937a69bbfbSPeter Wemm  * 'cap' is the relevant terminfo capability index.
2947a69bbfbSPeter Wemm  * 's' is the string value of the capability.
2954a1a9510SRong-En Fan  * 'parameterized' tells what type of translations to do:
2967a69bbfbSPeter Wemm  *	% translations if 1
2977a69bbfbSPeter Wemm  *	pad translations if >=0
2987a69bbfbSPeter Wemm  */
2994a1a9510SRong-En Fan NCURSES_EXPORT(char *)
_nc_captoinfo(const char * cap,const char * s,int const parameterized)3004a1a9510SRong-En Fan _nc_captoinfo(const char *cap, const char *s, int const parameterized)
3010e3d5408SPeter Wemm {
3020e3d5408SPeter Wemm     const char *capstart;
3030e3d5408SPeter Wemm 
3040e3d5408SPeter Wemm     stackptr = 0;
3050e3d5408SPeter Wemm     onstack = 0;
3060e3d5408SPeter Wemm     seenm = 0;
3070e3d5408SPeter Wemm     seenn = 0;
3080e3d5408SPeter Wemm     seenr = 0;
3090e3d5408SPeter Wemm     param = 1;
3100e3d5408SPeter Wemm 
311aae38d10SBaptiste Daroussin     DEBUG_THIS(("_nc_captoinfo params %d, %s", parameterized, s));
312aae38d10SBaptiste Daroussin 
31315589c42SPeter Wemm     dp = init_string();
3140e3d5408SPeter Wemm 
3150e3d5408SPeter Wemm     /* skip the initial padding (if we haven't been told not to) */
3160e3d5408SPeter Wemm     capstart = 0;
3170e3d5408SPeter Wemm     if (s == 0)
3180e3d5408SPeter Wemm 	s = "";
3194a1a9510SRong-En Fan     if (parameterized >= 0 && isdigit(UChar(*s)))
320aae38d10SBaptiste Daroussin 	for (capstart = s; *s != '\0'; s++)
32139f2269fSPeter Wemm 	    if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.'))
3220e3d5408SPeter Wemm 		break;
3230e3d5408SPeter Wemm 
3240e3d5408SPeter Wemm     while (*s != '\0') {
3250e3d5408SPeter Wemm 	switch (*s) {
3260e3d5408SPeter Wemm 	case '%':
3270e3d5408SPeter Wemm 	    s++;
3284a1a9510SRong-En Fan 	    if (parameterized < 1) {
32915589c42SPeter Wemm 		dp = save_char(dp, '%');
3300e3d5408SPeter Wemm 		break;
3310e3d5408SPeter Wemm 	    }
3320e3d5408SPeter Wemm 	    switch (*s++) {
33315589c42SPeter Wemm 	    case '%':
334aae38d10SBaptiste Daroussin 		dp = save_string(dp, "%%");
33515589c42SPeter Wemm 		break;
3360e3d5408SPeter Wemm 	    case 'r':
3370e3d5408SPeter Wemm 		if (seenr++ == 1) {
3380e3d5408SPeter Wemm 		    _nc_warning("saw %%r twice in %s", cap);
3390e3d5408SPeter Wemm 		}
3400e3d5408SPeter Wemm 		break;
3410e3d5408SPeter Wemm 	    case 'm':
3420e3d5408SPeter Wemm 		if (seenm++ == 1) {
3430e3d5408SPeter Wemm 		    _nc_warning("saw %%m twice in %s", cap);
3440e3d5408SPeter Wemm 		}
3450e3d5408SPeter Wemm 		break;
3460e3d5408SPeter Wemm 	    case 'n':
3470e3d5408SPeter Wemm 		if (seenn++ == 1) {
3480e3d5408SPeter Wemm 		    _nc_warning("saw %%n twice in %s", cap);
3490e3d5408SPeter Wemm 		}
3500e3d5408SPeter Wemm 		break;
35115589c42SPeter Wemm 	    case 'i':
35215589c42SPeter Wemm 		dp = save_string(dp, "%i");
35315589c42SPeter Wemm 		break;
3540e3d5408SPeter Wemm 	    case '6':
3550e3d5408SPeter Wemm 	    case 'B':
35615589c42SPeter Wemm 		getparm(param, 1);
35715589c42SPeter Wemm 		dp = save_string(dp, "%{10}%/%{16}%*");
35815589c42SPeter Wemm 		getparm(param, 1);
35915589c42SPeter Wemm 		dp = save_string(dp, "%{10}%m%+");
3600e3d5408SPeter Wemm 		break;
3610e3d5408SPeter Wemm 	    case '8':
3620e3d5408SPeter Wemm 	    case 'D':
3630e3d5408SPeter Wemm 		getparm(param, 2);
36415589c42SPeter Wemm 		dp = save_string(dp, "%{2}%*%-");
3650e3d5408SPeter Wemm 		break;
3660e3d5408SPeter Wemm 	    case '>':
3670e3d5408SPeter Wemm 		/* %?%{x}%>%t%{y}%+%; */
368aae38d10SBaptiste Daroussin 		if (s[0] && s[1]) {
369aae38d10SBaptiste Daroussin 		    getparm(param, 2);
37015589c42SPeter Wemm 		    dp = save_string(dp, "%?");
3710e3d5408SPeter Wemm 		    s += cvtchar(s);
37215589c42SPeter Wemm 		    dp = save_string(dp, "%>%t");
3730e3d5408SPeter Wemm 		    s += cvtchar(s);
37415589c42SPeter Wemm 		    dp = save_string(dp, "%+%;");
375aae38d10SBaptiste Daroussin 		} else {
376aae38d10SBaptiste Daroussin 		    _nc_warning("expected two characters after %%>");
377aae38d10SBaptiste Daroussin 		    dp = save_string(dp, "%>");
378aae38d10SBaptiste Daroussin 		}
3790e3d5408SPeter Wemm 		break;
3800e3d5408SPeter Wemm 	    case 'a':
3810e3d5408SPeter Wemm 		if ((*s == '=' || *s == '+' || *s == '-'
3820e3d5408SPeter Wemm 		     || *s == '*' || *s == '/')
3830e3d5408SPeter Wemm 		    && (s[1] == 'p' || s[1] == 'c')
3840e3d5408SPeter Wemm 		    && s[2] != '\0') {
3850e3d5408SPeter Wemm 		    int l;
3860e3d5408SPeter Wemm 		    l = 2;
3870e3d5408SPeter Wemm 		    if (*s != '=')
3880e3d5408SPeter Wemm 			getparm(param, 1);
3890e3d5408SPeter Wemm 		    if (s[1] == 'p') {
3900e3d5408SPeter Wemm 			getparm(param + s[2] - '@', 1);
3910e3d5408SPeter Wemm 			if (param != onstack) {
3920e3d5408SPeter Wemm 			    pop();
3930e3d5408SPeter Wemm 			    param--;
3940e3d5408SPeter Wemm 			}
3950e3d5408SPeter Wemm 			l++;
3960e3d5408SPeter Wemm 		    } else
3970e3d5408SPeter Wemm 			l += cvtchar(s + 2);
3980e3d5408SPeter Wemm 		    switch (*s) {
3990e3d5408SPeter Wemm 		    case '+':
40015589c42SPeter Wemm 			dp = save_string(dp, "%+");
4010e3d5408SPeter Wemm 			break;
4020e3d5408SPeter Wemm 		    case '-':
40315589c42SPeter Wemm 			dp = save_string(dp, "%-");
4040e3d5408SPeter Wemm 			break;
4050e3d5408SPeter Wemm 		    case '*':
40615589c42SPeter Wemm 			dp = save_string(dp, "%*");
4070e3d5408SPeter Wemm 			break;
4080e3d5408SPeter Wemm 		    case '/':
40915589c42SPeter Wemm 			dp = save_string(dp, "%/");
4100e3d5408SPeter Wemm 			break;
4110e3d5408SPeter Wemm 		    case '=':
4120e3d5408SPeter Wemm 			if (seenr) {
4130e3d5408SPeter Wemm 			    if (param == 1)
4140e3d5408SPeter Wemm 				onstack = 2;
4150e3d5408SPeter Wemm 			    else if (param == 2)
4160e3d5408SPeter Wemm 				onstack = 1;
4170e3d5408SPeter Wemm 			    else
4180e3d5408SPeter Wemm 				onstack = param;
41915589c42SPeter Wemm 			} else
4200e3d5408SPeter Wemm 			    onstack = param;
4210e3d5408SPeter Wemm 			break;
4220e3d5408SPeter Wemm 		    }
4230e3d5408SPeter Wemm 		    s += l;
4240e3d5408SPeter Wemm 		    break;
4250e3d5408SPeter Wemm 		}
4260e3d5408SPeter Wemm 		getparm(param, 1);
4270e3d5408SPeter Wemm 		s += cvtchar(s);
42815589c42SPeter Wemm 		dp = save_string(dp, "%+");
4290e3d5408SPeter Wemm 		break;
4300e3d5408SPeter Wemm 	    case '+':
4310e3d5408SPeter Wemm 		getparm(param, 1);
4320e3d5408SPeter Wemm 		s += cvtchar(s);
43315589c42SPeter Wemm 		dp = save_string(dp, "%+%c");
4340e3d5408SPeter Wemm 		pop();
4350e3d5408SPeter Wemm 		break;
4360e3d5408SPeter Wemm 	    case 's':
4370e3d5408SPeter Wemm #ifdef WATERLOO
4380e3d5408SPeter Wemm 		s += cvtchar(s);
4390e3d5408SPeter Wemm 		getparm(param, 1);
44015589c42SPeter Wemm 		dp = save_string(dp, "%-");
4410e3d5408SPeter Wemm #else
4420e3d5408SPeter Wemm 		getparm(param, 1);
44315589c42SPeter Wemm 		dp = save_string(dp, "%s");
4440e3d5408SPeter Wemm 		pop();
4450e3d5408SPeter Wemm #endif /* WATERLOO */
4460e3d5408SPeter Wemm 		break;
4470e3d5408SPeter Wemm 	    case '-':
4480e3d5408SPeter Wemm 		s += cvtchar(s);
4490e3d5408SPeter Wemm 		getparm(param, 1);
45015589c42SPeter Wemm 		dp = save_string(dp, "%-%c");
4510e3d5408SPeter Wemm 		pop();
4520e3d5408SPeter Wemm 		break;
4530e3d5408SPeter Wemm 	    case '.':
4540e3d5408SPeter Wemm 		getparm(param, 1);
45515589c42SPeter Wemm 		dp = save_string(dp, "%c");
4560e3d5408SPeter Wemm 		pop();
4570e3d5408SPeter Wemm 		break;
4580e3d5408SPeter Wemm 	    case '0':		/* not clear any of the historical termcaps did this */
459aae38d10SBaptiste Daroussin 		if (*s == '3') {
460aae38d10SBaptiste Daroussin 		    ++s;
4610e3d5408SPeter Wemm 		    goto see03;
462aae38d10SBaptiste Daroussin 		}
463aae38d10SBaptiste Daroussin 		if (*s == '2') {
464aae38d10SBaptiste Daroussin 		    ++s;
465aae38d10SBaptiste Daroussin 		    goto see02;
466aae38d10SBaptiste Daroussin 		}
4670e3d5408SPeter Wemm 		goto invalid;
4680e3d5408SPeter Wemm 	    case '2':
469aae38d10SBaptiste Daroussin 	      see02:
4700e3d5408SPeter Wemm 		getparm(param, 1);
47115589c42SPeter Wemm 		dp = save_string(dp, "%2d");
4720e3d5408SPeter Wemm 		pop();
4730e3d5408SPeter Wemm 		break;
47415589c42SPeter Wemm 	    case '3':
47515589c42SPeter Wemm 	      see03:
4760e3d5408SPeter Wemm 		getparm(param, 1);
47715589c42SPeter Wemm 		dp = save_string(dp, "%3d");
4780e3d5408SPeter Wemm 		pop();
4790e3d5408SPeter Wemm 		break;
4800e3d5408SPeter Wemm 	    case 'd':
4810e3d5408SPeter Wemm 		getparm(param, 1);
48215589c42SPeter Wemm 		dp = save_string(dp, "%d");
4830e3d5408SPeter Wemm 		pop();
4840e3d5408SPeter Wemm 		break;
4850e3d5408SPeter Wemm 	    case 'f':
4860e3d5408SPeter Wemm 		param++;
4870e3d5408SPeter Wemm 		break;
4880e3d5408SPeter Wemm 	    case 'b':
4890e3d5408SPeter Wemm 		param--;
4900e3d5408SPeter Wemm 		break;
4910e3d5408SPeter Wemm 	    case '\\':
49215589c42SPeter Wemm 		dp = save_string(dp, "%\\");
4930e3d5408SPeter Wemm 		break;
49415589c42SPeter Wemm 	    default:
49515589c42SPeter Wemm 	      invalid:
49615589c42SPeter Wemm 		dp = save_char(dp, '%');
4970e3d5408SPeter Wemm 		s--;
49815589c42SPeter Wemm 		_nc_warning("unknown %% code %s (%#x) in %s",
49939f2269fSPeter Wemm 			    unctrl((chtype) *s), UChar(*s), cap);
5000e3d5408SPeter Wemm 		break;
5010e3d5408SPeter Wemm 	    }
5020e3d5408SPeter Wemm 	    break;
5030e3d5408SPeter Wemm 	default:
504aae38d10SBaptiste Daroussin 	    if (*s != '\0')
50515589c42SPeter Wemm 		dp = save_char(dp, *s++);
5060e3d5408SPeter Wemm 	    break;
5070e3d5408SPeter Wemm 	}
5080e3d5408SPeter Wemm     }
5090e3d5408SPeter Wemm 
5100e3d5408SPeter Wemm     /*
5110e3d5408SPeter Wemm      * Now, if we stripped off some leading padding, add it at the end
5120e3d5408SPeter Wemm      * of the string as mandatory padding.
5130e3d5408SPeter Wemm      */
51415589c42SPeter Wemm     if (capstart) {
51515589c42SPeter Wemm 	dp = save_string(dp, "$<");
516aae38d10SBaptiste Daroussin 	for (s = capstart; *s != '\0'; s++)
51739f2269fSPeter Wemm 	    if (isdigit(UChar(*s)) || *s == '*' || *s == '.')
51815589c42SPeter Wemm 		dp = save_char(dp, *s);
5190e3d5408SPeter Wemm 	    else
5200e3d5408SPeter Wemm 		break;
52115589c42SPeter Wemm 	dp = save_string(dp, "/>");
5220e3d5408SPeter Wemm     }
5230e3d5408SPeter Wemm 
52415589c42SPeter Wemm     (void) save_char(dp, '\0');
525aae38d10SBaptiste Daroussin 
526aae38d10SBaptiste Daroussin     DEBUG_THIS(("... _nc_captoinfo %s", NonNull(my_string)));
527aae38d10SBaptiste Daroussin 
52815589c42SPeter Wemm     return (my_string);
52915589c42SPeter Wemm }
53015589c42SPeter Wemm 
53115589c42SPeter Wemm /*
53215589c42SPeter Wemm  * Check for an expression that corresponds to "%B" (BCD):
53315589c42SPeter Wemm  *	(parameter / 10) * 16 + (parameter % 10)
53415589c42SPeter Wemm  */
53515589c42SPeter Wemm static int
bcd_expression(const char * str)53615589c42SPeter Wemm bcd_expression(const char *str)
53715589c42SPeter Wemm {
53815589c42SPeter Wemm     /* leave this non-const for HPUX */
53915589c42SPeter Wemm     static char fmt[] = "%%p%c%%{10}%%/%%{16}%%*%%p%c%%{10}%%m%%+";
54015589c42SPeter Wemm     int len = 0;
54115589c42SPeter Wemm     char ch1, ch2;
54215589c42SPeter Wemm 
54315589c42SPeter Wemm     if (sscanf(str, fmt, &ch1, &ch2) == 2
54439f2269fSPeter Wemm 	&& isdigit(UChar(ch1))
54539f2269fSPeter Wemm 	&& isdigit(UChar(ch2))
54615589c42SPeter Wemm 	&& (ch1 == ch2)) {
54715589c42SPeter Wemm 	len = 28;
54815589c42SPeter Wemm #ifndef NDEBUG
54915589c42SPeter Wemm 	{
55015589c42SPeter Wemm 	    char buffer[80];
55115589c42SPeter Wemm 	    int tst;
55273f0a83dSXin LI 	    _nc_SPRINTF(buffer, _nc_SLIMIT(sizeof(buffer)) fmt, ch1, ch2);
55315589c42SPeter Wemm 	    tst = strlen(buffer) - 1;
55415589c42SPeter Wemm 	    assert(len == tst);
55515589c42SPeter Wemm 	}
55615589c42SPeter Wemm #endif
55715589c42SPeter Wemm     }
55815589c42SPeter Wemm     return len;
55915589c42SPeter Wemm }
56015589c42SPeter Wemm 
56115589c42SPeter Wemm static char *
save_tc_char(char * bufptr,int c1)56215589c42SPeter Wemm save_tc_char(char *bufptr, int c1)
56315589c42SPeter Wemm {
56415589c42SPeter Wemm     if (is7bits(c1) && isprint(c1)) {
56515589c42SPeter Wemm 	if (c1 == ':' || c1 == '\\')
56615589c42SPeter Wemm 	    bufptr = save_char(bufptr, '\\');
56715589c42SPeter Wemm 	bufptr = save_char(bufptr, c1);
56815589c42SPeter Wemm     } else {
569aae38d10SBaptiste Daroussin 	char temp[80];
570aae38d10SBaptiste Daroussin 
57173f0a83dSXin LI 	if (c1 == (c1 & 0x1f)) {	/* iscntrl() returns T on 255 */
57273f0a83dSXin LI 	    _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
57373f0a83dSXin LI 			"%.20s", unctrl((chtype) c1));
57473f0a83dSXin LI 	} else {
57573f0a83dSXin LI 	    _nc_SPRINTF(temp, _nc_SLIMIT(sizeof(temp))
57673f0a83dSXin LI 			"\\%03o", c1);
57773f0a83dSXin LI 	}
57815589c42SPeter Wemm 	bufptr = save_string(bufptr, temp);
57915589c42SPeter Wemm     }
58015589c42SPeter Wemm     return bufptr;
58115589c42SPeter Wemm }
58215589c42SPeter Wemm 
58315589c42SPeter Wemm static char *
save_tc_inequality(char * bufptr,int c1,int c2)58415589c42SPeter Wemm save_tc_inequality(char *bufptr, int c1, int c2)
58515589c42SPeter Wemm {
58615589c42SPeter Wemm     bufptr = save_string(bufptr, "%>");
58715589c42SPeter Wemm     bufptr = save_tc_char(bufptr, c1);
58815589c42SPeter Wemm     bufptr = save_tc_char(bufptr, c2);
58915589c42SPeter Wemm     return bufptr;
5900e3d5408SPeter Wemm }
5910e3d5408SPeter Wemm 
5920e3d5408SPeter Wemm /*
593aae38d10SBaptiste Daroussin  * info-to-cap --- conversion between terminfo and termcap formats
594aae38d10SBaptiste Daroussin  *
5950e3d5408SPeter Wemm  * Here are the capabilities infotocap assumes it can translate to:
5960e3d5408SPeter Wemm  *
5970e3d5408SPeter Wemm  *     %%       output `%'
5980e3d5408SPeter Wemm  *     %d       output value as in printf %d
5990e3d5408SPeter Wemm  *     %2       output value as in printf %2d
6000e3d5408SPeter Wemm  *     %3       output value as in printf %3d
6010e3d5408SPeter Wemm  *     %.       output value as in printf %c
6020e3d5408SPeter Wemm  *     %+c      add character c to value, then do %.
6030e3d5408SPeter Wemm  *     %>xy     if value > x then add y, no output
6040e3d5408SPeter Wemm  *     %r       reverse order of two parameters, no output
6050e3d5408SPeter Wemm  *     %i       increment by one, no output
6060e3d5408SPeter Wemm  *     %n       exclusive-or all parameters with 0140 (Datamedia 2500)
6070e3d5408SPeter Wemm  *     %B       BCD (16*(value/10)) + (value%10), no output
6080e3d5408SPeter Wemm  *     %D       Reverse coding (value - 2*(value%16)), no output (Delta Data).
6090e3d5408SPeter Wemm  *     %m       exclusive-or all parameters with 0177 (not in 4.4BSD)
6100e3d5408SPeter Wemm  */
6110e3d5408SPeter Wemm 
612aae38d10SBaptiste Daroussin #define octal_fixup(n, c) fixups[n].ch = ((fixups[n].ch << 3) | ((c) - '0'))
613aae38d10SBaptiste Daroussin 
6147a69bbfbSPeter Wemm /*
6157a69bbfbSPeter Wemm  * Convert a terminfo string to termcap format.  Parameters are as in
6167a69bbfbSPeter Wemm  * _nc_captoinfo().
6177a69bbfbSPeter Wemm  */
6184a1a9510SRong-En Fan NCURSES_EXPORT(char *)
_nc_infotocap(const char * cap GCC_UNUSED,const char * str,int const parameterized)6194a1a9510SRong-En Fan _nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameterized)
6200e3d5408SPeter Wemm {
6210e3d5408SPeter Wemm     int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
6220e3d5408SPeter Wemm     const char *padding;
6230e3d5408SPeter Wemm     const char *trimmed = 0;
62406bfebdeSXin LI     int in0, in1, in2;
6250e3d5408SPeter Wemm     char ch1 = 0, ch2 = 0;
6260e3d5408SPeter Wemm     char *bufptr = init_string();
62773f0a83dSXin LI     char octal[4];
62815589c42SPeter Wemm     int len;
629aae38d10SBaptiste Daroussin     int digits;
63015589c42SPeter Wemm     bool syntax_error = FALSE;
631aae38d10SBaptiste Daroussin     int myfix = 0;
632aae38d10SBaptiste Daroussin     struct {
633aae38d10SBaptiste Daroussin 	int ch;
634aae38d10SBaptiste Daroussin 	int offset;
635aae38d10SBaptiste Daroussin     } fixups[MAX_TC_FIXUPS];
636aae38d10SBaptiste Daroussin 
637*21817992SBaptiste Daroussin     DEBUG_THIS(("_nc_infotocap %s params %d, %s",
638*21817992SBaptiste Daroussin 		_nc_strict_bsd ? "strict" : "loose",
639*21817992SBaptiste Daroussin 		parameterized,
640*21817992SBaptiste Daroussin 		_nc_visbuf(str)));
6410e3d5408SPeter Wemm 
6420e3d5408SPeter Wemm     /* we may have to move some trailing mandatory padding up front */
6430e3d5408SPeter Wemm     padding = str + strlen(str) - 1;
64473f0a83dSXin LI     if (padding > str && *padding == '>') {
6457a656419SBaptiste Daroussin 	if (padding > (str + 1) && *--padding == '/')
6460e3d5408SPeter Wemm 	    --padding;
64739f2269fSPeter Wemm 	while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
6480e3d5408SPeter Wemm 	    padding--;
6494a1a9510SRong-En Fan 	if (padding > str && *padding == '<' && *--padding == '$')
6500e3d5408SPeter Wemm 	    trimmed = padding;
6510e3d5408SPeter Wemm 	padding += 2;
6520e3d5408SPeter Wemm 
65339f2269fSPeter Wemm 	while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
6540e3d5408SPeter Wemm 	    bufptr = save_char(bufptr, *padding++);
6550e3d5408SPeter Wemm     }
6560e3d5408SPeter Wemm 
657aae38d10SBaptiste Daroussin     for (; !syntax_error &&
658aae38d10SBaptiste Daroussin 	 *str &&
659aae38d10SBaptiste Daroussin 	 ((trimmed == 0) || (str < trimmed)); str++) {
6600e3d5408SPeter Wemm 	int c1, c2;
6610e3d5408SPeter Wemm 	char *cp = 0;
6620e3d5408SPeter Wemm 
66306bfebdeSXin LI 	if (str[0] == '^') {
66406bfebdeSXin LI 	    if (str[1] == '\0' || (str + 1) == trimmed) {
66506bfebdeSXin LI 		bufptr = save_string(bufptr, "\\136");
66606bfebdeSXin LI 		++str;
667aae38d10SBaptiste Daroussin 	    } else if (str[1] == '?') {
668aae38d10SBaptiste Daroussin 		/*
669aae38d10SBaptiste Daroussin 		 * Although the 4.3BSD termcap file has an instance of "kb=^?",
670aae38d10SBaptiste Daroussin 		 * that appears to be just cut/paste since neither 4.3BSD nor
671aae38d10SBaptiste Daroussin 		 * 4.4BSD termcap interprets "^?" as DEL.
672aae38d10SBaptiste Daroussin 		 */
673aae38d10SBaptiste Daroussin 		bufptr = save_string(bufptr, "\\177");
674aae38d10SBaptiste Daroussin 		++str;
67506bfebdeSXin LI 	    } else {
67606bfebdeSXin LI 		bufptr = save_char(bufptr, *str++);
67706bfebdeSXin LI 		bufptr = save_char(bufptr, *str);
67806bfebdeSXin LI 	    }
679*21817992SBaptiste Daroussin 	} else if (str[0] == ':') {
680*21817992SBaptiste Daroussin 	    bufptr = save_char(bufptr, '\\');
681*21817992SBaptiste Daroussin 	    bufptr = save_char(bufptr, '0');
682*21817992SBaptiste Daroussin 	    bufptr = save_char(bufptr, '7');
683*21817992SBaptiste Daroussin 	    bufptr = save_char(bufptr, '2');
68406bfebdeSXin LI 	} else if (str[0] == '\\') {
68506bfebdeSXin LI 	    if (str[1] == '\0' || (str + 1) == trimmed) {
68606bfebdeSXin LI 		bufptr = save_string(bufptr, "\\134");
68706bfebdeSXin LI 		++str;
68806bfebdeSXin LI 	    } else if (str[1] == '^') {
68906bfebdeSXin LI 		bufptr = save_string(bufptr, "\\136");
69006bfebdeSXin LI 		++str;
69106bfebdeSXin LI 	    } else if (str[1] == ',') {
6920e3d5408SPeter Wemm 		bufptr = save_char(bufptr, *++str);
69306bfebdeSXin LI 	    } else {
694aae38d10SBaptiste Daroussin 		int xx1;
69573f0a83dSXin LI 
69606bfebdeSXin LI 		bufptr = save_char(bufptr, *str++);
69773f0a83dSXin LI 		xx1 = *str;
69873f0a83dSXin LI 		if (_nc_strict_bsd) {
69973f0a83dSXin LI 
700aae38d10SBaptiste Daroussin 		    if (isoctal(UChar(xx1))) {
701aae38d10SBaptiste Daroussin 			int pad = 0;
702aae38d10SBaptiste Daroussin 			int xx2;
703aae38d10SBaptiste Daroussin 			int fix = 0;
704aae38d10SBaptiste Daroussin 
705aae38d10SBaptiste Daroussin 			if (!isoctal(UChar(str[1])))
70673f0a83dSXin LI 			    pad = 2;
707aae38d10SBaptiste Daroussin 			else if (str[1] && !isoctal(UChar(str[2])))
70873f0a83dSXin LI 			    pad = 1;
70973f0a83dSXin LI 
71073f0a83dSXin LI 			/*
71173f0a83dSXin LI 			 * Test for "\0", "\00" or "\000" and transform those
71273f0a83dSXin LI 			 * into "\200".
71373f0a83dSXin LI 			 */
71473f0a83dSXin LI 			if (xx1 == '0'
71573f0a83dSXin LI 			    && ((pad == 2) || (str[1] == '0'))
71673f0a83dSXin LI 			    && ((pad >= 1) || (str[2] == '0'))) {
71773f0a83dSXin LI 			    xx2 = '2';
71873f0a83dSXin LI 			} else {
71973f0a83dSXin LI 			    xx2 = '0';
72073f0a83dSXin LI 			    pad = 0;	/* FIXME - optionally pad to 3 digits */
72173f0a83dSXin LI 			}
722aae38d10SBaptiste Daroussin 			if (myfix < MAX_TC_FIXUPS) {
723aae38d10SBaptiste Daroussin 			    fix = 3 - pad;
724aae38d10SBaptiste Daroussin 			    fixups[myfix].ch = 0;
725aae38d10SBaptiste Daroussin 			    fixups[myfix].offset = (int) (bufptr
726aae38d10SBaptiste Daroussin 							  - my_string
727aae38d10SBaptiste Daroussin 							  - 1);
728aae38d10SBaptiste Daroussin 			}
72973f0a83dSXin LI 			while (pad-- > 0) {
73073f0a83dSXin LI 			    bufptr = save_char(bufptr, xx2);
731aae38d10SBaptiste Daroussin 			    if (myfix < MAX_TC_FIXUPS) {
732aae38d10SBaptiste Daroussin 				fixups[myfix].ch <<= 3;
733aae38d10SBaptiste Daroussin 				fixups[myfix].ch |= (xx2 - '0');
734aae38d10SBaptiste Daroussin 			    }
73573f0a83dSXin LI 			    xx2 = '0';
73673f0a83dSXin LI 			}
737aae38d10SBaptiste Daroussin 			if (myfix < MAX_TC_FIXUPS) {
738aae38d10SBaptiste Daroussin 			    int n;
739aae38d10SBaptiste Daroussin 			    for (n = 0; n < fix; ++n) {
740aae38d10SBaptiste Daroussin 				fixups[myfix].ch <<= 3;
741aae38d10SBaptiste Daroussin 				fixups[myfix].ch |= (str[n] - '0');
742aae38d10SBaptiste Daroussin 			    }
743aae38d10SBaptiste Daroussin 			    if (fixups[myfix].ch < 32) {
744aae38d10SBaptiste Daroussin 				++myfix;
745aae38d10SBaptiste Daroussin 			    }
746aae38d10SBaptiste Daroussin 			}
74773f0a83dSXin LI 		    } else if (strchr("E\\nrtbf", xx1) == 0) {
74873f0a83dSXin LI 			switch (xx1) {
74973f0a83dSXin LI 			case 'e':
75073f0a83dSXin LI 			    xx1 = 'E';
75173f0a83dSXin LI 			    break;
75273f0a83dSXin LI 			case 'l':
75373f0a83dSXin LI 			    xx1 = 'n';
75473f0a83dSXin LI 			    break;
75573f0a83dSXin LI 			case 's':
75673f0a83dSXin LI 			    bufptr = save_char(bufptr, '0');
75773f0a83dSXin LI 			    bufptr = save_char(bufptr, '4');
75873f0a83dSXin LI 			    xx1 = '0';
75973f0a83dSXin LI 			    break;
76073f0a83dSXin LI 			case ':':
76173f0a83dSXin LI 			    /*
76273f0a83dSXin LI 			     * Note: termcap documentation claims that ":"
76373f0a83dSXin LI 			     * must be escaped as "\072", however the
76473f0a83dSXin LI 			     * documentation is incorrect - read the code.
76573f0a83dSXin LI 			     * The replacement does not work reliably,
76673f0a83dSXin LI 			     * so the advice is not helpful.
76773f0a83dSXin LI 			     */
76873f0a83dSXin LI 			    bufptr = save_char(bufptr, '0');
76973f0a83dSXin LI 			    bufptr = save_char(bufptr, '7');
77073f0a83dSXin LI 			    xx1 = '2';
77173f0a83dSXin LI 			    break;
77273f0a83dSXin LI 			default:
77373f0a83dSXin LI 			    /* should not happen, but handle this anyway */
77473f0a83dSXin LI 			    _nc_SPRINTF(octal, _nc_SLIMIT(sizeof(octal))
77573f0a83dSXin LI 					"%03o", UChar(xx1));
77673f0a83dSXin LI 			    bufptr = save_char(bufptr, octal[0]);
77773f0a83dSXin LI 			    bufptr = save_char(bufptr, octal[1]);
77873f0a83dSXin LI 			    xx1 = octal[2];
77973f0a83dSXin LI 			    break;
78073f0a83dSXin LI 			}
78173f0a83dSXin LI 		    }
782aae38d10SBaptiste Daroussin 		} else {
783aae38d10SBaptiste Daroussin 		    if (myfix < MAX_TC_FIXUPS && isoctal(UChar(xx1))) {
784aae38d10SBaptiste Daroussin 			bool will_fix = TRUE;
785aae38d10SBaptiste Daroussin 			int n;
786aae38d10SBaptiste Daroussin 
787aae38d10SBaptiste Daroussin 			fixups[myfix].ch = 0;
788aae38d10SBaptiste Daroussin 			fixups[myfix].offset = (int) (bufptr - my_string - 1);
789aae38d10SBaptiste Daroussin 			for (n = 0; n < 3; ++n) {
790aae38d10SBaptiste Daroussin 			    if (isoctal(str[n])) {
791aae38d10SBaptiste Daroussin 				octal_fixup(myfix, str[n]);
792aae38d10SBaptiste Daroussin 			    } else {
793aae38d10SBaptiste Daroussin 				will_fix = FALSE;
794aae38d10SBaptiste Daroussin 				break;
795aae38d10SBaptiste Daroussin 			    }
796aae38d10SBaptiste Daroussin 			}
797aae38d10SBaptiste Daroussin 			if (will_fix && (fixups[myfix].ch < 32))
798aae38d10SBaptiste Daroussin 			    ++myfix;
799aae38d10SBaptiste Daroussin 		    }
80073f0a83dSXin LI 		}
80173f0a83dSXin LI 		bufptr = save_char(bufptr, xx1);
80206bfebdeSXin LI 	    }
80315589c42SPeter Wemm 	} else if (str[0] == '$' && str[1] == '<') {	/* discard padding */
8040e3d5408SPeter Wemm 	    str += 2;
80539f2269fSPeter Wemm 	    while (isdigit(UChar(*str))
8067a69bbfbSPeter Wemm 		   || *str == '.'
8077a69bbfbSPeter Wemm 		   || *str == '*'
8087a69bbfbSPeter Wemm 		   || *str == '/'
8097a69bbfbSPeter Wemm 		   || *str == '>')
8100e3d5408SPeter Wemm 		str++;
8110e3d5408SPeter Wemm 	    --str;
81206bfebdeSXin LI 	} else if (sscanf(str,
81306bfebdeSXin LI 			  "[%%?%%p1%%{8}%%<%%t%d%%p1%%d%%e%%p1%%{16}%%<%%t%d%%p1%%{8}%%-%%d%%e%d;5;%%p1%%d%%;m",
81406bfebdeSXin LI 			  &in0, &in1, &in2) == 3
81506bfebdeSXin LI 		   && ((in0 == 4 && in1 == 10 && in2 == 48)
81606bfebdeSXin LI 		       || (in0 == 3 && in1 == 9 && in2 == 38))) {
81706bfebdeSXin LI 	    /* dumb-down an optimized case from xterm-256color for termcap */
81873f0a83dSXin LI 	    if ((str = strstr(str, ";m")) == 0)
81973f0a83dSXin LI 		break;		/* cannot happen */
82006bfebdeSXin LI 	    ++str;
82106bfebdeSXin LI 	    if (in2 == 48) {
82206bfebdeSXin LI 		bufptr = save_string(bufptr, "[48;5;%dm");
82306bfebdeSXin LI 	    } else {
82406bfebdeSXin LI 		bufptr = save_string(bufptr, "[38;5;%dm");
82506bfebdeSXin LI 	    }
82615589c42SPeter Wemm 	} else if (str[0] == '%' && str[1] == '%') {	/* escaped '%' */
82715589c42SPeter Wemm 	    bufptr = save_string(bufptr, "%%");
8284a1a9510SRong-En Fan 	    ++str;
8294a1a9510SRong-En Fan 	} else if (*str != '%' || (parameterized < 1)) {
8300e3d5408SPeter Wemm 	    bufptr = save_char(bufptr, *str);
83115589c42SPeter Wemm 	} else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) {
8320e3d5408SPeter Wemm 	    str = strchr(str, ';');
83315589c42SPeter Wemm 	    bufptr = save_tc_inequality(bufptr, c1, c2);
83415589c42SPeter Wemm 	} else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) {
8350e3d5408SPeter Wemm 	    str = strchr(str, ';');
83673f0a83dSXin LI 	    bufptr = save_tc_inequality(bufptr, c1, ch2);
83715589c42SPeter Wemm 	} else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) {
8380e3d5408SPeter Wemm 	    str = strchr(str, ';');
83973f0a83dSXin LI 	    bufptr = save_tc_inequality(bufptr, ch1, c2);
84015589c42SPeter Wemm 	} else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) {
8410e3d5408SPeter Wemm 	    str = strchr(str, ';');
84273f0a83dSXin LI 	    bufptr = save_tc_inequality(bufptr, ch1, ch2);
84315589c42SPeter Wemm 	} else if ((len = bcd_expression(str)) != 0) {
84415589c42SPeter Wemm 	    str += len;
84515589c42SPeter Wemm 	    bufptr = save_string(bufptr, "%B");
846aae38d10SBaptiste Daroussin 	} else if ((sscanf(str, "%%{%d}%%+%%%c", &c1, &ch2) == 2
847aae38d10SBaptiste Daroussin 		    || sscanf(str, "%%'%c'%%+%%%c", &ch1, &ch2) == 2)
848aae38d10SBaptiste Daroussin 		   && ch2 == 'c'
84915589c42SPeter Wemm 		   && (cp = strchr(str, '+'))) {
8500e3d5408SPeter Wemm 	    str = cp + 2;
85115589c42SPeter Wemm 	    bufptr = save_string(bufptr, "%+");
8520e3d5408SPeter Wemm 
8530e3d5408SPeter Wemm 	    if (ch1)
8540e3d5408SPeter Wemm 		c1 = ch1;
85515589c42SPeter Wemm 	    bufptr = save_tc_char(bufptr, c1);
8560e3d5408SPeter Wemm 	}
85715589c42SPeter Wemm 	/* FIXME: this "works" for 'delta' */
85873f0a83dSXin LI 	else if (strncmp(str, "%{2}%*%-", (size_t) 8) == 0) {
8590e3d5408SPeter Wemm 	    str += 7;
86015589c42SPeter Wemm 	    bufptr = save_string(bufptr, "%D");
86173f0a83dSXin LI 	} else if (strncmp(str, "%{96}%^", (size_t) 7) == 0) {
8620e3d5408SPeter Wemm 	    str += 6;
86315589c42SPeter Wemm 	    if (saw_m++ == 0) {
86415589c42SPeter Wemm 		bufptr = save_string(bufptr, "%n");
8650e3d5408SPeter Wemm 	    }
86673f0a83dSXin LI 	} else if (strncmp(str, "%{127}%^", (size_t) 8) == 0) {
8670e3d5408SPeter Wemm 	    str += 7;
86815589c42SPeter Wemm 	    if (saw_n++ == 0) {
86915589c42SPeter Wemm 		bufptr = save_string(bufptr, "%m");
8700e3d5408SPeter Wemm 	    }
87115589c42SPeter Wemm 	} else {		/* cm-style format element */
8720e3d5408SPeter Wemm 	    str++;
8730e3d5408SPeter Wemm 	    switch (*str) {
8740e3d5408SPeter Wemm 	    case '%':
8750e3d5408SPeter Wemm 		bufptr = save_char(bufptr, '%');
8760e3d5408SPeter Wemm 		break;
8770e3d5408SPeter Wemm 
8780e3d5408SPeter Wemm 	    case '0':
8790e3d5408SPeter Wemm 	    case '1':
8800e3d5408SPeter Wemm 	    case '2':
8810e3d5408SPeter Wemm 	    case '3':
8820e3d5408SPeter Wemm 	    case '4':
8830e3d5408SPeter Wemm 	    case '5':
8840e3d5408SPeter Wemm 	    case '6':
8850e3d5408SPeter Wemm 	    case '7':
8860e3d5408SPeter Wemm 	    case '8':
8870e3d5408SPeter Wemm 	    case '9':
8880e3d5408SPeter Wemm 		bufptr = save_char(bufptr, '%');
88973f0a83dSXin LI 		ch1 = 0;
89073f0a83dSXin LI 		ch2 = 0;
891aae38d10SBaptiste Daroussin 		digits = 0;
89273f0a83dSXin LI 		while (isdigit(UChar(*str))) {
893aae38d10SBaptiste Daroussin 		    if (++digits > 2) {
894aae38d10SBaptiste Daroussin 			syntax_error = TRUE;
895aae38d10SBaptiste Daroussin 			break;
896aae38d10SBaptiste Daroussin 		    }
89773f0a83dSXin LI 		    ch2 = ch1;
89873f0a83dSXin LI 		    ch1 = *str++;
899aae38d10SBaptiste Daroussin 		    if (digits == 2 && ch2 != '0') {
900aae38d10SBaptiste Daroussin 			syntax_error = TRUE;
901aae38d10SBaptiste Daroussin 			break;
902aae38d10SBaptiste Daroussin 		    } else if (_nc_strict_bsd) {
903aae38d10SBaptiste Daroussin 			if (ch1 > '3') {
904aae38d10SBaptiste Daroussin 			    syntax_error = TRUE;
905aae38d10SBaptiste Daroussin 			    break;
906aae38d10SBaptiste Daroussin 			}
90773f0a83dSXin LI 		    } else {
90873f0a83dSXin LI 			bufptr = save_char(bufptr, ch1);
90973f0a83dSXin LI 		    }
91073f0a83dSXin LI 		}
911aae38d10SBaptiste Daroussin 		if (syntax_error)
912aae38d10SBaptiste Daroussin 		    break;
913aae38d10SBaptiste Daroussin 		/*
914aae38d10SBaptiste Daroussin 		 * Convert %02 to %2 and %03 to %3
915aae38d10SBaptiste Daroussin 		 */
916aae38d10SBaptiste Daroussin 		if (ch2 == '0' && !_nc_strict_bsd) {
917aae38d10SBaptiste Daroussin 		    ch2 = 0;
918aae38d10SBaptiste Daroussin 		    bufptr[-2] = bufptr[-1];
919aae38d10SBaptiste Daroussin 		    *--bufptr = 0;
920aae38d10SBaptiste Daroussin 		}
92173f0a83dSXin LI 		if (_nc_strict_bsd) {
922aae38d10SBaptiste Daroussin 		    if (ch2 != 0 && ch2 != '0') {
923aae38d10SBaptiste Daroussin 			syntax_error = TRUE;
924aae38d10SBaptiste Daroussin 		    } else if (ch1 < '2') {
92573f0a83dSXin LI 			ch1 = 'd';
926aae38d10SBaptiste Daroussin 		    }
92773f0a83dSXin LI 		    bufptr = save_char(bufptr, ch1);
92873f0a83dSXin LI 		}
929aae38d10SBaptiste Daroussin 		if (strchr("oxX.", *str)) {
930aae38d10SBaptiste Daroussin 		    syntax_error = TRUE;	/* termcap doesn't have octal, hex */
93115589c42SPeter Wemm 		}
9320e3d5408SPeter Wemm 		break;
9330e3d5408SPeter Wemm 
9340e3d5408SPeter Wemm 	    case 'd':
93515589c42SPeter Wemm 		bufptr = save_string(bufptr, "%d");
9360e3d5408SPeter Wemm 		break;
9370e3d5408SPeter Wemm 
9380e3d5408SPeter Wemm 	    case 'c':
93915589c42SPeter Wemm 		bufptr = save_string(bufptr, "%.");
9400e3d5408SPeter Wemm 		break;
9410e3d5408SPeter Wemm 
9420e3d5408SPeter Wemm 		/*
943*21817992SBaptiste Daroussin 		 * %s isn't in termcap, but it is convenient to pass it through
9440e3d5408SPeter Wemm 		 * so we can represent things like terminfo pfkey strings in
9450e3d5408SPeter Wemm 		 * termcap notation.
9460e3d5408SPeter Wemm 		 */
9470e3d5408SPeter Wemm 	    case 's':
948aae38d10SBaptiste Daroussin 		if (_nc_strict_bsd) {
949aae38d10SBaptiste Daroussin 		    syntax_error = TRUE;
950aae38d10SBaptiste Daroussin 		} else {
95115589c42SPeter Wemm 		    bufptr = save_string(bufptr, "%s");
952aae38d10SBaptiste Daroussin 		}
9530e3d5408SPeter Wemm 		break;
9540e3d5408SPeter Wemm 
9550e3d5408SPeter Wemm 	    case 'p':
9560e3d5408SPeter Wemm 		str++;
9570e3d5408SPeter Wemm 		if (*str == '1')
9580e3d5408SPeter Wemm 		    seenone = 1;
95915589c42SPeter Wemm 		else if (*str == '2') {
96015589c42SPeter Wemm 		    if (!seenone && !seentwo) {
96115589c42SPeter Wemm 			bufptr = save_string(bufptr, "%r");
9620e3d5408SPeter Wemm 			seentwo++;
9630e3d5408SPeter Wemm 		    }
964aae38d10SBaptiste Daroussin 		} else if (*str >= '3') {
965aae38d10SBaptiste Daroussin 		    syntax_error = TRUE;
966aae38d10SBaptiste Daroussin 		}
9670e3d5408SPeter Wemm 		break;
9680e3d5408SPeter Wemm 
9690e3d5408SPeter Wemm 	    case 'i':
97015589c42SPeter Wemm 		bufptr = save_string(bufptr, "%i");
9710e3d5408SPeter Wemm 		break;
9720e3d5408SPeter Wemm 
9730e3d5408SPeter Wemm 	    default:
97415589c42SPeter Wemm 		bufptr = save_char(bufptr, *str);
97515589c42SPeter Wemm 		syntax_error = TRUE;
97615589c42SPeter Wemm 		break;
9770e3d5408SPeter Wemm 	    }			/* endswitch (*str) */
9780e3d5408SPeter Wemm 	}			/* endelse (*str == '%') */
9790e3d5408SPeter Wemm 
9805d08fb1fSRong-En Fan 	/*
9815d08fb1fSRong-En Fan 	 * 'str' always points to the end of what was scanned in this step,
9825d08fb1fSRong-En Fan 	 * but that may not be the end of the string.
9835d08fb1fSRong-En Fan 	 */
9845d08fb1fSRong-En Fan 	assert(str != 0);
98573f0a83dSXin LI 	if (str == 0 || *str == '\0')
9860e3d5408SPeter Wemm 	    break;
9870e3d5408SPeter Wemm 
9880e3d5408SPeter Wemm     }				/* endwhile (*str) */
9890e3d5408SPeter Wemm 
990aae38d10SBaptiste Daroussin     if (!syntax_error &&
991aae38d10SBaptiste Daroussin 	myfix > 0 &&
992aae38d10SBaptiste Daroussin 	((int) strlen(my_string) - (4 * myfix)) < MIN_TC_FIXUPS) {
993aae38d10SBaptiste Daroussin 	while (--myfix >= 0) {
994aae38d10SBaptiste Daroussin 	    char *p = fixups[myfix].offset + my_string;
995aae38d10SBaptiste Daroussin 	    *p++ = '^';
996aae38d10SBaptiste Daroussin 	    *p++ = (char) (fixups[myfix].ch | '@');
997aae38d10SBaptiste Daroussin 	    while ((p[0] = p[2]) != '\0') {
998aae38d10SBaptiste Daroussin 		++p;
999aae38d10SBaptiste Daroussin 	    }
1000aae38d10SBaptiste Daroussin 	}
1001aae38d10SBaptiste Daroussin     }
1002aae38d10SBaptiste Daroussin 
1003aae38d10SBaptiste Daroussin     DEBUG_THIS(("... _nc_infotocap %s",
1004aae38d10SBaptiste Daroussin 		syntax_error
1005aae38d10SBaptiste Daroussin 		? "<ERR>"
1006aae38d10SBaptiste Daroussin 		: _nc_visbuf(my_string)));
1007aae38d10SBaptiste Daroussin 
100815589c42SPeter Wemm     return (syntax_error ? NULL : my_string);
10090e3d5408SPeter Wemm }
10100e3d5408SPeter Wemm 
10110e3d5408SPeter Wemm #ifdef MAIN
10120e3d5408SPeter Wemm 
10130e3d5408SPeter Wemm int curr_line;
10140e3d5408SPeter Wemm 
101515589c42SPeter Wemm int
main(int argc,char * argv[])101615589c42SPeter Wemm main(int argc, char *argv[])
10170e3d5408SPeter Wemm {
10180e3d5408SPeter Wemm     int c, tc = FALSE;
10190e3d5408SPeter Wemm 
10200e3d5408SPeter Wemm     while ((c = getopt(argc, argv, "c")) != EOF)
102115589c42SPeter Wemm 	switch (c) {
10220e3d5408SPeter Wemm 	case 'c':
10230e3d5408SPeter Wemm 	    tc = TRUE;
10240e3d5408SPeter Wemm 	    break;
10250e3d5408SPeter Wemm 	}
10260e3d5408SPeter Wemm 
10270e3d5408SPeter Wemm     curr_line = 0;
102815589c42SPeter Wemm     for (;;) {
10290e3d5408SPeter Wemm 	char buf[BUFSIZ];
10300e3d5408SPeter Wemm 
10310e3d5408SPeter Wemm 	++curr_line;
10320e3d5408SPeter Wemm 	if (fgets(buf, sizeof(buf), stdin) == 0)
10330e3d5408SPeter Wemm 	    break;
10340e3d5408SPeter Wemm 	buf[strlen(buf) - 1] = '\0';
10350e3d5408SPeter Wemm 	_nc_set_source(buf);
10360e3d5408SPeter Wemm 
103715589c42SPeter Wemm 	if (tc) {
10380e3d5408SPeter Wemm 	    char *cp = _nc_infotocap("to termcap", buf, 1);
10390e3d5408SPeter Wemm 
10400e3d5408SPeter Wemm 	    if (cp)
10410e3d5408SPeter Wemm 		(void) fputs(cp, stdout);
104215589c42SPeter Wemm 	} else
10430e3d5408SPeter Wemm 	    (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
10440e3d5408SPeter Wemm 	(void) putchar('\n');
10450e3d5408SPeter Wemm     }
10460e3d5408SPeter Wemm     return (0);
10470e3d5408SPeter Wemm }
10480e3d5408SPeter Wemm #endif /* MAIN */
10490e3d5408SPeter Wemm 
10504a1a9510SRong-En Fan #if NO_LEAKS
10514a1a9510SRong-En Fan NCURSES_EXPORT(void)
_nc_captoinfo_leaks(void)10524a1a9510SRong-En Fan _nc_captoinfo_leaks(void)
10534a1a9510SRong-En Fan {
10544a1a9510SRong-En Fan     if (my_string != 0) {
10554a1a9510SRong-En Fan 	FreeAndNull(my_string);
10564a1a9510SRong-En Fan     }
10574a1a9510SRong-En Fan     my_length = 0;
10584a1a9510SRong-En Fan }
10594a1a9510SRong-En Fan #endif
1060