* Fix of the list of files in the browser for terminals that need to erase
[alpine.git] / pico / osdep / terminal.c
blob3630952049a53515657cadbc867b478c6f195072
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: terminal.c 921 2008-01-31 02:09:25Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2008 University of Washington
8 * Copyright 2013-2021 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
18 * Program: Display routines
21 #include <system.h>
22 #include <general.h>
25 #include "../estruct.h"
26 #include "../keydefs.h"
27 #include "../pico.h"
28 #include "../mode.h"
30 #include "raw.h"
31 #include "color.h"
32 #include "tty.h"
33 #include "terminal.h"
34 #include "getkey.h"
36 #ifndef _WINDOWS
37 extern long gmode;
41 * Useful Defaults
43 #define MARGIN 8 /* size of minimim margin and */
44 #define MROW 2 /* rows in menu */
47 /* any special properties of the current terminal */
48 unsigned term_capabilities = (TT_EOLEXIST | TT_SCROLLEXIST | TT_INSCHAR | TT_DELCHAR);
54 unsigned
55 tthascap(void)
57 return(term_capabilities);
61 #if HAS_TERMINFO
64 * terminfo-based terminal i/o and control routines
68 /* internal prototypes */
69 static int tinfomove(int, int);
70 static int tinfoeeol(void);
71 static int tinfoeeop(void);
72 static int tinfobeep(void);
73 static int tinforev(int);
74 static int tinfoeri(void);
75 static int tinfoopen(void);
76 static int tinfoterminalinfo(int);
77 static int tinfoclose(void);
78 static void setup_dflt_esc_seq(void);
79 static void tinfoinsert(UCS);
80 static void tinfodelete(void);
82 extern int tput();
83 extern int tputs(char *, int, int (*)(int));
84 extern char *tgoto(char *, int, int);
85 extern char *tigetstr (char *);
86 extern int setupterm(char *, int, int *);
87 extern int tigetnum(char *);
88 extern int tigetflag(char *);
90 /**
91 ** Note: The tgoto calls should really be replaced by tparm calls for
92 ** modern terminfo. tgoto(s, x, y) == tparm(s, y, x).
93 **/
95 int _tlines, _tcolumns;
96 char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
97 *_setinverse, *_clearinverse,
98 *_setunderline, *_clearunderline,
99 *_setbold, *_clearallattr, /* there is no clear only bold! */
100 *_cleartoeoln, *_cleartoeos,
101 *_deleteline, /* delete line */
102 *_insertline, /* insert line */
103 *_scrollregion, /* define a scrolling region, vt100 */
104 *_insertchar, /* insert character, preferable to : */
105 *_startinsert, /* set insert mode and, */
106 *_endinsert, /* end insert mode */
107 *_deletechar, /* delete character */
108 *_startdelete, /* set delete mode and, */
109 *_enddelete, /* end delete mode */
110 *_scrolldown, /* scroll down */
111 *_scrollup, /* scroll up */
112 *_termcap_init, /* string to start termcap */
113 *_termcap_end, /* string to end termcap */
114 *_op, *_oc, *_setaf, *_setab, *_setf, *_setb, *_scp;
115 int _colors, _pairs, _bce, _xhp;
116 char term_name[40];
118 TERM term = {
119 NROW-1,
120 NCOL,
121 MARGIN,
122 MROW,
123 tinfoopen,
124 tinfoterminalinfo,
125 tinfoclose,
126 ttgetc,
127 ttputc,
128 ttflush,
129 tinfomove,
130 tinfoeeol,
131 tinfoeeop,
132 tinfobeep,
133 tinforev,
134 tinfoeri
139 * Add default keypad sequences to the trie.
141 static void
142 setup_dflt_esc_seq(void)
145 * this is sort of a hack [no kidding], but it allows us to use
146 * the function keys on pc's running telnet
150 * UW-NDC/UCS vt10[02] application mode.
152 kpinsert("\033OP", F1, 1);
153 kpinsert("\033OQ", F2, 1);
154 kpinsert("\033OR", F3, 1);
155 kpinsert("\033OS", F4, 1);
156 kpinsert("\033Op", F5, 1);
157 kpinsert("\033Oq", F6, 1);
158 kpinsert("\033Or", F7, 1);
159 kpinsert("\033Os", F8, 1);
160 kpinsert("\033Ot", F9, 1);
161 kpinsert("\033Ou", F10, 1);
162 kpinsert("\033Ov", F11, 1);
163 kpinsert("\033Ow", F12, 1);
166 * DEC vt100, ANSI and cursor key mode.
168 kpinsert("\033OA", KEY_UP, 1);
169 kpinsert("\033OB", KEY_DOWN, 1);
170 kpinsert("\033OC", KEY_RIGHT, 1);
171 kpinsert("\033OD", KEY_LEFT, 1);
174 * special keypad functions
176 kpinsert("\033[4J", KEY_PGUP, 1);
177 kpinsert("\033[3J", KEY_PGDN, 1);
178 kpinsert("\033[2J", KEY_HOME, 1);
179 kpinsert("\033[N", KEY_END, 1);
182 * vt220?
184 kpinsert("\033[5~", KEY_PGUP, 1);
185 kpinsert("\033[6~", KEY_PGDN, 1);
186 kpinsert("\033[1~", KEY_HOME, 1);
187 kpinsert("\033[4~", KEY_END, 1);
190 * konsole, XTerm (XFree 4.x.x) keyboard setting
192 kpinsert("\033[H", KEY_HOME, 1);
193 kpinsert("\033[F", KEY_END, 1);
196 * gnome-terminal 2.6.0, don't know why it
197 * changed from 2.2.1
199 kpinsert("\033OH", KEY_HOME, 1);
200 kpinsert("\033OF", KEY_END, 1);
203 * "\033[2~" was common for KEY_HOME in a quick survey
204 * of terminals (though typically the Insert key).
205 * Teraterm 2.33 sends the following escape sequences,
206 * which is quite incompatible with everything
207 * else:
208 * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
209 * PgDn: "\033[6~"
210 * The best thing to do would be to fix TeraTerm
211 * keymappings or to tweak terminfo.
215 * ANSI mode.
217 kpinsert("\033[=a", F1, 1);
218 kpinsert("\033[=b", F2, 1);
219 kpinsert("\033[=c", F3, 1);
220 kpinsert("\033[=d", F4, 1);
221 kpinsert("\033[=e", F5, 1);
222 kpinsert("\033[=f", F6, 1);
223 kpinsert("\033[=g", F7, 1);
224 kpinsert("\033[=h", F8, 1);
225 kpinsert("\033[=i", F9, 1);
226 kpinsert("\033[=j", F10, 1);
227 kpinsert("\033[=k", F11, 1);
228 kpinsert("\033[=l", F12, 1);
231 * DEC vt100, ANSI and cursor key mode reset.
233 kpinsert("\033[A", KEY_UP, 1);
234 kpinsert("\033[B", KEY_DOWN, 1);
235 kpinsert("\033[C", KEY_RIGHT, 1);
236 kpinsert("\033[D", KEY_LEFT, 1);
239 * DEC vt52 mode.
241 kpinsert("\033A", KEY_UP, 1);
242 kpinsert("\033B", KEY_DOWN, 1);
243 kpinsert("\033C", KEY_RIGHT, 1);
244 kpinsert("\033D", KEY_LEFT, 1);
247 * DEC vt52 application keys, and some Zenith 19.
249 kpinsert("\033?r", KEY_DOWN, 1);
250 kpinsert("\033?t", KEY_LEFT, 1);
251 kpinsert("\033?v", KEY_RIGHT, 1);
252 kpinsert("\033?x", KEY_UP, 1);
255 * Some Ctrl-Arrow keys
257 kpinsert("\033[5A", CTRL_KEY_UP, 1);
258 kpinsert("\033[5B", CTRL_KEY_DOWN, 1);
259 kpinsert("\033[5C", CTRL_KEY_RIGHT, 1);
260 kpinsert("\033[5D", CTRL_KEY_LEFT, 1);
262 kpinsert("\033[1;5A", CTRL_KEY_UP, 1);
263 kpinsert("\033[1;5B", CTRL_KEY_DOWN, 1);
264 kpinsert("\033[1;5C", CTRL_KEY_RIGHT, 1);
265 kpinsert("\033[1;5D", CTRL_KEY_LEFT, 1);
268 * Map some shift+up/down/left/right to their shiftless counterparts
270 kpinsert("\033[1;2A", KEY_UP, 1);
271 kpinsert("\033[1;2B", KEY_DOWN, 1);
272 kpinsert("\033[1;2C", KEY_RIGHT, 1);
273 kpinsert("\033[1;2D", KEY_LEFT, 1);
274 kpinsert("\033[a", KEY_UP, 1);
275 kpinsert("\033[b", KEY_DOWN, 1);
276 kpinsert("\033[c", KEY_RIGHT, 1);
277 kpinsert("\033[d", KEY_LEFT, 1);
280 * Sun Console sequences.
282 kpinsert("\033[1", KEY_SWALLOW_Z, 1);
283 kpinsert("\033[215", KEY_SWAL_UP, 1);
284 kpinsert("\033[217", KEY_SWAL_LEFT, 1);
285 kpinsert("\033[219", KEY_SWAL_RIGHT, 1);
286 kpinsert("\033[221", KEY_SWAL_DOWN, 1);
289 * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
291 kpinsert("\033_", KEY_KERMIT, 1);
294 * Fake a control character.
296 kpinsert("\033\033", KEY_DOUBLE_ESC, 1);
300 static int
301 tinfoterminalinfo(int termcap_wins)
303 char *_ku, *_kd, *_kl, *_kr,
304 *_kppu, *_kppd, *_kphome, *_kpend, *_kpdel,
305 *_kf1, *_kf2, *_kf3, *_kf4, *_kf5, *_kf6,
306 *_kf7, *_kf8, *_kf9, *_kf10, *_kf11, *_kf12;
307 char *ttnm;
309 if (Pmaster) {
311 * setupterm() automatically retrieves the value
312 * of the TERM variable.
314 int err;
315 ttnm = getenv("TERM");
316 if(!ttnm)
317 return(-1);
319 strncpy(term_name, ttnm, sizeof(term_name));
320 term_name[sizeof(term_name)-1] = '\0';
321 setupterm ((char *) 0, 1, &err);
322 if (err != 1) return(err-2);
324 else {
326 * setupterm() issues a message and exits, if the
327 * terminfo data base is gone or the term type is
328 * unknown, if arg2 is 0.
330 setupterm ((char *) 0, 1, (int *) 0);
333 _clearscreen = tigetstr("clear");
334 _moveto = tigetstr("cup");
335 _up = tigetstr("cuu1");
336 _down = tigetstr("cud1");
337 _right = tigetstr("cuf1");
338 _left = tigetstr("cub1");
339 _setinverse = tigetstr("smso");
340 _clearinverse = tigetstr("rmso");
341 _setunderline = tigetstr("smul");
342 _clearunderline = tigetstr("rmul");
343 _setbold = tigetstr("bold");
344 _clearallattr = tigetstr("sgr0");
345 _cleartoeoln = tigetstr("el");
346 _cleartoeos = tigetstr("ed");
347 _deletechar = tigetstr("dch1");
348 _insertchar = tigetstr("ich1");
349 _startinsert = tigetstr("smir");
350 _endinsert = tigetstr("rmir");
351 _deleteline = tigetstr("dl1");
352 _insertline = tigetstr("il1");
353 _scrollregion = tigetstr("csr");
354 _scrolldown = tigetstr("ind");
355 _scrollup = tigetstr("ri");
356 _termcap_init = tigetstr("smcup");
357 _termcap_end = tigetstr("rmcup");
358 _startdelete = tigetstr("smdc");
359 _enddelete = tigetstr("rmdc");
360 _ku = tigetstr("kcuu1");
361 _kd = tigetstr("kcud1");
362 _kl = tigetstr("kcub1");
363 _kr = tigetstr("kcuf1");
364 _kppu = tigetstr("kpp");
365 _kppd = tigetstr("knp");
366 _kphome = tigetstr("khome");
367 _kpend = tigetstr("kend");
368 _kpdel = tigetstr("kdch1");
369 _kf1 = tigetstr("kf1");
370 _kf2 = tigetstr("kf2");
371 _kf3 = tigetstr("kf3");
372 _kf4 = tigetstr("kf4");
373 _kf5 = tigetstr("kf5");
374 _kf6 = tigetstr("kf6");
375 _kf7 = tigetstr("kf7");
376 _kf8 = tigetstr("kf8");
377 _kf9 = tigetstr("kf9");
378 _kf10 = tigetstr("kf10");
379 _kf11 = tigetstr("kf11");
380 _kf12 = tigetstr("kf12");
382 _colors = tigetnum("colors");
383 _pairs = tigetnum("pairs");
384 _setaf = tigetstr("setaf");
385 _setab = tigetstr("setab");
386 _setf = tigetstr("setf");
387 _setb = tigetstr("setb");
388 _scp = tigetstr("scp");
389 _op = tigetstr("op");
390 _oc = tigetstr("oc");
391 _bce = tigetflag("bce");
392 _xhp = tigetflag("xhp");
394 _tlines = tigetnum("lines");
395 if(_tlines == -1){
396 char *er;
397 int rr;
399 /* tigetnum failed, try $LINES */
400 er = getenv("LINES");
401 if(er && (rr = atoi(er)) > 0)
402 _tlines = rr;
405 _tcolumns = tigetnum("cols");
406 if(_tcolumns == -1){
407 char *ec;
408 int cc;
410 /* tigetnum failed, try $COLUMNS */
411 ec = getenv("COLUMNS");
412 if(ec && (cc = atoi(ec)) > 0)
413 _tcolumns = cc;
417 * Add default keypad sequences to the trie.
418 * Since these come first, they will override any conflicting termcap
419 * or terminfo escape sequences defined below. An escape sequence is
420 * considered conflicting if one is a prefix of the other.
421 * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
422 * escape sequences that don't work, because they conflict with default
423 * sequences defined here.
425 if(!termcap_wins)
426 setup_dflt_esc_seq();
429 * add termcap/info escape sequences to the trie...
432 if(_ku != NULL && _kd != NULL && _kl != NULL && _kr != NULL){
433 kpinsert(_ku, KEY_UP, termcap_wins);
434 kpinsert(_kd, KEY_DOWN, termcap_wins);
435 kpinsert(_kl, KEY_LEFT, termcap_wins);
436 kpinsert(_kr, KEY_RIGHT, termcap_wins);
439 if(_kppu != NULL && _kppd != NULL){
440 kpinsert(_kppu, KEY_PGUP, termcap_wins);
441 kpinsert(_kppd, KEY_PGDN, termcap_wins);
444 kpinsert(_kphome, KEY_HOME, termcap_wins);
445 kpinsert(_kpend, KEY_END, termcap_wins);
446 kpinsert(_kpdel, KEY_DEL, termcap_wins);
448 kpinsert(_kf1, F1, termcap_wins);
449 kpinsert(_kf2, F2, termcap_wins);
450 kpinsert(_kf3, F3, termcap_wins);
451 kpinsert(_kf4, F4, termcap_wins);
452 kpinsert(_kf5, F5, termcap_wins);
453 kpinsert(_kf6, F6, termcap_wins);
454 kpinsert(_kf7, F7, termcap_wins);
455 kpinsert(_kf8, F8, termcap_wins);
456 kpinsert(_kf9, F9, termcap_wins);
457 kpinsert(_kf10, F10, termcap_wins);
458 kpinsert(_kf11, F11, termcap_wins);
459 kpinsert(_kf12, F12, termcap_wins);
462 * Add default keypad sequences to the trie.
463 * Since these come after the termcap/terminfo escape sequences above,
464 * the termcap/info sequences will override any conflicting default
465 * escape sequences defined here.
466 * So, with TERMCAP_WINS, some of the default sequences will be missing.
467 * This means that you'd better get all of your termcap/terminfo entries
468 * correct if you define TERMCAP_WINS.
470 if(termcap_wins)
471 setup_dflt_esc_seq();
473 if(Pmaster)
474 return(0);
475 else
476 return(TRUE);
479 static int
480 tinfoopen(void)
482 int row, col;
485 * determine the terminal's communication speed and decide
486 * if we need to do optimization ...
488 if(ttisslow())
489 term_capabilities |= TT_OPTIMIZE;
491 col = _tcolumns;
492 row = _tlines;
493 if(row >= 0)
494 row--;
496 ttgetwinsz(&row, &col);
497 term.t_nrow = (short) row;
498 term.t_ncol = (short) col;
500 if(_cleartoeoln != NULL) /* able to use clear to EOL? */
501 term_capabilities |= TT_EOLEXIST;
502 else
503 term_capabilities &= ~TT_EOLEXIST;
505 if(_setinverse != NULL)
506 term_capabilities |= TT_REVEXIST;
507 else
508 term_capabilities &= ~TT_REVEXIST;
510 if(_deletechar == NULL && (_startdelete == NULL || _enddelete == NULL))
511 term_capabilities &= ~TT_DELCHAR;
513 if(_insertchar == NULL && (_startinsert == NULL || _endinsert == NULL))
514 term_capabilities &= ~TT_INSCHAR;
516 if((_scrollregion == NULL || _scrolldown == NULL || _scrollup == NULL)
517 && (_deleteline == NULL || _insertline == NULL))
518 term_capabilities &= ~TT_SCROLLEXIST;
520 if(_clearscreen == NULL || _moveto == NULL || _up == NULL){
521 if(Pmaster == NULL){
522 puts("Incomplete terminfo entry\n");
523 exit(1);
527 ttopen();
529 if(_termcap_init && !Pmaster) {
530 putpad(_termcap_init); /* any init terminfo requires */
531 if (_scrollregion)
532 putpad(tgoto(_scrollregion, term.t_nrow, 0)) ;
536 * Initialize UW-modified NCSA telnet to use its functionkeys
538 if((gmode & MDFKEY) && Pmaster == NULL)
539 puts("\033[99h");
541 /* return ignored */
542 return(0);
546 static int
547 tinfoclose(void)
549 if(!Pmaster){
550 if(gmode&MDFKEY)
551 puts("\033[99l"); /* reset UW-NCSA telnet keys */
553 if(_termcap_end) /* any clean up terminfo requires */
554 putpad(_termcap_end);
557 ttclose();
559 /* return ignored */
560 return(0);
565 * tinfoinsert - insert a character at the current character position.
566 * _insertchar takes precedence.
568 static void
569 tinfoinsert(UCS ch)
571 if(_insertchar != NULL){
572 putpad(_insertchar);
573 ttputc(ch);
575 else{
576 putpad(_startinsert);
577 ttputc(ch);
578 putpad(_endinsert);
584 * tinfodelete - delete a character at the current character position.
586 static void
587 tinfodelete(void)
589 if(_startdelete == NULL && _enddelete == NULL)
590 putpad(_deletechar);
591 else{
592 putpad(_startdelete);
593 putpad(_deletechar);
594 putpad(_enddelete);
600 * o_scrolldown() - open a line at the given row position.
601 * use either region scrolling or deleteline/insertline
602 * to open a new line.
605 o_scrolldown(int row, int n)
607 register int i;
609 if(_scrollregion != NULL){
610 putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
611 tinfomove(row, 0);
612 for(i = 0; i < n; i++)
613 putpad((_scrollup != NULL && *_scrollup != '\0') ? _scrollup : "\n" );
614 putpad(tgoto(_scrollregion, term.t_nrow, 0));
615 tinfomove(row, 0);
617 else{
619 * this code causes a jiggly motion of the keymenu when scrolling
621 for(i = 0; i < n; i++){
622 tinfomove(term.t_nrow - (term.t_mrow+1), 0);
623 putpad(_deleteline);
624 tinfomove(row, 0);
625 putpad(_insertline);
627 #ifdef NOWIGGLYLINES
629 * this code causes a sweeping motion up and down the display
631 tinfomove(term.t_nrow - term.t_mrow - n, 0);
632 for(i = 0; i < n; i++)
633 putpad(_deleteline);
634 tinfomove(row, 0);
635 for(i = 0; i < n; i++)
636 putpad(_insertline);
637 #endif
640 /* return ignored */
641 return(0);
646 * o_scrollup() - open a line at the given row position.
647 * use either region scrolling or deleteline/insertline
648 * to open a new line.
651 o_scrollup(int row, int n)
653 register int i;
655 if(_scrollregion != NULL){
656 putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
657 /* setting scrolling region moves cursor to home */
658 tinfomove(term.t_nrow-(term.t_mrow+1), 0);
659 for(i = 0;i < n; i++)
660 putpad((_scrolldown == NULL || _scrolldown[0] == '\0') ? "\n"
661 : _scrolldown);
662 putpad(tgoto(_scrollregion, term.t_nrow, 0));
663 tinfomove(2, 0);
665 else{
666 for(i = 0; i < n; i++){
667 tinfomove(row, 0);
668 putpad(_deleteline);
669 tinfomove(term.t_nrow - (term.t_mrow+1), 0);
670 putpad(_insertline);
672 #ifdef NOWIGGLYLINES
673 /* see note above */
674 tinfomove(row, 0);
675 for(i = 0; i < n; i++)
676 putpad(_deleteline);
677 tinfomove(term.t_nrow - term.t_mrow - n, 0);
678 for(i = 0;i < n; i++)
679 putpad(_insertline);
680 #endif
683 /* return ignored */
684 return(0);
690 * o_insert - use terminfo to optimized character insert
691 * returns: true if it optimized output, false otherwise
694 o_insert(UCS c)
696 if(term_capabilities & TT_INSCHAR){
697 tinfoinsert(c);
698 return(1); /* no problems! */
701 return(0); /* can't do it. */
706 * o_delete - use terminfo to optimized character insert
707 * returns true if it optimized output, false otherwise
710 o_delete(void)
712 if(term_capabilities & TT_DELCHAR){
713 tinfodelete();
714 return(1); /* deleted, no problem! */
717 return(0); /* no dice. */
721 static int
722 tinfomove(int row, int col)
724 putpad(tgoto(_moveto, col, row));
726 /* return ignored */
727 return(0);
731 static int
732 tinfoeeol(void)
734 int c, starting_col, starting_line;
735 char *last_bg_color;
738 * If the terminal doesn't have back color erase, then we have to
739 * erase manually to preserve the background color.
741 if(pico_usingcolor() && (!_bce || !_cleartoeoln)){
742 extern int ttcol, ttrow;
744 starting_col = ttcol;
745 starting_line = ttrow;
746 last_bg_color = pico_get_last_bg_color();
747 pico_set_nbg_color();
748 for(c = ttcol; c < term.t_ncol; c++)
749 ttputc(' ');
751 tinfomove(starting_line, starting_col);
752 if(last_bg_color){
753 pico_set_bg_color(last_bg_color);
754 free(last_bg_color);
757 else if(_cleartoeoln)
758 putpad(_cleartoeoln);
760 /* return ignored */
761 return(0);
765 static int
766 tinfoeeop(void)
768 int i, starting_col, starting_row;
771 * If the terminal doesn't have back color erase, then we have to
772 * erase manually to preserve the background color.
774 if(pico_usingcolor() && (!_bce || !_cleartoeos)){
775 extern int ttcol, ttrow;
777 starting_col = ttcol;
778 starting_row = ttrow;
779 tinfoeeol(); /* rest of this line */
780 for(i = ttrow+1; i <= term.t_nrow; i++){ /* the remaining lines */
781 tinfomove(i, 0);
782 tinfoeeol();
785 tinfomove(starting_row, starting_col);
787 else if(_cleartoeos)
788 putpad(_cleartoeos);
790 /* return ignored */
791 return(0);
795 static int
796 tinforev(int state) /* change reverse video status */
797 { /* FALSE = normal video, TRUE = rev video */
798 if(state)
799 StartInverse();
800 else
801 EndInverse();
803 return(1);
807 static int
808 tinfoeri(void)
810 if(_xhp && _clearinverse)
811 putpad(_clearinverse);
813 return(1);
817 static int
818 tinfobeep(void)
820 ttputc(BELL);
822 /* return ignored */
823 return(0);
827 void
828 putpad(char *str)
830 tputs(str, 1, putchar);
833 #elif HAS_TERMCAP
836 * termcap-based terminal i/o and control routines
840 /* internal prototypes */
841 static int tcapmove(int, int);
842 static int tcapeeol(void);
843 static int tcapeeop(void);
844 static int tcapbeep(void);
845 static int tcaprev(int);
846 static int tcaperi(void);
847 static int tcapopen(void);
848 static int tcapterminalinfo(int);
849 static int tcapclose(void);
850 static void setup_dflt_esc_seq(void);
851 static void tcapinsert(UCS);
852 static void tcapdelete(void);
854 extern int tput();
855 extern char *tgoto(char *, int, int);
858 * This number used to be 315. No doubt there was a reason for that but we
859 * don't know what it was. It's a bit of a hassle to make it dynamic, and most
860 * modern systems seem to be using terminfo, so we'll just change it to 800.
861 * We weren't stopping on overflow before, so we'll do that, too.
863 #define TCAPSLEN 800
864 char tcapbuf[TCAPSLEN];
865 int _tlines, _tcolumns;
866 char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
867 *_setinverse, *_clearinverse,
868 *_setunderline, *_clearunderline,
869 *_setbold, *_clearallattr, /* there is no clear only bold! */
870 *_cleartoeoln, *_cleartoeos,
871 *_deleteline, /* delete line */
872 *_insertline, /* insert line */
873 *_scrollregion, /* define a scrolling region, vt100 */
874 *_insertchar, /* insert character, preferable to : */
875 *_startinsert, /* set insert mode and, */
876 *_endinsert, /* end insert mode */
877 *_deletechar, /* delete character */
878 *_startdelete, /* set delete mode and, */
879 *_enddelete, /* end delete mode */
880 *_scrolldown, /* scroll down */
881 *_scrollup, /* scroll up */
882 *_termcap_init, /* string to start termcap */
883 *_termcap_end, /* string to end termcap */
884 *_op, *_oc, *_setaf, *_setab, *_setf, *_setb, *_scp;
885 int _colors, _pairs, _bce, _xhp;
886 char term_name[40];
888 TERM term = {
889 NROW-1,
890 NCOL,
891 MARGIN,
892 MROW,
893 tcapopen,
894 tcapterminalinfo,
895 tcapclose,
896 ttgetc,
897 ttputc,
898 ttflush,
899 tcapmove,
900 tcapeeol,
901 tcapeeop,
902 tcapbeep,
903 tcaprev,
904 tcaperi
909 * Add default keypad sequences to the trie.
911 static void
912 setup_dflt_esc_seq(void)
915 * this is sort of a hack, but it allows us to use
916 * the function keys on pc's running telnet
920 * UW-NDC/UCS vt10[02] application mode.
922 kpinsert("\033OP", F1, 1);
923 kpinsert("\033OQ", F2, 1);
924 kpinsert("\033OR", F3, 1);
925 kpinsert("\033OS", F4, 1);
926 kpinsert("\033Op", F5, 1);
927 kpinsert("\033Oq", F6, 1);
928 kpinsert("\033Or", F7, 1);
929 kpinsert("\033Os", F8, 1);
930 kpinsert("\033Ot", F9, 1);
931 kpinsert("\033Ou", F10, 1);
932 kpinsert("\033Ov", F11, 1);
933 kpinsert("\033Ow", F12, 1);
936 * DEC vt100, ANSI and cursor key mode.
938 kpinsert("\033OA", KEY_UP, 1);
939 kpinsert("\033OB", KEY_DOWN, 1);
940 kpinsert("\033OC", KEY_RIGHT, 1);
941 kpinsert("\033OD", KEY_LEFT, 1);
944 * special keypad functions
946 kpinsert("\033[4J", KEY_PGUP, 1);
947 kpinsert("\033[3J", KEY_PGDN, 1);
948 kpinsert("\033[2J", KEY_HOME, 1);
949 kpinsert("\033[N", KEY_END, 1);
952 * vt220?
954 kpinsert("\033[5~", KEY_PGUP, 1);
955 kpinsert("\033[6~", KEY_PGDN, 1);
956 kpinsert("\033[1~", KEY_HOME, 1);
957 kpinsert("\033[4~", KEY_END, 1);
960 * konsole, XTerm (XFree 4.x.x) keyboard setting
962 kpinsert("\033[H", KEY_HOME, 1);
963 kpinsert("\033[F", KEY_END, 1);
966 * gnome-terminal 2.6.0, don't know why it
967 * changed from 2.2.1
969 kpinsert("\033OH", KEY_HOME, 1);
970 kpinsert("\033OF", KEY_END, 1);
973 * "\033[2~" was common for KEY_HOME in a quick survey
974 * of terminals (though typically the Insert key).
975 * Teraterm 2.33 sends the following escape sequences,
976 * which is quite incompatible with everything
977 * else:
978 * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
979 * PgDn: "\033[6~"
980 * The best thing to do would be to fix TeraTerm
981 * keymappings or to tweak terminfo.
985 * ANSI mode.
987 kpinsert("\033[=a", F1, 1);
988 kpinsert("\033[=b", F2, 1);
989 kpinsert("\033[=c", F3, 1);
990 kpinsert("\033[=d", F4, 1);
991 kpinsert("\033[=e", F5, 1);
992 kpinsert("\033[=f", F6, 1);
993 kpinsert("\033[=g", F7, 1);
994 kpinsert("\033[=h", F8, 1);
995 kpinsert("\033[=i", F9, 1);
996 kpinsert("\033[=j", F10, 1);
997 kpinsert("\033[=k", F11, 1);
998 kpinsert("\033[=l", F12, 1);
1001 * DEC vt100, ANSI and cursor key mode reset.
1003 kpinsert("\033[A", KEY_UP, 1);
1004 kpinsert("\033[B", KEY_DOWN, 1);
1005 kpinsert("\033[C", KEY_RIGHT, 1);
1006 kpinsert("\033[D", KEY_LEFT, 1);
1009 * DEC vt52 mode.
1011 kpinsert("\033A", KEY_UP, 1);
1012 kpinsert("\033B", KEY_DOWN, 1);
1013 kpinsert("\033C", KEY_RIGHT, 1);
1014 kpinsert("\033D", KEY_LEFT, 1);
1017 * DEC vt52 application keys, and some Zenith 19.
1019 kpinsert("\033?r", KEY_DOWN, 1);
1020 kpinsert("\033?t", KEY_LEFT, 1);
1021 kpinsert("\033?v", KEY_RIGHT, 1);
1022 kpinsert("\033?x", KEY_UP, 1);
1025 * Some Ctrl-Arrow keys
1027 kpinsert("\033[5A", CTRL_KEY_UP, 1);
1028 kpinsert("\033[5B", CTRL_KEY_DOWN, 1);
1029 kpinsert("\033[5C", CTRL_KEY_RIGHT, 1);
1030 kpinsert("\033[5D", CTRL_KEY_LEFT, 1);
1032 kpinsert("\033[1;5A", CTRL_KEY_UP, 1);
1033 kpinsert("\033[1;5B", CTRL_KEY_DOWN, 1);
1034 kpinsert("\033[1;5C", CTRL_KEY_RIGHT, 1);
1035 kpinsert("\033[1;5D", CTRL_KEY_LEFT, 1);
1038 * Map some shift+up/down/left/right to their shiftless counterparts
1040 kpinsert("\033[1;2A", KEY_UP, 1);
1041 kpinsert("\033[1;2B", KEY_DOWN, 1);
1042 kpinsert("\033[1;2C", KEY_RIGHT, 1);
1043 kpinsert("\033[1;2D", KEY_LEFT, 1);
1044 kpinsert("\033[a", KEY_UP, 1);
1045 kpinsert("\033[b", KEY_DOWN, 1);
1046 kpinsert("\033[c", KEY_RIGHT, 1);
1047 kpinsert("\033[d", KEY_LEFT, 1);
1050 * Sun Console sequences.
1052 kpinsert("\033[1", KEY_SWALLOW_Z, 1);
1053 kpinsert("\033[215", KEY_SWAL_UP, 1);
1054 kpinsert("\033[217", KEY_SWAL_LEFT, 1);
1055 kpinsert("\033[219", KEY_SWAL_RIGHT, 1);
1056 kpinsert("\033[221", KEY_SWAL_DOWN, 1);
1059 * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
1061 kpinsert("\033_", KEY_KERMIT, 1);
1064 * Fake a control character.
1066 kpinsert("\033\033", KEY_DOUBLE_ESC, 1);
1071 * Read termcap and set some global variables. Initialize input trie to
1072 * decode escape sequences.
1074 static int
1075 tcapterminalinfo(int termcap_wins)
1077 char *p, *tgetstr();
1078 char tcbuf[2*1024];
1079 char *tv_stype;
1080 char err_str[72];
1081 int err;
1082 char *_ku, *_kd, *_kl, *_kr,
1083 *_kppu, *_kppd, *_kphome, *_kpend, *_kpdel,
1084 *_kf1, *_kf2, *_kf3, *_kf4, *_kf5, *_kf6,
1085 *_kf7, *_kf8, *_kf9, *_kf10, *_kf11, *_kf12;
1087 if (!(tv_stype = getenv("TERM")) || !strncpy(term_name, tv_stype, sizeof(term_name))){
1088 if(Pmaster){
1089 return(-1);
1091 else{
1092 puts("Environment variable TERM not defined!");
1093 exit(1);
1097 term_name[sizeof(term_name)-1] = '\0';
1099 if((err = tgetent(tcbuf, tv_stype)) != 1){
1100 if(Pmaster){
1101 return(err - 2);
1103 else{
1104 snprintf(err_str, sizeof(err_str), "Unknown terminal type %s!", tv_stype);
1105 puts(err_str);
1106 exit(1);
1110 p = tcapbuf;
1112 _clearscreen = tgetstr("cl", &p);
1113 _moveto = tgetstr("cm", &p);
1114 _up = tgetstr("up", &p);
1115 _down = tgetstr("do", &p);
1116 _right = tgetstr("nd", &p);
1117 _left = tgetstr("bs", &p);
1118 _setinverse = tgetstr("so", &p);
1119 _clearinverse = tgetstr("se", &p);
1120 _setunderline = tgetstr("us", &p);
1121 _clearunderline = tgetstr("ue", &p);
1122 _setbold = tgetstr("md", &p);
1123 _clearallattr = tgetstr("me", &p);
1124 _cleartoeoln = tgetstr("ce", &p);
1125 _cleartoeos = tgetstr("cd", &p);
1126 _deletechar = tgetstr("dc", &p);
1127 _insertchar = tgetstr("ic", &p);
1128 _startinsert = tgetstr("im", &p);
1129 _endinsert = tgetstr("ei", &p);
1130 _deleteline = tgetstr("dl", &p);
1131 _insertline = tgetstr("al", &p);
1132 _scrollregion = tgetstr("cs", &p);
1133 _scrolldown = tgetstr("sf", &p);
1134 _scrollup = tgetstr("sr", &p);
1135 _termcap_init = tgetstr("ti", &p);
1136 _termcap_end = tgetstr("te", &p);
1137 _startdelete = tgetstr("dm", &p);
1138 _enddelete = tgetstr("ed", &p);
1139 _ku = tgetstr("ku", &p);
1140 _kd = tgetstr("kd", &p);
1141 _kl = tgetstr("kl", &p);
1142 _kr = tgetstr("kr", &p);
1143 _kppu = tgetstr("kP", &p);
1144 _kppd = tgetstr("kN", &p);
1145 _kphome = tgetstr("kh", &p);
1146 _kpend = tgetstr("kH", &p);
1147 _kpdel = tgetstr("kD", &p);
1148 _kf1 = tgetstr("k1", &p);
1149 _kf2 = tgetstr("k2", &p);
1150 _kf3 = tgetstr("k3", &p);
1151 _kf4 = tgetstr("k4", &p);
1152 _kf5 = tgetstr("k5", &p);
1153 _kf6 = tgetstr("k6", &p);
1154 _kf7 = tgetstr("k7", &p);
1155 _kf8 = tgetstr("k8", &p);
1156 _kf9 = tgetstr("k9", &p);
1157 if((_kf10 = tgetstr("k;", &p)) == NULL)
1158 _kf10 = tgetstr("k0", &p);
1159 _kf11 = tgetstr("F1", &p);
1160 _kf12 = tgetstr("F2", &p);
1162 _colors = tgetnum("Co");
1163 _pairs = tgetnum("pa");
1164 _setaf = tgetstr("AF", &p);
1165 _setab = tgetstr("AB", &p);
1166 _setf = tgetstr("Sf", &p);
1167 _setb = tgetstr("Sb", &p);
1168 _scp = tgetstr("sp", &p);
1169 _op = tgetstr("op", &p);
1170 _oc = tgetstr("oc", &p);
1171 _bce = tgetflag("ut");
1172 _xhp = tgetflag("xs");
1174 if (p >= &tcapbuf[TCAPSLEN]){
1175 puts("Terminal description too big!\n");
1176 if(Pmaster)
1177 return(-3);
1178 else
1179 exit(1);
1182 _tlines = tgetnum("li");
1183 if(_tlines == -1){
1184 char *er;
1185 int rr;
1187 /* tgetnum failed, try $LINES */
1188 er = getenv("LINES");
1189 if(er && (rr = atoi(er)) > 0)
1190 _tlines = rr;
1193 _tcolumns = tgetnum("co");
1194 if(_tcolumns == -1){
1195 char *ec;
1196 int cc;
1198 /* tgetnum failed, try $COLUMNS */
1199 ec = getenv("COLUMNS");
1200 if(ec && (cc = atoi(ec)) > 0)
1201 _tcolumns = cc;
1205 * Add default keypad sequences to the trie.
1206 * Since these come first, they will override any conflicting termcap
1207 * or terminfo escape sequences defined below. An escape sequence is
1208 * considered conflicting if one is a prefix of the other.
1209 * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
1210 * escape sequences that don't work, because they conflict with default
1211 * sequences defined here.
1213 if(!termcap_wins)
1214 setup_dflt_esc_seq();
1217 * add termcap/info escape sequences to the trie...
1220 if(_ku != NULL && _kd != NULL && _kl != NULL && _kr != NULL){
1221 kpinsert(_ku, KEY_UP, termcap_wins);
1222 kpinsert(_kd, KEY_DOWN, termcap_wins);
1223 kpinsert(_kl, KEY_LEFT, termcap_wins);
1224 kpinsert(_kr, KEY_RIGHT, termcap_wins);
1227 if(_kppu != NULL && _kppd != NULL){
1228 kpinsert(_kppu, KEY_PGUP, termcap_wins);
1229 kpinsert(_kppd, KEY_PGDN, termcap_wins);
1232 kpinsert(_kphome, KEY_HOME, termcap_wins);
1233 kpinsert(_kpend, KEY_END, termcap_wins);
1234 kpinsert(_kpdel, KEY_DEL, termcap_wins);
1236 kpinsert(_kf1, F1, termcap_wins);
1237 kpinsert(_kf2, F2, termcap_wins);
1238 kpinsert(_kf3, F3, termcap_wins);
1239 kpinsert(_kf4, F4, termcap_wins);
1240 kpinsert(_kf5, F5, termcap_wins);
1241 kpinsert(_kf6, F6, termcap_wins);
1242 kpinsert(_kf7, F7, termcap_wins);
1243 kpinsert(_kf8, F8, termcap_wins);
1244 kpinsert(_kf9, F9, termcap_wins);
1245 kpinsert(_kf10, F10, termcap_wins);
1246 kpinsert(_kf11, F11, termcap_wins);
1247 kpinsert(_kf12, F12, termcap_wins);
1250 * Add default keypad sequences to the trie.
1251 * Since these come after the termcap/terminfo escape sequences above,
1252 * the termcap/info sequences will override any conflicting default
1253 * escape sequences defined here.
1254 * So, with TERMCAP_WINS, some of the default sequences will be missing.
1255 * This means that you'd better get all of your termcap/terminfo entries
1256 * correct if you define TERMCAP_WINS.
1258 if(termcap_wins)
1259 setup_dflt_esc_seq();
1261 if(Pmaster)
1262 return(0);
1263 else
1264 return(TRUE);
1267 static int
1268 tcapopen(void)
1270 int row, col;
1273 * determine the terminal's communication speed and decide
1274 * if we need to do optimization ...
1276 if(ttisslow())
1277 term_capabilities |= TT_OPTIMIZE;
1279 col = _tcolumns;
1280 row = _tlines;
1281 if(row >= 0)
1282 row--;
1284 ttgetwinsz(&row, &col);
1285 term.t_nrow = (short) row;
1286 term.t_ncol = (short) col;
1288 if(_cleartoeoln != NULL) /* able to use clear to EOL? */
1289 term_capabilities |= TT_EOLEXIST;
1290 else
1291 term_capabilities &= ~TT_EOLEXIST;
1293 if(_setinverse != NULL)
1294 term_capabilities |= TT_REVEXIST;
1295 else
1296 term_capabilities &= ~TT_REVEXIST;
1298 if(_deletechar == NULL && (_startdelete == NULL || _enddelete == NULL))
1299 term_capabilities &= ~TT_DELCHAR;
1301 if(_insertchar == NULL && (_startinsert == NULL || _endinsert == NULL))
1302 term_capabilities &= ~TT_INSCHAR;
1304 if((_scrollregion == NULL || _scrolldown == NULL || _scrollup == NULL)
1305 && (_deleteline == NULL || _insertline == NULL))
1306 term_capabilities &= ~TT_SCROLLEXIST;
1308 if(_clearscreen == NULL || _moveto == NULL || _up == NULL){
1309 if(Pmaster == NULL){
1310 puts("Incomplete termcap entry\n");
1311 exit(1);
1315 ttopen();
1317 if(_termcap_init && !Pmaster) {
1318 putpad(_termcap_init); /* any init termcap requires */
1319 if (_scrollregion)
1320 putpad(tgoto(_scrollregion, term.t_nrow, 0)) ;
1324 * Initialize UW-modified NCSA telnet to use it's functionkeys
1326 if(gmode&MDFKEY && Pmaster == NULL)
1327 puts("\033[99h");
1329 /* return ignored */
1330 return(0);
1334 static int
1335 tcapclose(void)
1337 if(!Pmaster){
1338 if(gmode&MDFKEY)
1339 puts("\033[99l"); /* reset UW-NCSA telnet keys */
1341 if(_termcap_end) /* any cleanup termcap requires */
1342 putpad(_termcap_end);
1345 ttclose();
1347 /* return ignored */
1348 return(0);
1354 * tcapinsert - insert a character at the current character position.
1355 * _insertchar takes precedence.
1357 static void
1358 tcapinsert(UCS ch)
1360 if(_insertchar != NULL){
1361 putpad(_insertchar);
1362 ttputc(ch);
1364 else{
1365 putpad(_startinsert);
1366 ttputc(ch);
1367 putpad(_endinsert);
1373 * tcapdelete - delete a character at the current character position.
1375 static void
1376 tcapdelete(void)
1378 if(_startdelete == NULL && _enddelete == NULL)
1379 putpad(_deletechar);
1380 else{
1381 putpad(_startdelete);
1382 putpad(_deletechar);
1383 putpad(_enddelete);
1389 * o_scrolldown - open a line at the given row position.
1390 * use either region scrolling or deleteline/insertline
1391 * to open a new line.
1394 o_scrolldown(int row, int n)
1396 register int i;
1398 if(_scrollregion != NULL){
1399 putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
1400 tcapmove(row, 0);
1401 for(i = 0; i < n; i++)
1402 putpad( (_scrollup != NULL && *_scrollup != '\0')
1403 ? _scrollup : "\n" );
1404 putpad(tgoto(_scrollregion, term.t_nrow, 0));
1405 tcapmove(row, 0);
1407 else{
1409 * this code causes a jiggly motion of the keymenu when scrolling
1411 for(i = 0; i < n; i++){
1412 tcapmove(term.t_nrow - (term.t_mrow+1), 0);
1413 putpad(_deleteline);
1414 tcapmove(row, 0);
1415 putpad(_insertline);
1417 #ifdef NOWIGGLYLINES
1419 * this code causes a sweeping motion up and down the display
1421 tcapmove(term.t_nrow - term.t_mrow - n, 0);
1422 for(i = 0; i < n; i++)
1423 putpad(_deleteline);
1424 tcapmove(row, 0);
1425 for(i = 0; i < n; i++)
1426 putpad(_insertline);
1427 #endif
1430 /* return ignored */
1431 return(0);
1436 * o_scrollup - open a line at the given row position.
1437 * use either region scrolling or deleteline/insertline
1438 * to open a new line.
1441 o_scrollup(int row, int n)
1443 register int i;
1445 if(_scrollregion != NULL){
1446 putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
1447 /* setting scrolling region moves cursor to home */
1448 tcapmove(term.t_nrow-(term.t_mrow+1), 0);
1449 for(i = 0;i < n; i++)
1450 putpad((_scrolldown == NULL || _scrolldown[0] == '\0')
1451 ? "\n" : _scrolldown);
1452 putpad(tgoto(_scrollregion, term.t_nrow, 0));
1453 tcapmove(2, 0);
1455 else{
1456 for(i = 0; i < n; i++){
1457 tcapmove(row, 0);
1458 putpad(_deleteline);
1459 tcapmove(term.t_nrow - (term.t_mrow+1), 0);
1460 putpad(_insertline);
1462 #ifdef NOWIGGLYLINES
1463 /* see note above */
1464 tcapmove(row, 0);
1465 for(i = 0; i < n; i++)
1466 putpad(_deleteline);
1467 tcapmove(term.t_nrow - term.t_mrow - n, 0);
1468 for(i = 0;i < n; i++)
1469 putpad(_insertline);
1470 #endif
1473 /* return ignored */
1474 return(0);
1479 * o_insert - use termcap info to optimized character insert
1480 * returns: true if it optimized output, false otherwise
1483 o_insert(UCS c)
1485 if(term_capabilities & TT_INSCHAR){
1486 tcapinsert(c);
1487 return(1); /* no problems! */
1490 return(0); /* can't do it. */
1495 * o_delete - use termcap info to optimized character insert
1496 * returns true if it optimized output, false otherwise
1499 o_delete(void)
1501 if(term_capabilities & TT_DELCHAR){
1502 tcapdelete();
1503 return(1); /* deleted, no problem! */
1506 return(0); /* no dice. */
1510 static int
1511 tcapmove(int row, int col)
1513 putpad(tgoto(_moveto, col, row));
1515 /* return ignored */
1516 return(0);
1520 static int
1521 tcapeeol(void)
1523 int c, starting_col, starting_line;
1524 char *last_bg_color;
1527 * If the terminal doesn't have back color erase, then we have to
1528 * erase manually to preserve the background color.
1530 if(pico_usingcolor() && (!_bce || !_cleartoeoln)){
1531 extern int ttcol, ttrow;
1533 starting_col = ttcol;
1534 starting_line = ttrow;
1535 last_bg_color = pico_get_last_bg_color();
1536 pico_set_nbg_color();
1537 for(c = ttcol; c < term.t_ncol; c++)
1538 ttputc(' ');
1540 tcapmove(starting_line, starting_col);
1541 if(last_bg_color){
1542 pico_set_bg_color(last_bg_color);
1543 free(last_bg_color);
1546 else if(_cleartoeoln)
1547 putpad(_cleartoeoln);
1549 /* return ignored */
1550 return(0);
1554 static int
1555 tcapeeop(void)
1557 int i, starting_col, starting_row;
1560 * If the terminal doesn't have back color erase, then we have to
1561 * erase manually to preserve the background color.
1563 if(pico_usingcolor() && (!_bce || !_cleartoeos)){
1564 extern int ttcol, ttrow;
1566 starting_col = ttcol;
1567 starting_row = ttrow;
1568 tcapeeol(); /* rest of this line */
1569 for(i = ttrow+1; i <= term.t_nrow; i++){ /* the remaining lines */
1570 tcapmove(i, 0);
1571 tcapeeol();
1574 tcapmove(starting_row, starting_col);
1576 else if(_cleartoeos)
1577 putpad(_cleartoeos);
1579 /* return ignored */
1580 return(0);
1584 static int
1585 tcaperi(void)
1587 if(_xhp && _clearinverse)
1588 putpad(_clearinverse);
1590 return(1);
1594 static int
1595 tcaprev(int state) /* change reverse video status */
1596 { /* FALSE = normal video, TRUE = reverse video */
1597 if(state)
1598 StartInverse();
1599 else
1600 EndInverse();
1602 return(1);
1606 static int
1607 tcapbeep(void)
1609 ttputc(BELL);
1611 /* return ignored */
1612 return(0);
1616 void
1617 putpad(char *str)
1619 tputs(str, 1, putchar);
1622 #else /* HARD_CODED_ANSI_TERMINAL */
1625 * ANSI-specific terminal i/o and control routines
1629 #define BEL 0x07 /* BEL character. */
1630 #define ESC 0x1B /* ESC character. */
1633 extern int ttflush();
1635 extern int ansimove(int, int);
1636 extern int ansieeol(void);
1637 extern int ansieeop(void);
1638 extern int ansibeep(void);
1639 extern int ansiparm(int);
1640 extern int ansiopen(void);
1641 extern int ansiterminalinfo(int);
1642 extern int ansirev(int);
1645 * Standard terminal interface dispatch table. Most of the fields point into
1646 * "termio" code.
1648 #if defined(VAX) && !defined(__ALPHA)
1649 globaldef
1650 #endif
1652 TERM term = {
1653 NROW-1,
1654 NCOL,
1655 MARGIN,
1656 MROW,
1657 ansiopen,
1658 ansiterminalinfo,
1659 ttclose,
1660 ttgetc,
1661 ttputc,
1662 ttflush,
1663 ansimove,
1664 ansieeol,
1665 ansieeop,
1666 ansibeep,
1667 ansirev
1671 ansimove(int row, int col)
1673 ttputc(ESC);
1674 ttputc('[');
1675 ansiparm(row+1);
1676 ttputc(';');
1677 ansiparm(col+1);
1678 ttputc('H');
1682 ansieeol(void)
1684 ttputc(ESC);
1685 ttputc('[');
1686 ttputc('K');
1690 ansieeop(void)
1692 ttputc(ESC);
1693 ttputc('[');
1694 ttputc('J');
1698 ansirev(int state) /* change reverse video state */
1699 { /* TRUE = reverse, FALSE = normal */
1700 static int PrevState = 0;
1702 if(state != PrevState) {
1703 PrevState = state ;
1704 ttputc(ESC);
1705 ttputc('[');
1706 ttputc(state ? '7': '0');
1707 ttputc('m');
1712 ansibeep(void)
1714 ttputc(BEL);
1715 ttflush();
1719 ansiparm(int n)
1721 register int q;
1723 q = n/10;
1724 if (q != 0)
1725 ansiparm(q);
1726 ttputc((n%10) + '0');
1731 ansiterminalinfo(int termcap_wins)
1733 #if V7
1734 register char *cp;
1735 char *getenv();
1737 if ((cp = getenv("TERM")) == NULL) {
1738 puts("Shell variable TERM not defined!");
1739 exit(1);
1741 if (strcmp(cp, "vt100") != 0) {
1742 puts("Terminal type not 'vt100'!");
1743 exit(1);
1745 #endif
1746 /* revexist = TRUE; dead code? */
1750 ansiopen(void)
1752 ttopen();
1756 #endif /* HARD_CODED_ANSI_TERMINAL */
1757 #else /* _WINDOWS */
1759 /* These are all just noops in Windows */
1761 unsigned
1762 tthascap(void)
1764 return(0);
1768 * o_insert - optimize screen insert of char c
1771 o_insert(UCS c)
1773 return(0);
1778 * o_delete - optimized character deletion
1781 o_delete(void)
1783 return(0);
1788 #endif /* _WINDOWS */