Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* curses.c */ |
2 | ||
3 | /* Author: | |
4 | * Steve Kirkendall | |
5 | * 14407 SW Teal Blvd. #C | |
6 | * Beaverton, OR 97005 | |
7 | * kirkenda@cs.pdx.edu | |
8 | */ | |
9 | ||
10 | ||
11 | /* This file contains the functions & variables needed for a tiny subset of | |
12 | * curses. The principle advantage of this version of curses is its | |
13 | * extreme speed. Disadvantages are potentially larger code, few supported | |
14 | * functions, limited compatibility with full curses, and only stdscr. | |
15 | */ | |
16 | ||
17 | #include "config.h" | |
18 | #include "vi.h" | |
19 | ||
20 | #if ANY_UNIX | |
78ed81a3 | 21 | # if UNIXV || COH_386 |
15637ed4 RG |
22 | # ifdef TERMIOS |
23 | # include <termios.h> | |
24 | # else | |
25 | # include <termio.h> | |
26 | # endif | |
78ed81a3 | 27 | # ifndef NO_S5WINSIZE |
28 | # ifndef _SEQUENT_ | |
29 | # include <sys/stream.h> /* winsize struct defined in one of these? */ | |
30 | # include <sys/ptem.h> | |
31 | # endif | |
15637ed4 RG |
32 | # else |
33 | # undef TIOCGWINSZ /* we can't handle it correctly yet */ | |
34 | # endif | |
35 | # else | |
36 | # include <sgtty.h> | |
37 | # endif | |
38 | #endif | |
39 | ||
40 | #if TOS | |
41 | # include <osbind.h> | |
42 | #endif | |
43 | ||
44 | #if OSK | |
45 | # include <sgstat.h> | |
46 | #endif | |
47 | ||
48 | #if VMS | |
49 | extern int VMS_read_raw; /* Set in initscr() */ | |
50 | #endif | |
51 | ||
52 | ||
15637ed4 RG |
53 | static void starttcap(); |
54 | ||
55 | /* variables, publicly available & used in the macros */ | |
56 | char *termtype; /* name of terminal entry */ | |
57 | short ospeed; /* speed of the tty, eg B2400 */ | |
58 | #if OSK | |
59 | char PC_; /* Pad char */ | |
60 | char *BC; /* backspace character string */ | |
61 | #else | |
62 | char PC; /* Pad char */ | |
63 | #endif | |
64 | WINDOW *stdscr; /* pointer into kbuf[] */ | |
65 | WINDOW kbuf[KBSIZ]; /* a very large output buffer */ | |
66 | int LINES; /* :li#: number of rows */ | |
67 | int COLS; /* :co#: number of columns */ | |
68 | int AM; /* :am: boolean: auto margins? */ | |
69 | int PT; /* :pt: boolean: physical tabs? */ | |
70 | char *VB; /* :vb=: visible bell */ | |
71 | char *UP; /* :up=: move cursor up */ | |
72 | char *SO = ""; /* :so=: standout start */ | |
73 | char *SE = ""; /* :se=: standout end */ | |
74 | char *US = ""; /* :us=: underline start */ | |
75 | char *UE = ""; /* :ue=: underline end */ | |
76 | char *MD = ""; /* :md=: bold start */ | |
77 | char *ME = ""; /* :me=: bold end */ | |
78 | char *AS = ""; /* :as=: alternate (italic) start */ | |
79 | char *AE = ""; /* :ae=: alternate (italic) end */ | |
80 | #ifndef NO_VISIBLE | |
81 | char *MV; /* :mv=: "visible" selection start */ | |
82 | #endif | |
83 | char *CM; /* :cm=: cursor movement */ | |
84 | char *CE; /* :ce=: clear to end of line */ | |
85 | char *CD; /* :cd=: clear to end of screen */ | |
86 | char *AL; /* :al=: add a line */ | |
87 | char *DL; /* :dl=: delete a line */ | |
88 | #if OSK | |
89 | char *SR_; /* :sr=: scroll reverse */ | |
90 | #else | |
91 | char *SR; /* :sr=: scroll reverse */ | |
92 | #endif | |
78ed81a3 | 93 | char *KS = ""; /* :ks=: switch keypad to application mode */ |
94 | char *KE = ""; /* :ke=: switch keypad to system mode */ | |
15637ed4 RG |
95 | char *KU; /* :ku=: key sequence sent by up arrow */ |
96 | char *KD; /* :kd=: key sequence sent by down arrow */ | |
97 | char *KL; /* :kl=: key sequence sent by left arrow */ | |
98 | char *KR; /* :kr=: key sequence sent by right arrow */ | |
99 | char *HM; /* :HM=: key sequence sent by the <Home> key */ | |
100 | char *EN; /* :EN=: key sequence sent by the <End> key */ | |
101 | char *PU; /* :PU=: key sequence sent by the <PgUp> key */ | |
102 | char *PD; /* :PD=: key sequence sent by the <PgDn> key */ | |
103 | char *KI; /* :kI=: key sequence sent by the <Insert> key */ | |
104 | #ifndef NO_FKEY | |
105 | char *FKEY[NFKEYS]; /* :k0=: ... :k9=: sequences sent by function keys */ | |
106 | #endif | |
107 | char *IM = ""; /* :im=: insert mode start */ | |
108 | char *IC = ""; /* :ic=: insert the following character */ | |
109 | char *EI = ""; /* :ei=: insert mode end */ | |
110 | char *DC; /* :dc=: delete a character */ | |
111 | char *TI = ""; /* :ti=: terminal init */ /* GB */ | |
112 | char *TE = ""; /* :te=: terminal exit */ /* GB */ | |
113 | #ifndef NO_CURSORSHAPE | |
114 | #if 1 | |
115 | char *CQ = (char *)0;/* :cQ=: normal cursor */ | |
116 | char *CX = (char *)1;/* :cX=: cursor used for EX command/entry */ | |
117 | char *CV = (char *)2;/* :cV=: cursor used for VI command mode */ | |
118 | char *CI = (char *)3;/* :cI=: cursor used for VI input mode */ | |
119 | char *CR = (char *)4;/* :cR=: cursor used for VI replace mode */ | |
120 | #else | |
121 | char *CQ = ""; /* :cQ=: normal cursor */ | |
122 | char *CX = ""; /* :cX=: cursor used for EX command/entry */ | |
123 | char *CV = ""; /* :cV=: cursor used for VI command mode */ | |
124 | char *CI = ""; /* :cI=: cursor used for VI input mode */ | |
125 | char *CR = ""; /* :cR=: cursor used for VI replace mode */ | |
126 | #endif | |
127 | #endif | |
128 | char *aend = ""; /* end an attribute -- either UE or ME */ | |
129 | char ERASEKEY; /* backspace key taken from ioctl structure */ | |
130 | #ifndef NO_COLOR | |
78ed81a3 | 131 | char normalcolor[24]; |
132 | char SOcolor[24]; | |
133 | char SEcolor[24]; | |
134 | char UScolor[24]; | |
135 | char UEcolor[24]; | |
136 | char MDcolor[24]; | |
137 | char MEcolor[24]; | |
138 | char AScolor[24]; | |
139 | char AEcolor[24]; | |
15637ed4 | 140 | # ifndef NO_POPUP |
78ed81a3 | 141 | char POPUPcolor[24]; |
15637ed4 RG |
142 | # endif |
143 | # ifndef NO_VISIBLE | |
78ed81a3 | 144 | char VISIBLEcolor[24]; |
15637ed4 RG |
145 | # endif |
146 | #endif | |
147 | ||
148 | #if ANY_UNIX | |
78ed81a3 | 149 | # if UNIXV || COH_386 |
15637ed4 RG |
150 | # ifdef TERMIOS |
151 | static struct termios oldtermio; /* original tty mode */ | |
152 | static struct termios newtermio; /* cbreak/noecho tty mode */ | |
153 | # else | |
154 | static struct termio oldtermio; /* original tty mode */ | |
155 | static struct termio newtermio; /* cbreak/noecho tty mode */ | |
156 | # endif | |
157 | # else | |
158 | static struct sgttyb oldsgttyb; /* original tty mode */ | |
159 | static struct sgttyb newsgttyb; /* cbreak/nl/noecho tty mode */ | |
160 | static int oldint; /* ^C or DEL, the "intr" character */ | |
161 | # ifdef TIOCSLTC | |
162 | static int oldswitch; /* ^Z, the "suspend" character */ | |
163 | static int olddswitch; /* ^Y, the "delayed suspend" char */ | |
164 | static int oldquote; /* ^V, the "quote next char" char */ | |
165 | # endif | |
166 | # endif | |
167 | #endif | |
168 | ||
169 | #if OSK | |
170 | static struct sgbuf oldsgttyb; /* orginal tty mode */ | |
171 | static struct sgbuf newsgttyb; /* noecho tty mode */ | |
172 | #endif | |
173 | ||
174 | static char *capbuf; /* capability string buffer */ | |
175 | ||
176 | ||
177 | /* Initialize the Curses package. */ | |
178 | void initscr() | |
179 | { | |
180 | /* make sure TERM variable is set */ | |
181 | termtype = getenv("TERM"); | |
182 | ||
183 | #if VMS | |
184 | /* VMS getenv() handles TERM as a environment setting. Foreign | |
185 | * terminal support can be implemented by setting the ELVIS_TERM | |
186 | * logical or symbol to match a tinytcap entry. | |
187 | */ | |
188 | if (!strcmp(termtype,"unknown")) | |
189 | termtype = getenv("ELVIS_TERM"); | |
190 | #endif | |
191 | #if MSDOS | |
192 | /* For MS-DOS, if TERM is unset we can default to "pcbios", or | |
193 | * maybe "rainbow". | |
194 | */ | |
195 | if (!termtype) | |
196 | { | |
197 | #ifdef RAINBOW | |
198 | if (*(unsigned char far*)(0xffff000eL) == 6 /* Rainbow 100a */ | |
199 | || *(unsigned char far*)(0xffff000eL) == 148)/* Rainbow 100b */ | |
200 | { | |
201 | termtype = "rainbow"; | |
202 | } | |
203 | else | |
204 | #endif | |
205 | termtype = "pcbios"; | |
206 | } | |
207 | if (!strcmp(termtype, "pcbios")) | |
208 | #else | |
209 | if (!termtype) | |
210 | #endif | |
211 | { | |
212 | #if ANY_UNIX | |
213 | write(2, "Environment variable TERM must be set\n", (unsigned)38); | |
78ed81a3 | 214 | exit(2); |
15637ed4 RG |
215 | #endif |
216 | #if OSK | |
217 | writeln(2, "Environment variable TERM must be set\n", (unsigned)38); | |
78ed81a3 | 218 | exit(2); |
15637ed4 RG |
219 | #endif |
220 | #if AMIGA | |
221 | termtype = TERMTYPE; | |
222 | starttcap(termtype); | |
223 | #endif | |
224 | #if MSDOS | |
225 | starttcap("pcbios"); | |
226 | #endif | |
227 | #if TOS | |
228 | termtype = "vt52"; | |
229 | starttcap(termtype); | |
230 | #endif | |
231 | #if VMS | |
232 | write(2, "UNKNOWN terminal: define ELVIS_TERM\n", (unsigned)36); | |
78ed81a3 | 233 | exit(2); |
15637ed4 RG |
234 | #endif |
235 | } | |
236 | else | |
237 | { | |
238 | #if MSDOS | |
239 | *o_pcbios = 0; | |
240 | #endif | |
241 | /* start termcap stuff */ | |
242 | starttcap(termtype); | |
243 | } | |
244 | ||
245 | /* create stdscr and curscr */ | |
246 | stdscr = kbuf; | |
247 | ||
248 | /* change the terminal mode to cbreak/noecho */ | |
249 | #if ANY_UNIX | |
78ed81a3 | 250 | # if UNIXV || COH_386 |
15637ed4 RG |
251 | # ifdef TERMIOS |
252 | tcgetattr(2, &oldtermio); | |
253 | # else | |
254 | ioctl(2, TCGETA, &oldtermio); | |
255 | # endif | |
256 | # else | |
257 | ioctl(2, TIOCGETP, &oldsgttyb); | |
258 | # endif | |
259 | #endif | |
260 | ||
261 | #if OSK | |
262 | _gs_opt(0, &oldsgttyb); | |
263 | #endif | |
264 | ||
265 | #if VMS | |
266 | VMS_read_raw = 1; /* cbreak/noecho */ | |
267 | vms_open_tty(); | |
268 | #endif | |
269 | resume_curses(TRUE); | |
270 | } | |
271 | ||
272 | /* Shut down the Curses package. */ | |
273 | void endwin() | |
274 | { | |
275 | /* change the terminal mode back the way it was */ | |
276 | suspend_curses(); | |
277 | #if AMIGA | |
278 | amiclosewin(); | |
279 | #endif | |
280 | } | |
281 | ||
282 | ||
283 | static int curses_active = FALSE; | |
284 | ||
78ed81a3 | 285 | extern int oldcurs; |
286 | ||
15637ed4 RG |
287 | /* Send any required termination strings. Turn off "raw" mode. */ |
288 | void suspend_curses() | |
289 | { | |
78ed81a3 | 290 | #if ANY_UNIX && !(UNIXV || COH_386) |
15637ed4 RG |
291 | struct tchars tbuf; |
292 | # ifdef TIOCSLTC | |
293 | struct ltchars ltbuf; | |
294 | # endif | |
295 | #endif | |
296 | #ifndef NO_CURSORSHAPE | |
297 | if (has_CQ) | |
298 | { | |
299 | do_CQ(); | |
78ed81a3 | 300 | oldcurs = 0; |
15637ed4 RG |
301 | } |
302 | #endif | |
303 | if (has_TE) /* GB */ | |
304 | { | |
305 | do_TE(); | |
306 | } | |
307 | if (has_KE) | |
308 | { | |
309 | do_KE(); | |
310 | } | |
311 | #ifndef NO_COLOR | |
312 | quitcolor(); | |
313 | #endif | |
314 | refresh(); | |
315 | ||
316 | /* change the terminal mode back the way it was */ | |
317 | #if ANY_UNIX | |
78ed81a3 | 318 | # if (UNIXV || COH_386) |
319 | # ifdef TERMIOS | |
15637ed4 RG |
320 | tcsetattr(2, TCSADRAIN, &oldtermio); |
321 | # else | |
322 | ioctl(2, TCSETAW, &oldtermio); | |
323 | # endif | |
324 | # else | |
325 | ioctl(2, TIOCSETP, &oldsgttyb); | |
326 | ||
327 | ioctl(2, TIOCGETC, (struct sgttyb *) &tbuf); | |
328 | tbuf.t_intrc = oldint; | |
329 | ioctl(2, TIOCSETC, (struct sgttyb *) &tbuf); | |
330 | ||
331 | # ifdef TIOCSLTC | |
332 | ioctl(2, TIOCGLTC, <buf); | |
333 | ltbuf.t_suspc = oldswitch; | |
334 | ltbuf.t_dsuspc = olddswitch; | |
335 | ltbuf.t_lnextc = oldquote; | |
336 | ioctl(2, TIOCSLTC, <buf); | |
337 | # endif | |
338 | # endif | |
339 | #endif | |
340 | #if OSK | |
341 | _ss_opt(0, &oldsgttyb); | |
342 | #endif | |
343 | #if AMIGA | |
344 | ttyshutdown(); | |
345 | #endif | |
346 | #if MSDOS | |
347 | raw_set_stdio(FALSE); | |
348 | #endif | |
349 | ||
350 | #if VMS | |
351 | VMS_read_raw = 0; | |
352 | #endif | |
353 | curses_active = FALSE; | |
354 | } | |
355 | ||
356 | ||
357 | /* put the terminal in RAW mode. If "quietly" is FALSE, then ask the user | |
358 | * to hit a key, and wait for keystroke before returning. | |
359 | */ | |
360 | void resume_curses(quietly) | |
361 | int quietly; | |
362 | { | |
363 | if (!curses_active) | |
364 | { | |
365 | /* change the terminal mode to cbreak/noecho */ | |
366 | #if ANY_UNIX | |
78ed81a3 | 367 | # if UNIXV || COH_386 |
15637ed4 RG |
368 | ospeed = (oldtermio.c_cflag & CBAUD); |
369 | ERASEKEY = oldtermio.c_cc[VERASE]; | |
370 | newtermio = oldtermio; | |
371 | newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK); | |
372 | newtermio.c_oflag &= ~OPOST; | |
373 | newtermio.c_lflag &= ISIG; | |
374 | newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */ | |
375 | newtermio.c_cc[VMIN] = 1; | |
376 | newtermio.c_cc[VTIME] = 0; | |
377 | # ifdef VSWTCH | |
378 | newtermio.c_cc[VSWTCH] = 0; | |
379 | # endif | |
380 | # ifdef VSUSP | |
381 | newtermio.c_cc[VSUSP] = 0; | |
382 | # endif | |
383 | # ifdef TERMIOS | |
384 | tcsetattr(2, TCSADRAIN, &newtermio); | |
385 | # else | |
386 | ioctl(2, TCSETAW, &newtermio); | |
387 | # endif | |
78ed81a3 | 388 | # else /* BSD, V7, Coherent-286, or Minix */ |
15637ed4 RG |
389 | struct tchars tbuf; |
390 | # ifdef TIOCSLTC | |
391 | struct ltchars ltbuf; | |
392 | # endif | |
393 | ||
394 | ospeed = oldsgttyb.sg_ospeed; | |
395 | ERASEKEY = oldsgttyb.sg_erase; | |
396 | newsgttyb = oldsgttyb; | |
397 | newsgttyb.sg_flags |= CBREAK; | |
398 | newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS); | |
399 | ioctl(2, TIOCSETP, &newsgttyb); | |
400 | ||
401 | ioctl(2, TIOCGETC, (struct sgttyb *) &tbuf); | |
402 | oldint = tbuf.t_intrc; | |
403 | tbuf.t_intrc = ctrl('C'); /* always use ^C for interrupts */ | |
404 | ioctl(2, TIOCSETC, (struct sgttyb *) &tbuf); | |
405 | ||
406 | # ifdef TIOCSLTC | |
407 | ioctl(2, TIOCGLTC, <buf); | |
408 | oldswitch = ltbuf.t_suspc; | |
409 | ltbuf.t_suspc = 0; /* disable ^Z for elvis */ | |
410 | olddswitch = ltbuf.t_dsuspc; | |
411 | ltbuf.t_dsuspc = 0; /* disable ^Y for elvis */ | |
412 | oldquote = ltbuf.t_lnextc; | |
413 | ltbuf.t_lnextc = 0; /* disable ^V for elvis */ | |
414 | ioctl(2, TIOCSLTC, <buf); | |
415 | # endif | |
416 | ||
417 | # endif | |
418 | #endif | |
419 | #if OSK | |
420 | newsgttyb = oldsgttyb; | |
421 | newsgttyb.sg_echo = 0; | |
422 | newsgttyb.sg_eofch = 0; | |
423 | newsgttyb.sg_kbach = 0; | |
424 | newsgttyb.sg_kbich = ctrl('C'); | |
425 | _ss_opt(0, &newsgttyb); | |
426 | ospeed = oldsgttyb.sg_baud; | |
427 | ERASEKEY = oldsgttyb.sg_bspch; | |
428 | #endif | |
429 | #if AMIGA | |
430 | /* turn on window resize and RAW */ | |
431 | ttysetup(); | |
432 | #endif | |
433 | #if MSDOS | |
434 | raw_set_stdio(TRUE); | |
435 | #endif | |
436 | ||
437 | #if VMS | |
438 | VMS_read_raw = 1; | |
439 | { int c; | |
440 | read(0,&c,0); /* Flush the tty buffer. */ | |
441 | } | |
442 | ERASEKEY = '\177'; /* Accept <DEL> as <^H> for VMS */ | |
443 | #endif | |
444 | ||
78ed81a3 | 445 | curses_active = TRUE; |
446 | } | |
447 | ||
448 | /* If we're supposed to quit quietly, then we're done */ | |
449 | if (quietly) | |
450 | { | |
15637ed4 RG |
451 | if (has_TI) /* GB */ |
452 | { | |
453 | do_TI(); | |
454 | } | |
455 | if (has_KS) | |
456 | { | |
457 | do_KS(); | |
458 | } | |
459 | ||
15637ed4 RG |
460 | return; |
461 | } | |
462 | ||
463 | signal(SIGINT, SIG_IGN); | |
464 | ||
465 | move(LINES - 1, 0); | |
466 | do_SO(); | |
467 | #if VMS | |
468 | qaddstr("\n[Press <RETURN> to continue]"); | |
469 | #else | |
470 | qaddstr("[Press <RETURN> to continue]"); | |
471 | #endif | |
472 | do_SE(); | |
473 | refresh(); | |
474 | ttyread(kbuf, 20, 0); /* in RAW mode, so <20 is very likely */ | |
78ed81a3 | 475 | if (has_TI) |
476 | { | |
477 | do_TI(); | |
478 | } | |
15637ed4 RG |
479 | if (kbuf[0] == ':') |
480 | { | |
481 | mode = MODE_COLON; | |
482 | addch('\n'); | |
483 | refresh(); | |
484 | } | |
485 | else | |
486 | { | |
487 | mode = MODE_VI; | |
488 | redraw(MARK_UNSET, FALSE); | |
489 | } | |
490 | exwrote = FALSE; | |
491 | ||
15637ed4 | 492 | signal(SIGINT, trapint); |
15637ed4 RG |
493 | } |
494 | ||
495 | /* This function fetches an optional string from termcap */ | |
496 | static void mayhave(T, s) | |
497 | char **T; /* where to store the returned pointer */ | |
498 | char *s; /* name of the capability */ | |
499 | { | |
500 | char *val; | |
501 | ||
502 | val = tgetstr(s, &capbuf); | |
503 | if (val) | |
504 | { | |
505 | *T = val; | |
506 | } | |
507 | } | |
508 | ||
509 | ||
510 | /* This function fetches a required string from termcap */ | |
511 | static void musthave(T, s) | |
512 | char **T; /* where to store the returned pointer */ | |
513 | char *s; /* name of the capability */ | |
514 | { | |
515 | mayhave(T, s); | |
516 | if (!*T) | |
517 | { | |
518 | write(2, "This termcap entry lacks the :", (unsigned)30); | |
519 | write(2, s, (unsigned)2); | |
520 | write(2, "=: capability\n", (unsigned)14); | |
521 | #if OSK | |
522 | write(2, "\l", 1); | |
523 | #endif | |
78ed81a3 | 524 | exit(2); |
15637ed4 RG |
525 | } |
526 | } | |
527 | ||
528 | ||
529 | /* This function fetches a pair of strings from termcap. If one of them is | |
530 | * missing, then the other one is ignored. | |
531 | */ | |
532 | static void pair(T, U, sT, sU) | |
533 | char **T; /* where to store the first pointer */ | |
534 | char **U; /* where to store the second pointer */ | |
535 | char *sT; /* name of the first capability */ | |
536 | char *sU; /* name of the second capability */ | |
537 | { | |
538 | mayhave(T, sT); | |
539 | mayhave(U, sU); | |
540 | if (!**T || !**U) | |
541 | { | |
542 | *T = *U = ""; | |
543 | } | |
544 | } | |
545 | ||
546 | ||
547 | ||
548 | /* Read everything from termcap */ | |
549 | static void starttcap(term) | |
550 | char *term; | |
551 | { | |
552 | static char cbmem[800]; | |
553 | ||
554 | /* allocate memory for capbuf */ | |
555 | capbuf = cbmem; | |
556 | ||
557 | /* get the termcap entry */ | |
558 | switch (tgetent(kbuf, term)) | |
559 | { | |
560 | case -1: | |
561 | write(2, "Can't read /etc/termcap\n", (unsigned)24); | |
562 | #if OSK | |
563 | write(2, "\l", 1); | |
564 | #endif | |
565 | exit(2); | |
566 | ||
567 | case 0: | |
568 | write(2, "Unrecognized TERM type\n", (unsigned)23); | |
569 | #if OSK | |
570 | write(2, "\l", 1); | |
571 | #endif | |
572 | exit(3); | |
573 | } | |
574 | ||
575 | /* get strings */ | |
576 | musthave(&UP, "up"); | |
577 | mayhave(&VB, "vb"); | |
578 | musthave(&CM, "cm"); | |
579 | pair(&SO, &SE, "so", "se"); | |
580 | mayhave(&TI, "ti"); | |
581 | mayhave(&TE, "te"); | |
582 | if (tgetnum("ug") <= 0) | |
583 | { | |
584 | pair(&US, &UE, "us", "ue"); | |
585 | pair(&MD, &ME, "md", "me"); | |
586 | ||
587 | /* get italics, or have it default to underline */ | |
588 | pair(&AS, &AE, "as", "ae"); | |
589 | if (!*AS) | |
590 | { | |
591 | AS = US; | |
592 | AE = UE; | |
593 | } | |
594 | } | |
595 | #ifndef NO_VISIBLE | |
596 | MV = SO; /* by default */ | |
597 | mayhave(&MV, "mv"); | |
598 | #endif | |
599 | mayhave(&AL, "al"); | |
600 | mayhave(&DL, "dl"); | |
601 | musthave(&CE, "ce"); | |
602 | mayhave(&CD, "cd"); | |
603 | #if OSK | |
604 | mayhave(&SR_, "sr"); | |
605 | #else | |
606 | mayhave(&SR, "sr"); | |
607 | #endif | |
608 | pair(&IM, &EI, "im", "ei"); | |
609 | mayhave(&IC, "ic"); | |
610 | mayhave(&DC, "dc"); | |
611 | ||
612 | /* other termcap stuff */ | |
613 | AM = (tgetflag("am") && !tgetflag("xn")); | |
614 | PT = tgetflag("pt"); | |
615 | #if AMIGA | |
616 | amiopenwin(termtype); /* Must run this before ttysetup(); */ | |
617 | ttysetup(); /* Must run this before getsize(0); */ | |
618 | #endif | |
619 | getsize(0); | |
620 | ||
621 | /* Key sequences */ | |
78ed81a3 | 622 | pair(&KS, &KE, "ks", "ke"); /* keypad enable/disable */ |
15637ed4 RG |
623 | mayhave(&KU, "ku"); /* up */ |
624 | mayhave(&KD, "kd"); /* down */ | |
15637ed4 | 625 | mayhave(&KR, "kr"); /* right */ |
78ed81a3 | 626 | mayhave(&KL, "kl"); /* left */ |
627 | if (KL && KL[0]=='\b' && !KL[1]) | |
628 | { | |
629 | /* never use '\b' as a left arrow! */ | |
630 | KL = (char *)0; | |
631 | } | |
15637ed4 RG |
632 | mayhave(&PU, "kP"); /* PgUp */ |
633 | mayhave(&PD, "kN"); /* PgDn */ | |
634 | mayhave(&HM, "kh"); /* Home */ | |
635 | mayhave(&EN, "kH"); /* End */ | |
636 | mayhave(&KI, "kI"); /* Insert */ | |
637 | #ifndef CRUNCH | |
638 | if (!PU) mayhave(&PU, "K2"); /* "3x3 pad" names for PgUp, etc. */ | |
639 | if (!PD) mayhave(&PD, "K5"); | |
640 | if (!HM) mayhave(&HM, "K1"); | |
641 | if (!EN) mayhave(&EN, "K4"); | |
642 | ||
643 | mayhave(&PU, "PU"); /* old XENIX names for PgUp, etc. */ | |
644 | mayhave(&PD, "PD"); /* (overrides others, if used.) */ | |
645 | mayhave(&HM, "HM"); | |
646 | mayhave(&EN, "EN"); | |
647 | #endif | |
648 | #ifndef NO_FKEY | |
649 | mayhave(&FKEY[0], "k0"); /* function key codes */ | |
650 | mayhave(&FKEY[1], "k1"); | |
651 | mayhave(&FKEY[2], "k2"); | |
652 | mayhave(&FKEY[3], "k3"); | |
653 | mayhave(&FKEY[4], "k4"); | |
654 | mayhave(&FKEY[5], "k5"); | |
655 | mayhave(&FKEY[6], "k6"); | |
656 | mayhave(&FKEY[7], "k7"); | |
657 | mayhave(&FKEY[8], "k8"); | |
658 | mayhave(&FKEY[9], "k9"); | |
659 | # ifndef NO_SHIFT_FKEY | |
660 | mayhave(&FKEY[10], "s0"); /* shift function key codes */ | |
661 | mayhave(&FKEY[11], "s1"); | |
662 | mayhave(&FKEY[12], "s2"); | |
663 | mayhave(&FKEY[13], "s3"); | |
664 | mayhave(&FKEY[14], "s4"); | |
665 | mayhave(&FKEY[15], "s5"); | |
666 | mayhave(&FKEY[16], "s6"); | |
667 | mayhave(&FKEY[17], "s7"); | |
668 | mayhave(&FKEY[18], "s8"); | |
669 | mayhave(&FKEY[19], "s9"); | |
670 | # ifndef NO_CTRL_FKEY | |
671 | mayhave(&FKEY[20], "c0"); /* control function key codes */ | |
672 | mayhave(&FKEY[21], "c1"); | |
673 | mayhave(&FKEY[22], "c2"); | |
674 | mayhave(&FKEY[23], "c3"); | |
675 | mayhave(&FKEY[24], "c4"); | |
676 | mayhave(&FKEY[25], "c5"); | |
677 | mayhave(&FKEY[26], "c6"); | |
678 | mayhave(&FKEY[27], "c7"); | |
679 | mayhave(&FKEY[28], "c8"); | |
680 | mayhave(&FKEY[29], "c9"); | |
681 | # ifndef NO_ALT_FKEY | |
682 | mayhave(&FKEY[30], "a0"); /* alt function key codes */ | |
683 | mayhave(&FKEY[31], "a1"); | |
684 | mayhave(&FKEY[32], "a2"); | |
685 | mayhave(&FKEY[33], "a3"); | |
686 | mayhave(&FKEY[34], "a4"); | |
687 | mayhave(&FKEY[35], "a5"); | |
688 | mayhave(&FKEY[36], "a6"); | |
689 | mayhave(&FKEY[37], "a7"); | |
690 | mayhave(&FKEY[38], "a8"); | |
691 | mayhave(&FKEY[39], "a9"); | |
692 | # endif | |
693 | # endif | |
694 | # endif | |
695 | #endif | |
696 | ||
697 | #ifndef NO_CURSORSHAPE | |
698 | /* cursor shapes */ | |
699 | CQ = tgetstr("cQ", &capbuf); | |
700 | if (has_CQ) | |
701 | { | |
702 | CX = tgetstr("cX", &capbuf); | |
703 | if (!CX) CX = CQ; | |
704 | CV = tgetstr("cV", &capbuf); | |
705 | if (!CV) CV = CQ; | |
706 | CI = tgetstr("cI", &capbuf); | |
707 | if (!CI) CI = CQ; | |
708 | CR = tgetstr("cR", &capbuf); | |
709 | if (!CR) CR = CQ; | |
710 | } | |
711 | # ifndef CRUNCH | |
712 | else | |
713 | { | |
714 | CQ = CV = ""; | |
715 | pair(&CQ, &CV, "ve", "vs"); | |
716 | CX = CI = CR = CQ; | |
717 | } | |
718 | # endif /* !CRUNCH */ | |
719 | #endif /* !NO_CURSORSHAPE */ | |
720 | ||
721 | #ifndef NO_COLOR | |
722 | strcpy(SOcolor, SO); | |
723 | strcpy(SEcolor, SE); | |
724 | strcpy(AScolor, AS); | |
725 | strcpy(AEcolor, AE); | |
726 | strcpy(MDcolor, MD); | |
727 | strcpy(MEcolor, ME); | |
728 | strcpy(UScolor, US); | |
729 | strcpy(UEcolor, UE); | |
730 | # ifndef NO_POPUP | |
731 | strcpy(POPUPcolor, SO); | |
732 | # endif | |
733 | # ifndef NO_VISIBLE | |
734 | strcpy(VISIBLEcolor, MV); | |
735 | # endif | |
736 | #endif | |
737 | ||
738 | } | |
739 | ||
740 | ||
741 | /* This function gets the window size. It uses the TIOCGWINSZ ioctl call if | |
742 | * your system has it, or tgetnum("li") and tgetnum("co") if it doesn't. | |
743 | * This function is called once during initialization, and thereafter it is | |
744 | * called whenever the SIGWINCH signal is sent to this process. | |
745 | */ | |
746 | int getsize(signo) | |
747 | int signo; | |
748 | { | |
749 | int lines; | |
750 | int cols; | |
751 | #ifdef TIOCGWINSZ | |
752 | struct winsize size; | |
753 | #endif | |
754 | ||
755 | #ifdef SIGWINCH | |
756 | /* reset the signal vector */ | |
78ed81a3 | 757 | signal(SIGWINCH, (void *)getsize); |
15637ed4 RG |
758 | #endif |
759 | ||
760 | /* get the window size, one way or another. */ | |
761 | lines = cols = 0; | |
762 | #ifdef TIOCGWINSZ | |
763 | if (ioctl(2, TIOCGWINSZ, &size) >= 0) | |
764 | { | |
765 | lines = size.ws_row; | |
766 | cols = size.ws_col; | |
767 | } | |
768 | #endif | |
769 | #if AMIGA | |
770 | /* Amiga gets window size by asking the console.device */ | |
771 | if (!strcmp(TERMTYPE, termtype)) | |
772 | { | |
773 | auto long len; | |
774 | auto char buf[30]; | |
775 | ||
776 | Write(Output(), "\2330 q", 4); /* Ask the console.device */ | |
777 | len = Read(Input(), buf, 29); | |
778 | buf[len] = '\000'; | |
779 | sscanf(&buf[5], "%d;%d", &lines, &cols); | |
780 | } | |
781 | #endif | |
782 | if ((lines == 0 || cols == 0) && signo == 0) | |
783 | { | |
784 | LINES = tgetnum("li"); | |
785 | COLS = tgetnum("co"); | |
786 | } | |
787 | #if MSDOS | |
788 | # ifdef RAINBOW | |
789 | if (!strcmp(termtype, "rainbow")) | |
790 | { | |
791 | /* Determine whether Rainbow is in 80-column or 132-column mode */ | |
792 | cols = *(unsigned char far *)0xee000f57L; | |
793 | } | |
794 | else | |
795 | # endif | |
796 | { | |
797 | lines = v_rows(); | |
798 | cols = v_cols(); | |
799 | } | |
800 | #endif | |
801 | if (lines >= 2 && cols >= 30) | |
802 | { | |
803 | LINES = lines; | |
804 | COLS = cols; | |
805 | } | |
806 | ||
807 | /* Make sure we got values that we can live with */ | |
808 | if (LINES < 2 || COLS < 30) | |
809 | { | |
810 | write(2, "Screen too small\n", (unsigned)17); | |
811 | #if OSK | |
812 | write(2, "\l", 1); | |
813 | #endif | |
814 | endwin(); | |
815 | exit(2); | |
816 | } | |
817 | ||
818 | #if AMIGA | |
819 | if (*o_lines != LINES || *o_columns != COLS) | |
820 | { | |
821 | *o_lines = LINES; | |
822 | *o_columns = COLS; | |
823 | } | |
824 | #endif | |
825 | ||
826 | return 0; | |
827 | } | |
828 | ||
829 | ||
830 | /* This is a function version of addch() -- it is used by tputs() */ | |
831 | int faddch(ch) | |
832 | int ch; | |
833 | { | |
834 | addch(ch); | |
835 | ||
836 | return 0; | |
837 | } | |
838 | ||
839 | /* This function quickly adds a string to the output queue. It does *NOT* | |
840 | * convert \n into <CR><LF>. | |
841 | */ | |
842 | void qaddstr(str) | |
843 | char *str; | |
844 | { | |
845 | REG char *s_, *d_; | |
846 | ||
847 | #if MSDOS | |
848 | if (o_pcbios[0]) | |
849 | { | |
850 | while (*str) | |
851 | qaddch(*str++); | |
852 | return; | |
853 | } | |
854 | #endif | |
855 | for (s_=(str), d_=stdscr; *d_++ = *s_++; ) | |
856 | { | |
857 | } | |
858 | stdscr = d_ - 1; | |
859 | } | |
860 | ||
861 | /* Output the ESC sequence needed to go into any video mode, if supported */ | |
862 | void attrset(a) | |
863 | int a; | |
864 | { | |
865 | do_aend(); | |
866 | if (a == A_BOLD) | |
867 | { | |
868 | do_MD(); | |
869 | aend = ME; | |
870 | } | |
871 | else if (a == A_UNDERLINE) | |
872 | { | |
873 | do_US(); | |
874 | aend = UE; | |
875 | } | |
876 | else if (a == A_ALTCHARSET) | |
877 | { | |
878 | do_AS(); | |
879 | aend = AE; | |
880 | } | |
881 | else | |
882 | { | |
883 | aend = ""; | |
884 | } | |
885 | } | |
886 | ||
887 | ||
888 | /* Insert a single character into the display */ | |
889 | void insch(ch) | |
890 | int ch; | |
891 | { | |
892 | if (has_IM) | |
893 | do_IM(); | |
894 | do_IC(); | |
895 | qaddch(ch); | |
896 | if (has_EI) | |
897 | do_EI(); | |
898 | } | |
899 | ||
900 | void wrefresh() | |
901 | { | |
902 | if (stdscr != kbuf) | |
903 | { | |
904 | VOIDBIOS(;,ttywrite(kbuf, (unsigned)(stdscr - kbuf))); | |
905 | stdscr = kbuf; | |
906 | } | |
907 | } | |
908 | ||
909 | void wqrefresh() | |
910 | { | |
911 | if (stdscr - kbuf > 2000) | |
912 | { | |
913 | VOIDBIOS(stdscr = kbuf, | |
914 | { | |
915 | ttywrite(kbuf, (unsigned)(stdscr - kbuf)); | |
916 | stdscr = kbuf; | |
917 | }); | |
918 | } | |
919 | } | |
920 | ||
921 | #ifndef NO_COLOR | |
922 | /* This function is called during termination. It resets color modes */ | |
923 | int ansiquit() | |
924 | { | |
78ed81a3 | 925 | /* if ANSI terminal & colors were set, then reset the colors */ |
926 | if (!strcmp(UP, "\033[A") && strcmp(SOcolor, SO)) | |
15637ed4 RG |
927 | { |
928 | tputs("\033[37;40m\033[m", 1, faddch); | |
929 | clrtoeol(); | |
930 | return 1; | |
931 | } | |
932 | return 0; | |
933 | } | |
934 | ||
935 | /* This sets the color strings that work for ANSI terminals. If the TERMCAP | |
936 | * doesn't look like an ANSI terminal, then it returns FALSE. If the colors | |
937 | * aren't understood, it also returns FALSE. If all goes well, it returns TRUE | |
938 | */ | |
939 | int ansicolor(cmode, attrbyte) | |
940 | int cmode; /* mode to set, e.g. A_NORMAL */ | |
941 | int attrbyte; /* IBM PC attribute byte */ | |
942 | { | |
78ed81a3 | 943 | char temp[24]; /* hold the new mode string */ |
15637ed4 RG |
944 | |
945 | /* if not ANSI-ish, then fail */ | |
946 | if (strcmp(UP, "\033[A") && strcmp(UP, "\033OA")) | |
947 | { | |
78ed81a3 | 948 | /* Only give an error message if we're editing a file. |
949 | * (I.e., if we're *NOT* currently doing a ".exrc") | |
950 | */ | |
951 | if (tmpfd >= 0) | |
952 | msg("Don't know how to set colors for this terminal"); | |
953 | return FALSE; | |
15637ed4 RG |
954 | } |
955 | ||
956 | /* construct the color string */ | |
78ed81a3 | 957 | #ifdef MWC /* either Coherent-286 ("COHERENT"), or Coherent-386 ("M_SYSV") */ |
958 | sprintf(temp, "\033[m\033[3%cm\033[4%cm%s%s", | |
959 | "04261537"[attrbyte & 0x07], | |
960 | "04261537"[(attrbyte >> 4) & 0x07], | |
961 | (attrbyte & 0x08) ? "\033[1m" : "", | |
962 | (attrbyte & 0x80) ? "\033[5m" : ""); | |
963 | #else | |
15637ed4 RG |
964 | sprintf(temp, "\033[m\033[3%c;4%c%s%sm", |
965 | "04261537"[attrbyte & 0x07], | |
966 | "04261537"[(attrbyte >> 4) & 0x07], | |
967 | (attrbyte & 0x08) ? ";1" : "", | |
968 | (attrbyte & 0x80) ? ";5" : ""); | |
78ed81a3 | 969 | #endif |
15637ed4 RG |
970 | |
971 | /* stick it in the right place */ | |
972 | switch (cmode) | |
973 | { | |
974 | case A_NORMAL: | |
975 | if (!strcmp(MEcolor, normalcolor)) | |
976 | strcpy(MEcolor, temp); | |
977 | if (!strcmp(UEcolor, normalcolor)) | |
978 | strcpy(UEcolor, temp); | |
979 | if (!strcmp(AEcolor, normalcolor)) | |
980 | strcpy(AEcolor, temp); | |
981 | if (!strcmp(SEcolor, normalcolor)) | |
982 | strcpy(SEcolor, temp); | |
983 | ||
984 | strcpy(normalcolor, temp); | |
985 | tputs(normalcolor, 1, faddch); | |
986 | break; | |
987 | ||
988 | case A_BOLD: | |
989 | strcpy(MDcolor, temp); | |
990 | strcpy(MEcolor, normalcolor); | |
991 | break; | |
992 | ||
993 | case A_UNDERLINE: | |
994 | strcpy(UScolor, temp); | |
995 | strcpy(UEcolor, normalcolor); | |
996 | break; | |
997 | ||
998 | case A_ALTCHARSET: | |
999 | strcpy(AScolor, temp); | |
1000 | strcpy(AEcolor, normalcolor); | |
1001 | break; | |
1002 | ||
1003 | case A_STANDOUT: | |
1004 | strcpy(SOcolor, temp); | |
1005 | strcpy(SEcolor, normalcolor); | |
1006 | break; | |
1007 | ||
1008 | #ifndef NO_POPUP | |
1009 | case A_POPUP: | |
1010 | strcpy(POPUPcolor, temp); | |
1011 | break; | |
1012 | #endif | |
1013 | ||
1014 | #ifndef NO_VISIBLE | |
1015 | case A_VISIBLE: | |
1016 | strcpy(VISIBLEcolor, temp); | |
1017 | break; | |
1018 | #endif | |
1019 | } | |
1020 | ||
78ed81a3 | 1021 | return TRUE; |
15637ed4 RG |
1022 | } |
1023 | ||
1024 | ||
1025 | /* This function outputs the ESC sequence needed to switch the screen back | |
1026 | * to "normal" mode. On color terminals which haven't had their color set | |
1027 | * yet, this is one of the termcap strings; for color terminals that really | |
1028 | * have had colors defined, we just the "normal color" escape sequence. | |
1029 | */ | |
78ed81a3 | 1030 | int |
15637ed4 RG |
1031 | endcolor() |
1032 | { | |
1033 | if (aend == ME) | |
1034 | tputs(MEcolor, 1, faddch); | |
1035 | else if (aend == UE) | |
1036 | tputs(UEcolor, 1, faddch); | |
1037 | else if (aend == AE) | |
1038 | tputs(AEcolor, 1, faddch); | |
1039 | else if (aend == SE) | |
1040 | tputs(SEcolor, 1, faddch); | |
1041 | aend = ""; | |
1042 | return 0; | |
1043 | } | |
1044 | ||
1045 | ||
1046 | #endif /* !NO_COLOR */ |