150276Speter/****************************************************************************
2184989Srafan * Copyright (c) 1998-2006,2008 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32166124Srafan *     and: Thomas E. Dickey                        1996-on                 *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/*
3650276Speter *	captoinfo.c --- conversion between termcap and terminfo formats
3750276Speter *
3850276Speter *	The captoinfo() code was swiped from Ross Ridge's mytinfo package,
3950276Speter *	adapted to fit ncurses by Eric S. Raymond <esr@snark.thyrsus.com>.
4050276Speter *
4150276Speter *	There is just one entry point:
4250276Speter *
43166124Srafan *	char *_nc_captoinfo(n, s, parameterized)
4450276Speter *
4550276Speter *	Convert value s for termcap string capability named n into terminfo
4650276Speter *	format.
4750276Speter *
4850276Speter *	This code recognizes all the standard 4.4BSD %-escapes:
4950276Speter *
5050276Speter *	%%       output `%'
5150276Speter *	%d       output value as in printf %d
5250276Speter *	%2       output value as in printf %2d
5350276Speter *	%3       output value as in printf %3d
5450276Speter *	%.       output value as in printf %c
5550276Speter *	%+x      add x to value, then do %.
5650276Speter *	%>xy     if value > x then add y, no output
5750276Speter *	%r       reverse order of two parameters, no output
5850276Speter *	%i       increment by one, no output
5950276Speter *	%n       exclusive-or all parameters with 0140 (Datamedia 2500)
6050276Speter *	%B       BCD (16*(value/10)) + (value%10), no output
6150276Speter *	%D       Reverse coding (value - 2*(value%16)), no output (Delta Data).
6250276Speter *
6350276Speter *	Also, %02 and %03 are accepted as synonyms for %2 and %3.
6450276Speter *
6550276Speter *	Besides all the standard termcap escapes, this translator understands
6650276Speter *	the following extended escapes:
6750276Speter *
6850276Speter *	used by GNU Emacs termcap libraries
6950276Speter *		%a[+*-/=][cp]x	GNU arithmetic.
7050276Speter *		%m		xor the first two parameters by 0177
7150276Speter *		%b		backup to previous parameter
7250276Speter *		%f		skip this parameter
7350276Speter *
7450276Speter *	used by the University of Waterloo (MFCF) termcap libraries
7550276Speter *		%-x	 subtract parameter FROM char x and output it as a char
7650276Speter *		%ax	 add the character x to parameter
7750276Speter *
7850276Speter *	If #define WATERLOO is on, also enable these translations:
7950276Speter *
8050276Speter *		%sx	 subtract parameter FROM the character x
8150276Speter *
8250276Speter *	By default, this Waterloo translations are not compiled in, because
8350276Speter *	the Waterloo %s conflicts with the way terminfo uses %s in strings for
8450276Speter *	function programming.
8550276Speter *
8650276Speter *	Note the two definitions of %a: the GNU definition is translated if the
8750276Speter *	characters after the 'a' are valid for it, otherwise the UW definition
8850276Speter *	is translated.
8950276Speter */
9050276Speter
9150276Speter#include <curses.priv.h>
9250276Speter
9350276Speter#include <ctype.h>
9450276Speter#include <tic.h>
9550276Speter
96184989SrafanMODULE_ID("$Id: captoinfo.c,v 1.52 2008/08/16 19:24:51 tom Exp $")
9750276Speter
9850276Speter#define MAX_PUSHED	16	/* max # args we can push onto the stack */
9950276Speter
10050276Speterstatic int stack[MAX_PUSHED];	/* the stack */
10150276Speterstatic int stackptr;		/* the next empty place on the stack */
10250276Speterstatic int onstack;		/* the top of stack */
10350276Speterstatic int seenm;		/* seen a %m */
10450276Speterstatic int seenn;		/* seen a %n */
10550276Speterstatic int seenr;		/* seen a %r */
10650276Speterstatic int param;		/* current parameter */
10750276Speterstatic char *dp;		/* pointer to end of the converted string */
10850276Speter
10962449Speterstatic char *my_string;
11050276Speterstatic size_t my_length;
11150276Speter
11262449Speterstatic char *
11362449Speterinit_string(void)
11450276Speter/* initialize 'my_string', 'my_length' */
11550276Speter{
11662449Speter    if (my_string == 0)
11762449Speter	my_string = typeMalloc(char, my_length = 256);
11862449Speter    if (my_string == 0)
119166124Srafan	_nc_err_abort(MSG_NO_MEMORY);
12050276Speter
12162449Speter    *my_string = '\0';
12262449Speter    return my_string;
12350276Speter}
12450276Speter
12562449Speterstatic char *
12662449Spetersave_string(char *d, const char *const s)
12750276Speter{
12862449Speter    size_t have = (d - my_string);
12962449Speter    size_t need = have + strlen(s) + 2;
13062449Speter    if (need > my_length) {
13162449Speter	my_string = (char *) realloc(my_string, my_length = (need + need));
13262449Speter	if (my_string == 0)
133166124Srafan	    _nc_err_abort(MSG_NO_MEMORY);
13462449Speter	d = my_string + have;
13562449Speter    }
13662449Speter    (void) strcpy(d, s);
13762449Speter    return d + strlen(d);
13850276Speter}
13950276Speter
140166124Srafanstatic NCURSES_INLINE char *
141166124Srafansave_char(char *s, int c)
14250276Speter{
14362449Speter    static char temp[2];
144166124Srafan    temp[0] = (char) c;
14562449Speter    return save_string(s, temp);
14650276Speter}
14750276Speter
14862449Speterstatic void
14962449Speterpush(void)
15050276Speter/* push onstack on to the stack */
15150276Speter{
152184989Srafan    if (stackptr >= MAX_PUSHED)
15350276Speter	_nc_warning("string too complex to convert");
15450276Speter    else
15550276Speter	stack[stackptr++] = onstack;
15650276Speter}
15750276Speter
15862449Speterstatic void
15962449Speterpop(void)
16050276Speter/* pop the top of the stack into onstack */
16150276Speter{
16250276Speter    if (stackptr == 0) {
16350276Speter	if (onstack == 0)
16450276Speter	    _nc_warning("I'm confused");
16550276Speter	else
16650276Speter	    onstack = 0;
16762449Speter    } else
16850276Speter	onstack = stack[--stackptr];
16950276Speter    param++;
17050276Speter}
17150276Speter
17262449Speterstatic int
17362449Spetercvtchar(register const char *sp)
17450276Speter/* convert a character to a terminfo push */
17550276Speter{
17650276Speter    unsigned char c = 0;
17750276Speter    int len;
17850276Speter
17962449Speter    switch (*sp) {
18050276Speter    case '\\':
18162449Speter	switch (*++sp) {
18250276Speter	case '\'':
18350276Speter	case '$':
18450276Speter	case '\\':
18550276Speter	case '%':
186184989Srafan	    c = (unsigned char) (*sp);
18750276Speter	    len = 2;
18850276Speter	    break;
18950276Speter	case '\0':
19050276Speter	    c = '\\';
19150276Speter	    len = 1;
19250276Speter	    break;
19350276Speter	case '0':
19450276Speter	case '1':
19550276Speter	case '2':
19650276Speter	case '3':
19750276Speter	    len = 1;
19897049Speter	    while (isdigit(UChar(*sp))) {
19950276Speter		c = 8 * c + (*sp++ - '0');
20050276Speter		len++;
20150276Speter	    }
20250276Speter	    break;
20350276Speter	default:
204184989Srafan	    c = (unsigned char) (*sp);
20550276Speter	    len = 2;
20650276Speter	    break;
20750276Speter	}
20850276Speter	break;
20950276Speter    case '^':
21050276Speter	c = (*++sp & 0x1f);
21150276Speter	len = 2;
21250276Speter	break;
21350276Speter    default:
214184989Srafan	c = (unsigned char) (*sp);
21550276Speter	len = 1;
21650276Speter    }
21750276Speter    if (isgraph(c) && c != ',' && c != '\'' && c != '\\' && c != ':') {
21862449Speter	dp = save_string(dp, "%\'");
21962449Speter	dp = save_char(dp, c);
22062449Speter	dp = save_char(dp, '\'');
22150276Speter    } else {
22262449Speter	dp = save_string(dp, "%{");
22350276Speter	if (c > 99)
22462449Speter	    dp = save_char(dp, c / 100 + '0');
22550276Speter	if (c > 9)
22662449Speter	    dp = save_char(dp, ((int) (c / 10)) % 10 + '0');
22762449Speter	dp = save_char(dp, c % 10 + '0');
22862449Speter	dp = save_char(dp, '}');
22950276Speter    }
23050276Speter    return len;
23150276Speter}
23250276Speter
23362449Speterstatic void
23462449Spetergetparm(int parm, int n)
23550276Speter/* push n copies of param on the terminfo stack if not already there */
23650276Speter{
23762449Speter    if (seenr) {
23862449Speter	if (parm == 1)
23962449Speter	    parm = 2;
24062449Speter	else if (parm == 2)
24162449Speter	    parm = 1;
24262449Speter    }
24362449Speter    if (onstack == parm) {
24462449Speter	if (n > 1) {
24562449Speter	    _nc_warning("string may not be optimal");
24662449Speter	    dp = save_string(dp, "%Pa");
24762449Speter	    while (n--) {
24862449Speter		dp = save_string(dp, "%ga");
24962449Speter	    }
25050276Speter	}
25162449Speter	return;
25262449Speter    }
25362449Speter    if (onstack != 0)
25462449Speter	push();
25550276Speter
25662449Speter    onstack = parm;
25750276Speter
25862449Speter    while (n--) {
25962449Speter	dp = save_string(dp, "%p");
26062449Speter	dp = save_char(dp, '0' + parm);
26162449Speter    }
26250276Speter
26362449Speter    if (seenn && parm < 3) {
26462449Speter	dp = save_string(dp, "%{96}%^");
26562449Speter    }
26650276Speter
26762449Speter    if (seenm && parm < 3) {
26862449Speter	dp = save_string(dp, "%{127}%^");
26962449Speter    }
27050276Speter}
27150276Speter
27276726Speter/*
27376726Speter * Convert a termcap string to terminfo format.
27476726Speter * 'cap' is the relevant terminfo capability index.
27576726Speter * 's' is the string value of the capability.
276166124Srafan * 'parameterized' tells what type of translations to do:
27776726Speter *	% translations if 1
27876726Speter *	pad translations if >=0
27976726Speter */
280166124SrafanNCURSES_EXPORT(char *)
281166124Srafan_nc_captoinfo(const char *cap, const char *s, int const parameterized)
28250276Speter{
28350276Speter    const char *capstart;
28450276Speter
28550276Speter    stackptr = 0;
28650276Speter    onstack = 0;
28750276Speter    seenm = 0;
28850276Speter    seenn = 0;
28950276Speter    seenr = 0;
29050276Speter    param = 1;
29150276Speter
29262449Speter    dp = init_string();
29350276Speter
29450276Speter    /* skip the initial padding (if we haven't been told not to) */
29550276Speter    capstart = 0;
29650276Speter    if (s == 0)
29750276Speter	s = "";
298166124Srafan    if (parameterized >= 0 && isdigit(UChar(*s)))
29962449Speter	for (capstart = s;; s++)
30097049Speter	    if (!(isdigit(UChar(*s)) || *s == '*' || *s == '.'))
30150276Speter		break;
30250276Speter
30362449Speter    while (*s != '\0') {
30462449Speter	switch (*s) {
30550276Speter	case '%':
30650276Speter	    s++;
307166124Srafan	    if (parameterized < 1) {
30862449Speter		dp = save_char(dp, '%');
30950276Speter		break;
31050276Speter	    }
31162449Speter	    switch (*s++) {
31262449Speter	    case '%':
31362449Speter		dp = save_char(dp, '%');
31462449Speter		break;
31550276Speter	    case 'r':
31650276Speter		if (seenr++ == 1) {
31750276Speter		    _nc_warning("saw %%r twice in %s", cap);
31850276Speter		}
31950276Speter		break;
32050276Speter	    case 'm':
32150276Speter		if (seenm++ == 1) {
32250276Speter		    _nc_warning("saw %%m twice in %s", cap);
32350276Speter		}
32450276Speter		break;
32550276Speter	    case 'n':
32650276Speter		if (seenn++ == 1) {
32750276Speter		    _nc_warning("saw %%n twice in %s", cap);
32850276Speter		}
32950276Speter		break;
33062449Speter	    case 'i':
33162449Speter		dp = save_string(dp, "%i");
33262449Speter		break;
33350276Speter	    case '6':
33450276Speter	    case 'B':
33562449Speter		getparm(param, 1);
33662449Speter		dp = save_string(dp, "%{10}%/%{16}%*");
33762449Speter		getparm(param, 1);
33862449Speter		dp = save_string(dp, "%{10}%m%+");
33950276Speter		break;
34050276Speter	    case '8':
34150276Speter	    case 'D':
34250276Speter		getparm(param, 2);
34362449Speter		dp = save_string(dp, "%{2}%*%-");
34450276Speter		break;
34550276Speter	    case '>':
34650276Speter		getparm(param, 2);
34750276Speter		/* %?%{x}%>%t%{y}%+%; */
34862449Speter		dp = save_string(dp, "%?");
34950276Speter		s += cvtchar(s);
35062449Speter		dp = save_string(dp, "%>%t");
35150276Speter		s += cvtchar(s);
35262449Speter		dp = save_string(dp, "%+%;");
35350276Speter		break;
35450276Speter	    case 'a':
35550276Speter		if ((*s == '=' || *s == '+' || *s == '-'
35676726Speter		     || *s == '*' || *s == '/')
35750276Speter		    && (s[1] == 'p' || s[1] == 'c')
35850276Speter		    && s[2] != '\0') {
35950276Speter		    int l;
36050276Speter		    l = 2;
36150276Speter		    if (*s != '=')
36250276Speter			getparm(param, 1);
36350276Speter		    if (s[1] == 'p') {
36450276Speter			getparm(param + s[2] - '@', 1);
36550276Speter			if (param != onstack) {
36650276Speter			    pop();
36750276Speter			    param--;
36850276Speter			}
36950276Speter			l++;
37050276Speter		    } else
37150276Speter			l += cvtchar(s + 2);
37262449Speter		    switch (*s) {
37350276Speter		    case '+':
37462449Speter			dp = save_string(dp, "%+");
37550276Speter			break;
37650276Speter		    case '-':
37762449Speter			dp = save_string(dp, "%-");
37850276Speter			break;
37950276Speter		    case '*':
38062449Speter			dp = save_string(dp, "%*");
38150276Speter			break;
38250276Speter		    case '/':
38362449Speter			dp = save_string(dp, "%/");
38450276Speter			break;
38550276Speter		    case '=':
38650276Speter			if (seenr) {
38750276Speter			    if (param == 1)
38850276Speter				onstack = 2;
38950276Speter			    else if (param == 2)
39050276Speter				onstack = 1;
39150276Speter			    else
39250276Speter				onstack = param;
39362449Speter			} else
39450276Speter			    onstack = param;
39550276Speter			break;
39650276Speter		    }
39750276Speter		    s += l;
39850276Speter		    break;
39950276Speter		}
40050276Speter		getparm(param, 1);
40150276Speter		s += cvtchar(s);
40262449Speter		dp = save_string(dp, "%+");
40350276Speter		break;
40450276Speter	    case '+':
40550276Speter		getparm(param, 1);
40650276Speter		s += cvtchar(s);
40762449Speter		dp = save_string(dp, "%+%c");
40850276Speter		pop();
40950276Speter		break;
41050276Speter	    case 's':
41150276Speter#ifdef WATERLOO
41250276Speter		s += cvtchar(s);
41350276Speter		getparm(param, 1);
41462449Speter		dp = save_string(dp, "%-");
41550276Speter#else
41650276Speter		getparm(param, 1);
41762449Speter		dp = save_string(dp, "%s");
41850276Speter		pop();
41950276Speter#endif /* WATERLOO */
42050276Speter		break;
42150276Speter	    case '-':
42250276Speter		s += cvtchar(s);
42350276Speter		getparm(param, 1);
42462449Speter		dp = save_string(dp, "%-%c");
42550276Speter		pop();
42650276Speter		break;
42750276Speter	    case '.':
42850276Speter		getparm(param, 1);
42962449Speter		dp = save_string(dp, "%c");
43050276Speter		pop();
43150276Speter		break;
43262449Speter	    case '0':		/* not clear any of the historical termcaps did this */
43350276Speter		if (*s == '3')
43450276Speter		    goto see03;
43550276Speter		else if (*s != '2')
43650276Speter		    goto invalid;
43750276Speter		/* FALLTHRU */
43850276Speter	    case '2':
43950276Speter		getparm(param, 1);
44062449Speter		dp = save_string(dp, "%2d");
44150276Speter		pop();
44250276Speter		break;
44362449Speter	    case '3':
44462449Speter	      see03:
44550276Speter		getparm(param, 1);
44662449Speter		dp = save_string(dp, "%3d");
44750276Speter		pop();
44850276Speter		break;
44950276Speter	    case 'd':
45050276Speter		getparm(param, 1);
45162449Speter		dp = save_string(dp, "%d");
45250276Speter		pop();
45350276Speter		break;
45450276Speter	    case 'f':
45550276Speter		param++;
45650276Speter		break;
45750276Speter	    case 'b':
45850276Speter		param--;
45950276Speter		break;
46050276Speter	    case '\\':
46162449Speter		dp = save_string(dp, "%\\");
46250276Speter		break;
46362449Speter	    default:
46462449Speter	      invalid:
46562449Speter		dp = save_char(dp, '%');
46650276Speter		s--;
46762449Speter		_nc_warning("unknown %% code %s (%#x) in %s",
468166124Srafan			    unctrl((chtype) *s), UChar(*s), cap);
46950276Speter		break;
47050276Speter	    }
47150276Speter	    break;
47250276Speter#ifdef REVISIBILIZE
47350276Speter	case '\\':
47462449Speter	    dp = save_char(dp, *s++);
47562449Speter	    dp = save_char(dp, *s++);
47662449Speter	    break;
47750276Speter	case '\n':
47862449Speter	    dp = save_string(dp, "\\n");
47962449Speter	    s++;
48062449Speter	    break;
48150276Speter	case '\t':
48262449Speter	    dp = save_string(dp, "\\t");
48362449Speter	    s++;
48462449Speter	    break;
48550276Speter	case '\r':
48662449Speter	    dp = save_string(dp, "\\r");
48762449Speter	    s++;
48862449Speter	    break;
48950276Speter	case '\200':
49062449Speter	    dp = save_string(dp, "\\0");
49162449Speter	    s++;
49262449Speter	    break;
49350276Speter	case '\f':
49462449Speter	    dp = save_string(dp, "\\f");
49562449Speter	    s++;
49662449Speter	    break;
49750276Speter	case '\b':
49862449Speter	    dp = save_string(dp, "\\b");
49962449Speter	    s++;
50062449Speter	    break;
50150276Speter	case ' ':
50262449Speter	    dp = save_string(dp, "\\s");
50362449Speter	    s++;
50462449Speter	    break;
50550276Speter	case '^':
50662449Speter	    dp = save_string(dp, "\\^");
50762449Speter	    s++;
50862449Speter	    break;
50950276Speter	case ':':
51062449Speter	    dp = save_string(dp, "\\:");
51162449Speter	    s++;
51262449Speter	    break;
51350276Speter	case ',':
51462449Speter	    dp = save_string(dp, "\\,");
51562449Speter	    s++;
51662449Speter	    break;
51750276Speter	default:
51850276Speter	    if (*s == '\033') {
51962449Speter		dp = save_string(dp, "\\E");
52050276Speter		s++;
52150276Speter	    } else if (*s > 0 && *s < 32) {
52262449Speter		dp = save_char(dp, '^');
52362449Speter		dp = save_char(dp, *s + '@');
52450276Speter		s++;
52550276Speter	    } else if (*s <= 0 || *s >= 127) {
52662449Speter		dp = save_char(dp, '\\');
52762449Speter		dp = save_char(dp, ((*s & 0300) >> 6) + '0');
52862449Speter		dp = save_char(dp, ((*s & 0070) >> 3) + '0');
52962449Speter		dp = save_char(dp, (*s & 0007) + '0');
53050276Speter		s++;
53150276Speter	    } else
53262449Speter		dp = save_char(dp, *s++);
53350276Speter	    break;
53450276Speter#else
53550276Speter	default:
53662449Speter	    dp = save_char(dp, *s++);
53750276Speter	    break;
53850276Speter#endif
53950276Speter	}
54050276Speter    }
54150276Speter
54250276Speter    /*
54350276Speter     * Now, if we stripped off some leading padding, add it at the end
54450276Speter     * of the string as mandatory padding.
54550276Speter     */
54662449Speter    if (capstart) {
54762449Speter	dp = save_string(dp, "$<");
54862449Speter	for (s = capstart;; s++)
54997049Speter	    if (isdigit(UChar(*s)) || *s == '*' || *s == '.')
55062449Speter		dp = save_char(dp, *s);
55150276Speter	    else
55250276Speter		break;
55362449Speter	dp = save_string(dp, "/>");
55450276Speter    }
55550276Speter
55662449Speter    (void) save_char(dp, '\0');
55762449Speter    return (my_string);
55850276Speter}
55950276Speter
56050276Speter/*
56162449Speter * Check for an expression that corresponds to "%B" (BCD):
56262449Speter *	(parameter / 10) * 16 + (parameter % 10)
56362449Speter */
56462449Speterstatic int
56562449Speterbcd_expression(const char *str)
56662449Speter{
56762449Speter    /* leave this non-const for HPUX */
56862449Speter    static char fmt[] = "%%p%c%%{10}%%/%%{16}%%*%%p%c%%{10}%%m%%+";
56962449Speter    int len = 0;
57062449Speter    char ch1, ch2;
57162449Speter
57262449Speter    if (sscanf(str, fmt, &ch1, &ch2) == 2
57397049Speter	&& isdigit(UChar(ch1))
57497049Speter	&& isdigit(UChar(ch2))
57562449Speter	&& (ch1 == ch2)) {
57662449Speter	len = 28;
57762449Speter#ifndef NDEBUG
57862449Speter	{
57962449Speter	    char buffer[80];
58062449Speter	    int tst;
58162449Speter	    sprintf(buffer, fmt, ch1, ch2);
58262449Speter	    tst = strlen(buffer) - 1;
58362449Speter	    assert(len == tst);
58462449Speter	}
58562449Speter#endif
58662449Speter    }
58762449Speter    return len;
58862449Speter}
58962449Speter
59062449Speterstatic char *
59162449Spetersave_tc_char(char *bufptr, int c1)
59262449Speter{
59362449Speter    char temp[80];
59462449Speter
59562449Speter    if (is7bits(c1) && isprint(c1)) {
59662449Speter	if (c1 == ':' || c1 == '\\')
59762449Speter	    bufptr = save_char(bufptr, '\\');
59862449Speter	bufptr = save_char(bufptr, c1);
59962449Speter    } else {
60062449Speter	if (c1 == (c1 & 0x1f))	/* iscntrl() returns T on 255 */
60176726Speter	    (void) strcpy(temp, unctrl((chtype) c1));
60262449Speter	else
60362449Speter	    (void) sprintf(temp, "\\%03o", c1);
60462449Speter	bufptr = save_string(bufptr, temp);
60562449Speter    }
60662449Speter    return bufptr;
60762449Speter}
60862449Speter
60962449Speterstatic char *
61062449Spetersave_tc_inequality(char *bufptr, int c1, int c2)
61162449Speter{
61262449Speter    bufptr = save_string(bufptr, "%>");
61362449Speter    bufptr = save_tc_char(bufptr, c1);
61462449Speter    bufptr = save_tc_char(bufptr, c2);
61562449Speter    return bufptr;
61662449Speter}
61762449Speter
61862449Speter/*
61950276Speter * Here are the capabilities infotocap assumes it can translate to:
62050276Speter *
62150276Speter *     %%       output `%'
62250276Speter *     %d       output value as in printf %d
62350276Speter *     %2       output value as in printf %2d
62450276Speter *     %3       output value as in printf %3d
62550276Speter *     %.       output value as in printf %c
62650276Speter *     %+c      add character c to value, then do %.
62750276Speter *     %>xy     if value > x then add y, no output
62850276Speter *     %r       reverse order of two parameters, no output
62950276Speter *     %i       increment by one, no output
63050276Speter *     %n       exclusive-or all parameters with 0140 (Datamedia 2500)
63150276Speter *     %B       BCD (16*(value/10)) + (value%10), no output
63250276Speter *     %D       Reverse coding (value - 2*(value%16)), no output (Delta Data).
63350276Speter *     %m       exclusive-or all parameters with 0177 (not in 4.4BSD)
63450276Speter */
63550276Speter
63676726Speter/*
63776726Speter * Convert a terminfo string to termcap format.  Parameters are as in
63876726Speter * _nc_captoinfo().
63976726Speter */
640166124SrafanNCURSES_EXPORT(char *)
641166124Srafan_nc_infotocap(const char *cap GCC_UNUSED, const char *str, int const parameterized)
64250276Speter{
64362449Speter    int seenone = 0, seentwo = 0, saw_m = 0, saw_n = 0;
64450276Speter    const char *padding;
64550276Speter    const char *trimmed = 0;
64650276Speter    char ch1 = 0, ch2 = 0;
64750276Speter    char *bufptr = init_string();
64862449Speter    int len;
64962449Speter    bool syntax_error = FALSE;
65050276Speter
65150276Speter    /* we may have to move some trailing mandatory padding up front */
65250276Speter    padding = str + strlen(str) - 1;
653166124Srafan    if (padding > str && *padding == '>' && *--padding == '/') {
65450276Speter	--padding;
65597049Speter	while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
65650276Speter	    padding--;
657166124Srafan	if (padding > str && *padding == '<' && *--padding == '$')
65850276Speter	    trimmed = padding;
65950276Speter	padding += 2;
66050276Speter
66197049Speter	while (isdigit(UChar(*padding)) || *padding == '.' || *padding == '*')
66250276Speter	    bufptr = save_char(bufptr, *padding++);
66350276Speter    }
66450276Speter
66562449Speter    for (; *str && str != trimmed; str++) {
66662449Speter	int c1, c2;
66762449Speter	char *cp = 0;
66850276Speter
66962449Speter	if (str[0] == '\\' && (str[1] == '^' || str[1] == ',')) {
67050276Speter	    bufptr = save_char(bufptr, *++str);
67162449Speter	} else if (str[0] == '$' && str[1] == '<') {	/* discard padding */
67250276Speter	    str += 2;
67397049Speter	    while (isdigit(UChar(*str))
67476726Speter		   || *str == '.'
67576726Speter		   || *str == '*'
67676726Speter		   || *str == '/'
67776726Speter		   || *str == '>')
67850276Speter		str++;
67950276Speter	    --str;
68062449Speter	} else if (str[0] == '%' && str[1] == '%') {	/* escaped '%' */
68162449Speter	    bufptr = save_string(bufptr, "%%");
682166124Srafan	    ++str;
683166124Srafan	} else if (*str != '%' || (parameterized < 1)) {
68450276Speter	    bufptr = save_char(bufptr, *str);
68562449Speter	} else if (sscanf(str, "%%?%%{%d}%%>%%t%%{%d}%%+%%;", &c1, &c2) == 2) {
68650276Speter	    str = strchr(str, ';');
68762449Speter	    bufptr = save_tc_inequality(bufptr, c1, c2);
68862449Speter	} else if (sscanf(str, "%%?%%{%d}%%>%%t%%'%c'%%+%%;", &c1, &ch2) == 2) {
68950276Speter	    str = strchr(str, ';');
69062449Speter	    bufptr = save_tc_inequality(bufptr, c1, c2);
69162449Speter	} else if (sscanf(str, "%%?%%'%c'%%>%%t%%{%d}%%+%%;", &ch1, &c2) == 2) {
69250276Speter	    str = strchr(str, ';');
69362449Speter	    bufptr = save_tc_inequality(bufptr, c1, c2);
69462449Speter	} else if (sscanf(str, "%%?%%'%c'%%>%%t%%'%c'%%+%%;", &ch1, &ch2) == 2) {
69550276Speter	    str = strchr(str, ';');
69662449Speter	    bufptr = save_tc_inequality(bufptr, c1, c2);
69762449Speter	} else if ((len = bcd_expression(str)) != 0) {
69862449Speter	    str += len;
69962449Speter	    bufptr = save_string(bufptr, "%B");
70062449Speter	} else if ((sscanf(str, "%%{%d}%%+%%c", &c1) == 1
70162449Speter		    || sscanf(str, "%%'%c'%%+%%c", &ch1) == 1)
70276726Speter		   && (cp = strchr(str, '+'))) {
70350276Speter	    str = cp + 2;
70462449Speter	    bufptr = save_string(bufptr, "%+");
70550276Speter
70650276Speter	    if (ch1)
70750276Speter		c1 = ch1;
70862449Speter	    bufptr = save_tc_char(bufptr, c1);
70950276Speter	}
71062449Speter	/* FIXME: this "works" for 'delta' */
71162449Speter	else if (strncmp(str, "%{2}%*%-", 8) == 0) {
71250276Speter	    str += 7;
71362449Speter	    bufptr = save_string(bufptr, "%D");
71462449Speter	} else if (strncmp(str, "%{96}%^", 7) == 0) {
71550276Speter	    str += 6;
71662449Speter	    if (saw_m++ == 0) {
71762449Speter		bufptr = save_string(bufptr, "%n");
71850276Speter	    }
71962449Speter	} else if (strncmp(str, "%{127}%^", 8) == 0) {
72050276Speter	    str += 7;
72162449Speter	    if (saw_n++ == 0) {
72262449Speter		bufptr = save_string(bufptr, "%m");
72350276Speter	    }
72462449Speter	} else {		/* cm-style format element */
72550276Speter	    str++;
72650276Speter	    switch (*str) {
72750276Speter	    case '%':
72850276Speter		bufptr = save_char(bufptr, '%');
72950276Speter		break;
73050276Speter
73150276Speter	    case '0':
73250276Speter	    case '1':
73350276Speter	    case '2':
73450276Speter	    case '3':
73550276Speter	    case '4':
73650276Speter	    case '5':
73750276Speter	    case '6':
73850276Speter	    case '7':
73950276Speter	    case '8':
74050276Speter	    case '9':
74150276Speter		bufptr = save_char(bufptr, '%');
74297049Speter		while (isdigit(UChar(*str)))
74350276Speter		    bufptr = save_char(bufptr, *str++);
74462449Speter		if (strchr("doxX.", *str)) {
74562449Speter		    if (*str != 'd')	/* termcap doesn't have octal, hex */
74662449Speter			return 0;
74762449Speter		}
74850276Speter		break;
74950276Speter
75050276Speter	    case 'd':
75162449Speter		bufptr = save_string(bufptr, "%d");
75250276Speter		break;
75350276Speter
75450276Speter	    case 'c':
75562449Speter		bufptr = save_string(bufptr, "%.");
75650276Speter		break;
75750276Speter
75862449Speter		/*
75962449Speter		 * %s isn't in termcap, but it's convenient to pass it through
76062449Speter		 * so we can represent things like terminfo pfkey strings in
76162449Speter		 * termcap notation.
76262449Speter		 */
76350276Speter	    case 's':
76462449Speter		bufptr = save_string(bufptr, "%s");
76550276Speter		break;
76650276Speter
76750276Speter	    case 'p':
76850276Speter		str++;
76950276Speter		if (*str == '1')
77050276Speter		    seenone = 1;
77162449Speter		else if (*str == '2') {
77262449Speter		    if (!seenone && !seentwo) {
77362449Speter			bufptr = save_string(bufptr, "%r");
77450276Speter			seentwo++;
77550276Speter		    }
77662449Speter		} else if (*str >= '3')
77762449Speter		    return (0);
77850276Speter		break;
77950276Speter
78050276Speter	    case 'i':
78162449Speter		bufptr = save_string(bufptr, "%i");
78250276Speter		break;
78350276Speter
78450276Speter	    default:
78562449Speter		bufptr = save_char(bufptr, *str);
78662449Speter		syntax_error = TRUE;
78762449Speter		break;
78862449Speter	    }			/* endswitch (*str) */
78962449Speter	}			/* endelse (*str == '%') */
79050276Speter
791184989Srafan	/*
792184989Srafan	 * 'str' always points to the end of what was scanned in this step,
793184989Srafan	 * but that may not be the end of the string.
794184989Srafan	 */
795184989Srafan	assert(str != 0);
79650276Speter	if (*str == '\0')
79750276Speter	    break;
79850276Speter
79962449Speter    }				/* endwhile (*str) */
80050276Speter
80162449Speter    return (syntax_error ? NULL : my_string);
80250276Speter}
80350276Speter
80450276Speter#ifdef MAIN
80550276Speter
80650276Speterint curr_line;
80750276Speter
80862449Speterint
80962449Spetermain(int argc, char *argv[])
81050276Speter{
81150276Speter    int c, tc = FALSE;
81250276Speter
81350276Speter    while ((c = getopt(argc, argv, "c")) != EOF)
81462449Speter	switch (c) {
81550276Speter	case 'c':
81650276Speter	    tc = TRUE;
81750276Speter	    break;
81850276Speter	}
81950276Speter
82050276Speter    curr_line = 0;
82162449Speter    for (;;) {
82262449Speter	char buf[BUFSIZ];
82350276Speter
82450276Speter	++curr_line;
82550276Speter	if (fgets(buf, sizeof(buf), stdin) == 0)
82650276Speter	    break;
82750276Speter	buf[strlen(buf) - 1] = '\0';
82850276Speter	_nc_set_source(buf);
82950276Speter
83062449Speter	if (tc) {
83162449Speter	    char *cp = _nc_infotocap("to termcap", buf, 1);
83250276Speter
83350276Speter	    if (cp)
83450276Speter		(void) fputs(cp, stdout);
83562449Speter	} else
83650276Speter	    (void) fputs(_nc_captoinfo("to terminfo", buf, 1), stdout);
83750276Speter	(void) putchar('\n');
83850276Speter    }
83962449Speter    return (0);
84050276Speter}
84150276Speter#endif /* MAIN */
84250276Speter
843166124Srafan#if NO_LEAKS
844166124SrafanNCURSES_EXPORT(void)
845166124Srafan_nc_captoinfo_leaks(void)
846166124Srafan{
847166124Srafan    if (my_string != 0) {
848166124Srafan	FreeAndNull(my_string);
849166124Srafan    }
850166124Srafan    my_length = 0;
851166124Srafan}
852166124Srafan#endif
853