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