Merge from vendor branch AWK:
[dragonfly.git] / contrib / nvi / cl / cl_bsd.c
1 /*-
2  * Copyright (c) 1995, 1996
3  *      Keith Bostic.  All rights reserved.
4  *
5  * See the LICENSE file for redistribution information.
6  */
7
8 #include "config.h"
9
10 #ifndef lint
11 static const char sccsid[] = "@(#)cl_bsd.c      8.29 (Berkeley) 7/1/96";
12 #endif /* not lint */
13
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 #include <sys/time.h>
17
18 #include <bitstring.h>
19 #include <ctype.h>
20 #include <curses.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <termios.h>
26 #include <unistd.h>
27
28 #include "../common/common.h"
29 #include "../vi/vi.h"
30 #include "cl.h"
31
32 static char     *ke;                            /* Keypad on. */
33 static char     *ks;                            /* Keypad off. */
34 static char     *vb;                            /* Visible bell string. */
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 __P((char *, int));
49  * PUBLIC: #endif
50  */
51 int
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 __P((void));
70  * PUBLIC: #endif
71  */
72 void
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 __P((void));
86  * PUBLIC: #endif
87  */
88 void
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 __P((WINDOW *, int));
106  * PUBLIC: #endif
107  */
108 void
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 __P((void *, int));
124  * PUBLIC: #endif
125  */
126 int
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 __P((const char *, FILE *, FILE *));
148  * PUBLIC: #endif
149  */
150 void *
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 __P((char *, int, int *));
166  * PUBLIC: #endif
167  */
168 void
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         "kend",         "@7",           /* Go to eol. */
214         "khome",        "kh",           /* Go to sol. */
215         "kich1",        "kI",           /* Insert at cursor. */
216         "kil1",         "kA",           /* Insert line. */
217         "kind",         "kF",           /* Scroll down. */
218         "kll",          "kH",           /* Go to eol. */
219         "knp",          "kN",           /* Page down. */
220         "kpp",          "kP",           /* Page up. */
221         "kri",          "kR",           /* Scroll up. */
222         "lines",        "li",           /* Terminal lines. */
223         "rmcup",        "te",           /* Terminal end string. */
224         "rmkx",         "ke",           /* Exit "keypad-transmit" mode. */
225         "rmso",         "se",           /* Standout end. */
226         "smcup",        "ti",           /* Terminal initialization string. */
227         "smkx",         "ks",           /* Enter "keypad-transmit" mode. */
228         "smso",         "so",           /* Standout begin. */
229 };
230
231 #ifdef _AIX
232 /*
233  * AIX's implementation for function keys greater than 10 is different and
234  * only goes as far as 36.
235  */
236 static const char codes[] = {
237 /*  0-10 */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';',
238 /* 11-20 */ '<', '>', '!', '@', '#', '$', '%', '^', '&', '*',
239 /* 21-30 */ '(', ')', '-', '_', '+', ',', ':', '?', '[', ']',
240 /* 31-36 */ '{', '}', '|', '~', '/', '='
241 };
242
243 #else
244
245 /*
246  * !!!
247  * Historically, the 4BSD termcap code didn't support functions keys greater
248  * than 9.  This was silently enforced -- asking for key k12 would return the
249  * value for k1.  We try and get around this by using the tables specified in
250  * the terminfo(TI_ENV) man page from the 3rd Edition SVID.  This assumes the
251  * implementors of any System V compatibility code or an extended termcap used
252  * those codes.
253  */
254 static const char codes[] = {
255 /*  0-10 */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';',
256 /* 11-19 */ '1', '2', '3', '4', '5', '6', '7', '8', '9',
257 /* 20-63 */ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
258             'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
259             'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
260             'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
261 };
262 #endif /* _AIX */
263
264 /*
265  * lcmp --
266  *      list comparison routine for bsearch.
267  */
268 static int
269 lcmp(a, b)
270         const void *a, *b;
271 {
272         return (strcmp(a, ((TL *)b)->terminfo));
273 }
274
275 /*
276  * tigetstr --
277  *
278  * Vendors put the prototype for tigetstr into random include files, including
279  * <term.h>, which we can't include because it makes other systems unhappy.
280  * Try and work around the problem, since we only care about the return value.
281  *
282  * PUBLIC: #ifdef HAVE_CURSES_TIGETSTR
283  * PUBLIC: char *tigetstr();
284  * PUBLIC: #else
285  * PUBLIC: char *tigetstr __P((char *));
286  * PUBLIC: #endif
287  */
288 char *
289 tigetstr(name)
290         char *name;
291 {
292         static char sbuf[256];
293         TL *tlp;
294         int n;
295         char *p, keyname[3];
296
297         if ((tlp = bsearch(name,
298             list, sizeof(list) / sizeof(TL), sizeof(TL), lcmp)) == NULL) {
299 #ifdef _AIX
300                 if (name[0] == 'k' &&
301                     name[1] == 'f' && (n = atoi(name + 2)) <= 36) {
302                         keyname[0] = 'k';
303                         keyname[1] = codes[n];
304                         keyname[2] = '\0';
305 #else
306                 if (name[0] == 'k' &&
307                     name[1] == 'f' && (n = atoi(name + 2)) <= 63) {
308                         keyname[0] = n <= 10 ? 'k' : 'F';
309                         keyname[1] = codes[n];
310                         keyname[2] = '\0';
311 #endif
312                         name = keyname;
313                 }
314         } else
315                 name = tlp->termcap;
316
317         p = sbuf;
318 #ifdef _AIX
319         return ((p = tgetstr(name, &p)) == NULL ? (char *)-1 : strcpy(sbuf, p));
320 #else
321         return (tgetstr(name, &p) == NULL ? (char *)-1 : sbuf);
322 #endif
323 }
324
325 /*
326  * tigetnum --
327  *
328  * PUBLIC: #ifndef HAVE_CURSES_TIGETSTR
329  * PUBLIC: int tigetnum __P((char *));
330  * PUBLIC: #endif
331  */
332 int
333 tigetnum(name)
334         char *name;
335 {
336         TL *tlp;
337         int val;
338
339         if ((tlp = bsearch(name,
340             list, sizeof(list) / sizeof(TL), sizeof(TL), lcmp)) != NULL) {
341                 name = tlp->termcap;
342         }
343
344         return ((val = tgetnum(name)) == -1 ? -2 : val);
345 }
346 #endif /* !HAVE_CURSES_TIGETSTR */