1 /*	$OpenBSD: cl_bsd.c,v 1.10 2009/10/27 23:59:47 deraadt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1995, 1996
5  *	Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9 
10 #include "config.h"
11 
12 #include <sys/types.h>
13 #include <sys/queue.h>
14 #include <sys/time.h>
15 
16 #include <bitstring.h>
17 #include <ctype.h>
18 #include <curses.h>
19 #include <signal.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <termios.h>
24 #include <unistd.h>
25 
26 #include "../common/common.h"
27 #include "../vi/vi.h"
28 #include "cl.h"
29 
30 #ifndef	HAVE_CURSES_SETUPTERM
31 static char	*ke;				/* Keypad on. */
32 static char	*ks;				/* Keypad off. */
33 static char	*vb;				/* Visible bell string. */
34 #endif
35 
36 /*
37  * HP's support the entire System V curses package except for the tigetstr
38  * and tigetnum functions.  Ultrix supports the BSD curses package except
39  * for the idlok function.  Cthulu only knows why.  Break things up into a
40  * minimal set of functions.
41  */
42 
43 #ifndef HAVE_CURSES_ADDNSTR
44 /*
45  * addnstr --
46  *
47  * PUBLIC: #ifndef HAVE_CURSES_ADDNSTR
48  * PUBLIC: int addnstr(char *, int);
49  * PUBLIC: #endif
50  */
51 int
addnstr(s,n)52 addnstr(s, n)
53 	char *s;
54 	int n;
55 {
56 	int ch;
57 
58 	while (n-- && (ch = *s++))
59 		addch(ch);
60 	return (OK);
61 }
62 #endif
63 
64 #ifndef	HAVE_CURSES_BEEP
65 /*
66  * beep --
67  *
68  * PUBLIC: #ifndef HAVE_CURSES_BEEP
69  * PUBLIC: void beep(void);
70  * PUBLIC: #endif
71  */
72 void
beep()73 beep()
74 {
75 	(void)write(1, "\007", 1);	/* '\a' */
76 }
77 #endif /* !HAVE_CURSES_BEEP */
78 
79 #ifndef	HAVE_CURSES_FLASH
80 /*
81  * flash --
82  *	Flash the screen.
83  *
84  * PUBLIC: #ifndef HAVE_CURSES_FLASH
85  * PUBLIC: void flash(void);
86  * PUBLIC: #endif
87  */
88 void
flash()89 flash()
90 {
91 	if (vb != NULL) {
92 		(void)tputs(vb, 1, cl_putchar);
93 		(void)fflush(stdout);
94 	} else
95 		beep();
96 }
97 #endif /* !HAVE_CURSES_FLASH */
98 
99 #ifndef	HAVE_CURSES_IDLOK
100 /*
101  * idlok --
102  *	Turn on/off hardware line insert/delete.
103  *
104  * PUBLIC: #ifndef HAVE_CURSES_IDLOK
105  * PUBLIC: void idlok(WINDOW *, int);
106  * PUBLIC: #endif
107  */
108 void
idlok(win,bf)109 idlok(win, bf)
110 	WINDOW *win;
111 	int bf;
112 {
113 	return;
114 }
115 #endif /* !HAVE_CURSES_IDLOK */
116 
117 #ifndef	HAVE_CURSES_KEYPAD
118 /*
119  * keypad --
120  *	Put the keypad/cursor arrows into or out of application mode.
121  *
122  * PUBLIC: #ifndef HAVE_CURSES_KEYPAD
123  * PUBLIC: int keypad(void *, int);
124  * PUBLIC: #endif
125  */
126 int
keypad(a,on)127 keypad(a, on)
128 	void *a;
129 	int on;
130 {
131 	char *p;
132 
133 	if ((p = tigetstr(on ? "smkx" : "rmkx")) != (char *)-1) {
134 		(void)tputs(p, 0, cl_putchar);
135 		(void)fflush(stdout);
136 	}
137 	return (0);
138 }
139 #endif /* !HAVE_CURSES_KEYPAD */
140 
141 #ifndef	HAVE_CURSES_NEWTERM
142 /*
143  * newterm --
144  *	Create a new curses screen.
145  *
146  * PUBLIC: #ifndef HAVE_CURSES_NEWTERM
147  * PUBLIC: void *newterm(const char *, FILE *, FILE *);
148  * PUBLIC: #endif
149  */
150 void *
newterm(a,b,c)151 newterm(a, b, c)
152 	const char *a;
153 	FILE *b, *c;
154 {
155 	return (initscr());
156 }
157 #endif /* !HAVE_CURSES_NEWTERM */
158 
159 #ifndef	HAVE_CURSES_SETUPTERM
160 /*
161  * setupterm --
162  *	Set up terminal.
163  *
164  * PUBLIC: #ifndef HAVE_CURSES_SETUPTERM
165  * PUBLIC: void setupterm(char *, int, int *);
166  * PUBLIC: #endif
167  */
168 void
setupterm(ttype,fno,errp)169 setupterm(ttype, fno, errp)
170 	char *ttype;
171 	int fno, *errp;
172 {
173 	static char buf[2048];
174 	char *p;
175 
176 	if ((*errp = tgetent(buf, ttype)) > 0) {
177 		if (ke != NULL)
178 			free(ke);
179 		ke = ((p = tigetstr("rmkx")) == (char *)-1) ?
180 		    NULL : strdup(p);
181 		if (ks != NULL)
182 			free(ks);
183 		ks = ((p = tigetstr("smkx")) == (char *)-1) ?
184 		    NULL : strdup(p);
185 		if (vb != NULL)
186 			free(vb);
187 		vb = ((p = tigetstr("flash")) == (char *)-1) ?
188 		    NULL : strdup(p);
189 	}
190 }
191 #endif /* !HAVE_CURSES_SETUPTERM */
192 
193 #ifndef	HAVE_CURSES_TIGETSTR
194 /* Terminfo-to-termcap translation table. */
195 typedef struct _tl {
196 	char *terminfo;			/* Terminfo name. */
197 	char *termcap;			/* Termcap name. */
198 } TL;
199 static const TL list[] = {
200 	"cols",		"co",		/* Terminal columns. */
201 	"cup",		"cm",		/* Cursor up. */
202 	"cuu1",		"up",		/* Cursor up. */
203 	"el",		"ce",		/* Clear to end-of-line. */
204 	"flash",	"vb",		/* Visible bell. */
205 	"kcub1",  	"kl",		/* Cursor left. */
206 	"kcud1",	"kd",		/* Cursor down. */
207 	"kcuf1",	"kr",		/* Cursor right. */
208 	"kcuu1",  	"ku",		/* Cursor up. */
209 	"kdch1",	"kD",		/* Delete character. */
210 	"kdl1",		"kL",		/* Delete line. */
211 	"ked",		"kS",		/* Delete to end of screen. */
212 	"kel",		"kE",		/* Delete to eol. */
213 	"khome",	"kh",		/* Go to sol. */
214 	"kich1",	"kI",		/* Insert at cursor. */
215 	"kil1",		"kA",		/* Insert line. */
216 	"kind",		"kF",		/* Scroll down. */
217 	"kll",		"kH",		/* Go to eol. */
218 	"knp",		"kN",		/* Page down. */
219 	"kpp",		"kP",		/* Page up. */
220 	"kri",		"kR",		/* Scroll up. */
221 	"lines",	"li",		/* Terminal lines. */
222 	"rmcup",	"te",		/* Terminal end string. */
223 	"rmkx",		"ke",		/* Exit "keypad-transmit" mode. */
224 	"rmso",		"se",		/* Standout end. */
225 	"smcup",	"ti",		/* Terminal initialization string. */
226 	"smkx",		"ks",		/* Enter "keypad-transmit" mode. */
227 	"smso",		"so",		/* Standout begin. */
228 };
229 
230 #ifdef _AIX
231 /*
232  * AIX's implementation for function keys greater than 10 is different and
233  * only goes as far as 36.
234  */
235 static const char codes[] = {
236 /*  0-10 */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';',
237 /* 11-20 */ '<', '>', '!', '@', '#', '$', '%', '^', '&', '*',
238 /* 21-30 */ '(', ')', '-', '_', '+', ',', ':', '?', '[', ']',
239 /* 31-36 */ '{', '}', '|', '~', '/', '='
240 };
241 
242 #else
243 
244 /*
245  * !!!
246  * Historically, the 4BSD termcap code didn't support functions keys greater
247  * than 9.  This was silently enforced -- asking for key k12 would return the
248  * value for k1.  We try and get around this by using the tables specified in
249  * the terminfo(TI_ENV) man page from the 3rd Edition SVID.  This assumes the
250  * implementors of any System V compatibility code or an extended termcap used
251  * those codes.
252  */
253 static const char codes[] = {
254 /*  0-10 */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';',
255 /* 11-19 */ '1', '2', '3', '4', '5', '6', '7', '8', '9',
256 /* 20-63 */ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
257 	    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
258 	    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
259 	    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
260 };
261 #endif /* _AIX */
262 
263 /*
264  * lcmp --
265  *	list comparison routine for bsearch.
266  */
267 static int
lcmp(a,b)268 lcmp(a, b)
269 	const void *a, *b;
270 {
271 	return (strcmp(a, ((TL *)b)->terminfo));
272 }
273 
274 /*
275  * tigetstr --
276  *
277  * Vendors put the prototype for tigetstr into random include files, including
278  * <term.h>, which we can't include because it makes other systems unhappy.
279  * Try and work around the problem, since we only care about the return value.
280  *
281  * PUBLIC: #ifdef HAVE_CURSES_TIGETSTR
282  * PUBLIC: char *tigetstr();
283  * PUBLIC: #else
284  * PUBLIC: char *tigetstr(char *);
285  * PUBLIC: #endif
286  */
287 char *
tigetstr(name)288 tigetstr(name)
289 	char *name;
290 {
291 	static char sbuf[256];
292 	TL *tlp;
293 	int n;
294 	char *p, keyname[3];
295 
296 	if ((tlp = bsearch(name,
297 	    list, sizeof(list) / sizeof(TL), sizeof(TL), lcmp)) == NULL) {
298 #ifdef _AIX
299 		if (name[0] == 'k' &&
300 		    name[1] == 'f' && (n = atoi(name + 2)) <= 36) {
301 			keyname[0] = 'k';
302 			keyname[1] = codes[n];
303 			keyname[2] = '\0';
304 #else
305 		if (name[0] == 'k' &&
306 		    name[1] == 'f' && (n = atoi(name + 2)) <= 63) {
307 			keyname[0] = n <= 10 ? 'k' : 'F';
308 			keyname[1] = codes[n];
309 			keyname[2] = '\0';
310 #endif
311 			name = keyname;
312 		}
313 	} else
314 		name = tlp->termcap;
315 
316 	p = sbuf;
317 #ifdef _AIX
318 	return ((p = tgetstr(name, &p)) == NULL ? (char *)-1 : (strlcpy(sbuf, p, sizeof(sbuf)), sbuf));
319 #else
320 	return (tgetstr(name, &p) == NULL ? (char *)-1 : sbuf);
321 #endif
322 }
323 
324 /*
325  * tigetnum --
326  *
327  * PUBLIC: #ifndef HAVE_CURSES_TIGETSTR
328  * PUBLIC: int tigetnum(char *);
329  * PUBLIC: #endif
330  */
331 int
tigetnum(name)332 tigetnum(name)
333 	char *name;
334 {
335 	TL *tlp;
336 	int val;
337 
338 	if ((tlp = bsearch(name,
339 	    list, sizeof(list) / sizeof(TL), sizeof(TL), lcmp)) != NULL) {
340 		name = tlp->termcap;
341 	}
342 
343 	return ((val = tgetnum(name)) == -1 ? -2 : val);
344 }
345 #endif /* !HAVE_CURSES_TIGETSTR */
346