Commit | Line | Data |
---|---|---|
fd88f5c5 C |
1 | /*- |
2 | * Copyright (c) 1993, 1994 | |
3 | * The Regents of the University of California. All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * 3. All advertising materials mentioning features or use of this software | |
14 | * must display the following acknowledgement: | |
15 | * This product includes software developed by the University of | |
16 | * California, Berkeley and its contributors. | |
17 | * 4. Neither the name of the University nor the names of its contributors | |
18 | * may be used to endorse or promote products derived from this software | |
19 | * without specific prior written permission. | |
20 | * | |
21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
31 | * SUCH DAMAGE. | |
32 | */ | |
33 | ||
34 | #ifndef lint | |
35 | static char sccsid[] = "@(#)svi_term.c 9.1 (Berkeley) 11/9/94"; | |
36 | #endif /* not lint */ | |
37 | ||
38 | #include <sys/types.h> | |
39 | #include <sys/queue.h> | |
40 | #include <sys/time.h> | |
41 | ||
42 | #include <bitstring.h> | |
43 | #include <errno.h> | |
44 | #include <limits.h> | |
45 | #include <signal.h> | |
46 | #include <stdio.h> | |
47 | #include <stdlib.h> | |
48 | #include <string.h> | |
49 | #include <termios.h> | |
50 | #include <unistd.h> | |
51 | ||
52 | #include "compat.h" | |
53 | #include <curses.h> | |
54 | #include <db.h> | |
55 | #include <regex.h> | |
56 | ||
57 | #include "vi.h" | |
58 | #include "../vi/vcmd.h" | |
59 | #include "excmd.h" | |
60 | #include "svi_screen.h" | |
61 | ||
62 | /* | |
63 | * XXX | |
64 | * THIS REQUIRES THAT ALL SCREENS SHARE A TERMINAL TYPE. | |
65 | */ | |
66 | typedef struct _tklist { | |
67 | char *ts; /* Key's termcap string. */ | |
68 | char *output; /* Corresponding vi command. */ | |
69 | char *name; /* Name. */ | |
70 | u_char value; /* Special value (for lookup). */ | |
71 | } TKLIST; | |
72 | static TKLIST const c_tklist[] = { /* Command mappings. */ | |
73 | #ifdef SYSV_CURSES | |
74 | {"kil1", "O", "insert line"}, | |
75 | {"kdch1", "x", "delete character"}, | |
76 | {"kcud1", "j", "cursor down"}, | |
77 | {"kel", "D", "delete to eol"}, | |
78 | {"kind", "\004", "scroll down"}, | |
79 | {"kll", "$", "go to eol"}, | |
80 | {"khome", "^", "go to sol"}, | |
81 | {"kich1", "i", "insert at cursor"}, | |
82 | {"kdl1", "dd", "delete line"}, | |
83 | {"kcub1", "h", "cursor left"}, | |
84 | {"knp", "\006", "page down"}, | |
85 | {"kpp", "\002", "page up"}, | |
86 | {"kri", "\025", "scroll up"}, | |
87 | {"ked", "dG", "delete to end of screen"}, | |
88 | {"kcuf1", "l", "cursor right"}, | |
89 | {"kcuu1", "k", "cursor up"}, | |
90 | #else | |
91 | {"kA", "O", "insert line"}, | |
92 | {"kD", "x", "delete character"}, | |
93 | {"kd", "j", "cursor down"}, | |
94 | {"kE", "D", "delete to eol"}, | |
95 | {"kF", "\004", "scroll down"}, | |
96 | {"kH", "$", "go to eol"}, | |
97 | {"kh", "^", "go to sol"}, | |
98 | {"kI", "i", "insert at cursor"}, | |
99 | {"kL", "dd", "delete line"}, | |
100 | {"kl", "h", "cursor left"}, | |
101 | {"kN", "\006", "page down"}, | |
102 | {"kP", "\002", "page up"}, | |
103 | {"kR", "\025", "scroll up"}, | |
104 | {"kS", "dG", "delete to end of screen"}, | |
105 | {"kr", "l", "cursor right"}, | |
106 | {"ku", "k", "cursor up"}, | |
107 | #endif | |
108 | {NULL}, | |
109 | }; | |
110 | static TKLIST const m1_tklist[] = { /* Input mappings (lookup). */ | |
111 | {NULL}, | |
112 | }; | |
113 | static TKLIST const m2_tklist[] = { /* Input mappings (set or delete). */ | |
114 | #ifdef SYSV_CURSES | |
115 | {"kcud1", "\033ja", "cursor down"}, | |
116 | {"kcub1", "\033ha", "cursor left"}, | |
117 | {"kcuu1", "\033ka", "cursor up"}, | |
118 | {"kcuf1", "\033la", "cursor right"}, | |
119 | #else | |
120 | {"kd", "\033ja", "cursor down"}, | |
121 | {"kl", "\033ha", "cursor left"}, | |
122 | {"ku", "\033ka", "cursor up"}, | |
123 | {"kr", "\033la", "cursor right"}, | |
124 | #endif | |
125 | {NULL}, | |
126 | }; | |
127 | ||
128 | /* | |
129 | * svi_term_init -- | |
130 | * Initialize the special keys defined by the termcap/terminfo entry. | |
131 | */ | |
132 | int | |
133 | svi_term_init(sp) | |
134 | SCR *sp; | |
135 | { | |
136 | KEYLIST *kp; | |
137 | SEQ *qp; | |
138 | TKLIST const *tkp; | |
139 | size_t len; | |
140 | char *sbp, *s, *t, sbuf[1024]; | |
141 | ||
142 | /* Command mappings. */ | |
143 | for (tkp = c_tklist; tkp->name != NULL; ++tkp) { | |
144 | #ifdef SYSV_CURSES | |
145 | if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) | |
146 | continue; | |
147 | #else | |
148 | sbp = sbuf; | |
149 | if ((t = tgetstr(tkp->ts, &sbp)) == NULL) | |
150 | continue; | |
151 | #endif | |
152 | if (seq_set(sp, tkp->name, strlen(tkp->name), t, strlen(t), | |
153 | tkp->output, strlen(tkp->output), SEQ_COMMAND, | |
154 | SEQ_NOOVERWRITE | SEQ_SCREEN)) | |
155 | return (1); | |
156 | } | |
157 | ||
158 | /* Input mappings needing to be looked up. */ | |
159 | for (tkp = m1_tklist; tkp->name != NULL; ++tkp) { | |
160 | #ifdef SYSV_CURSES | |
161 | if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) | |
162 | continue; | |
163 | #else | |
164 | sbp = sbuf; | |
165 | if ((t = tgetstr(tkp->ts, &sbp)) == NULL) | |
166 | continue; | |
167 | #endif | |
168 | for (kp = keylist;; ++kp) | |
169 | if (kp->value == tkp->value) | |
170 | break; | |
171 | if (kp == NULL) | |
172 | continue; | |
173 | if (seq_set(sp, tkp->name, strlen(tkp->name), t, strlen(t), | |
174 | &kp->ch, 1, SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN)) | |
175 | return (1); | |
176 | } | |
177 | ||
178 | /* Input mappings that are already set or are text deletions. */ | |
179 | for (tkp = m2_tklist; tkp->name != NULL; ++tkp) { | |
180 | #ifdef SYSV_CURSES | |
181 | if ((t = tigetstr(tkp->ts)) == NULL || t == (char *)-1) | |
182 | continue; | |
183 | #else | |
184 | sbp = sbuf; | |
185 | if ((t = tgetstr(tkp->ts, &sbp)) == NULL) | |
186 | continue; | |
187 | #endif | |
188 | /* | |
189 | * !!! | |
190 | * Some terminals' <cursor_left> keys send single <backspace> | |
191 | * characters. This is okay in command mapping, but not okay | |
192 | * in input mapping. That combination is the only one we'll | |
193 | * ever see, hopefully, so kluge it here for now. | |
194 | */ | |
195 | if (!strcmp(t, "\b")) | |
196 | continue; | |
197 | if (tkp->output == NULL) { | |
198 | if (seq_set(sp, tkp->name, strlen(tkp->name), | |
199 | t, strlen(t), NULL, 0, | |
200 | SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN)) | |
201 | return (1); | |
202 | } else | |
203 | if (seq_set(sp, tkp->name, strlen(tkp->name), | |
204 | t, strlen(t), tkp->output, strlen(tkp->output), | |
205 | SEQ_INPUT, SEQ_NOOVERWRITE | SEQ_SCREEN)) | |
206 | return (1); | |
207 | } | |
208 | ||
209 | /* Rework any function key mappings. */ | |
210 | for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = qp->q.le_next) { | |
211 | if (!F_ISSET(qp, SEQ_FUNCMAP)) | |
212 | continue; | |
213 | (void)svi_fmap(sp, qp->stype, | |
214 | qp->input, qp->ilen, qp->output, qp->olen); | |
215 | } | |
216 | ||
217 | /* Set up the visual bell information. */ | |
218 | t = sbuf; | |
219 | if (tgetstr("vb", &t) != NULL && (len = t - sbuf) != 0) { | |
220 | MALLOC_RET(sp, s, char *, len); | |
221 | memmove(s, sbuf, len); | |
222 | if (SVP(sp)->VB != NULL) | |
223 | free(SVP(sp)->VB); | |
224 | SVP(sp)->VB = s; | |
225 | return (0); | |
226 | } | |
227 | ||
228 | return (0); | |
229 | } | |
230 | ||
231 | /* | |
232 | * svi_term_end -- | |
233 | * End the special keys defined by the termcap/terminfo entry. | |
234 | */ | |
235 | int | |
236 | svi_term_end(sp) | |
237 | SCR *sp; | |
238 | { | |
239 | SEQ *qp, *nqp; | |
240 | ||
241 | /* Delete screen specific mappings. */ | |
242 | for (qp = sp->gp->seqq.lh_first; qp != NULL; qp = nqp) { | |
243 | nqp = qp->q.le_next; | |
244 | if (!F_ISSET(qp, SEQ_SCREEN)) | |
245 | continue; | |
246 | (void)seq_mdel(qp); | |
247 | } | |
248 | return (0); | |
249 | } | |
250 | ||
251 | /* | |
252 | * svi_fmap -- | |
253 | * Map a function key. | |
254 | */ | |
255 | int | |
256 | svi_fmap(sp, stype, from, flen, to, tlen) | |
257 | SCR *sp; | |
258 | enum seqtype stype; | |
259 | CHAR_T *from, *to; | |
260 | size_t flen, tlen; | |
261 | { | |
262 | size_t nlen; | |
263 | int nf; | |
264 | char *p, *t, keyname[64]; | |
265 | ||
266 | /* If the terminal isn't initialized, there's nothing to do. */ | |
267 | if (!F_ISSET(SVP(sp), SVI_CURSES_INIT)) | |
268 | return (0); | |
269 | ||
270 | #ifdef SYSV_CURSES | |
271 | (void)snprintf(keyname, sizeof(keyname), "kf%d", atoi(from + 1)); | |
272 | if ((t = tigetstr(keyname)) == NULL || t == (char *)-1) | |
273 | t = NULL; | |
274 | #else | |
275 | /* | |
276 | * !!! | |
277 | * Historically, the 4BSD termcap code didn't support functions keys | |
278 | * greater than 9. This was silently enforced -- asking for key k12 | |
279 | * returned the value for k1. We try and get around this by using | |
280 | * the tables specified in the terminfo(TI_ENV) man page from the 3rd | |
281 | * Edition SVID. This assumes that the implementors of any System V | |
282 | * compatibility code or an extended termcap used those codes. | |
283 | */ | |
284 | { int n; char *sbp, sbuf[1024]; | |
285 | static const char codes[] = { | |
286 | /* 0-10 */ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ';', | |
287 | /* 11-19 */ '1', '2', '3', '4', '5', '6', '7', '8', '9', | |
288 | /* 20-63 */ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', | |
289 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', | |
290 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', | |
291 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', | |
292 | }; | |
293 | if ((n = atoi(from + 1)) > 63) { | |
294 | p = msg_print(sp, from, &nf); | |
295 | msgq(sp, M_ERR, | |
296 | "228|Termcap has no code for the %s function key", p); | |
297 | if (nf) | |
298 | FREE_SPACE(sp, p, 0); | |
299 | return (1); | |
300 | } | |
301 | (void)snprintf(keyname, sizeof(keyname), | |
302 | "%c%c", n <= 10 ? 'k' : 'F', codes[n]); | |
303 | sbp = sbuf; | |
304 | t = tgetstr(keyname, &sbp); | |
305 | } | |
306 | #endif | |
307 | if (t == NULL) { | |
308 | p = msg_print(sp, from, &nf); | |
309 | msgq(sp, M_ERR, "229|This terminal has no %s key", p); | |
310 | if (nf) | |
311 | FREE_SPACE(sp, p, 0); | |
312 | return (1); | |
313 | } | |
314 | ||
315 | nlen = snprintf(keyname, | |
316 | sizeof(keyname), "function key %d", atoi(from + 1)); | |
317 | return (seq_set(sp, keyname, nlen, t, strlen(t), | |
318 | to, tlen, stype, SEQ_NOOVERWRITE | SEQ_SCREEN | SEQ_USERDEF)); | |
319 | } |