* Changes in the source code of Alpine to define internal prototypes
[alpine.git] / pico / osdep / terminal.c
blob6150c6fc8839236a316c49d6007f21311a2c5f91
1 /*
2 * ========================================================================
3 * Copyright 2006-2008 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
14 * Program: Display routines
17 #include <system.h>
18 #include <general.h>
21 #include "../estruct.h"
22 #include "../keydefs.h"
23 #include "../pico.h"
24 #include "../mode.h"
26 #include "raw.h"
27 #include "color.h"
28 #include "tty.h"
29 #include "terminal.h"
30 #include "getkey.h"
32 #ifndef _WINDOWS
33 extern long gmode;
37 * Useful Defaults
39 #define MARGIN 8 /* size of minimim margin and */
40 #define MROW 2 /* rows in menu */
43 /* any special properties of the current terminal */
44 unsigned term_capabilities = (TT_EOLEXIST | TT_SCROLLEXIST | TT_INSCHAR | TT_DELCHAR);
50 unsigned
51 tthascap(void)
53 return(term_capabilities);
57 #if HAS_TERMINFO
60 * terminfo-based terminal i/o and control routines
64 /* internal prototypes */
65 static int tinfomove(int, int);
66 static int tinfoeeol(void);
67 static int tinfoeeop(void);
68 static int tinfobeep(void);
69 static int tinforev(int);
70 static int tinfoeri(void);
71 static int tinfoopen(void);
72 static int tinfoterminalinfo(int);
73 static int tinfoclose(void);
74 static void setup_dflt_esc_seq(void);
75 static void tinfoinsert(UCS);
76 static void tinfodelete(void);
78 extern int tput(char);
79 extern int tputs(char *, int, int (*)(int));
80 extern char *tgoto(char *, int, int);
81 extern char *tigetstr (char *);
82 extern int setupterm(char *, int, int *);
83 extern int tigetnum(char *);
84 extern int tigetflag(char *);
86 /**
87 ** Note: The tgoto calls should really be replaced by tparm calls for
88 ** modern terminfo. tgoto(s, x, y) == tparm(s, y, x).
89 **/
91 int _tlines, _tcolumns;
92 char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
93 *_setinverse, *_clearinverse,
94 *_setunderline, *_clearunderline,
95 *_setbold, *_clearallattr, /* there is no clear only bold! */
96 *_cleartoeoln, *_cleartoeos,
97 *_deleteline, /* delete line */
98 *_insertline, /* insert line */
99 *_scrollregion, /* define a scrolling region, vt100 */
100 *_insertchar, /* insert character, preferable to : */
101 *_startinsert, /* set insert mode and, */
102 *_endinsert, /* end insert mode */
103 *_deletechar, /* delete character */
104 *_startdelete, /* set delete mode and, */
105 *_enddelete, /* end delete mode */
106 *_scrolldown, /* scroll down */
107 *_scrollup, /* scroll up */
108 *_termcap_init, /* string to start termcap */
109 *_termcap_end, /* string to end termcap */
110 *_op, *_oc, *_setaf, *_setab, *_setf, *_setb, *_scp;
111 int _colors, _pairs, _bce, _xhp;
112 char term_name[40];
114 TERM term = {
115 NROW-1,
116 NCOL,
117 MARGIN,
118 MROW,
119 tinfoopen,
120 tinfoterminalinfo,
121 tinfoclose,
122 ttgetc,
123 ttputc,
124 ttflush,
125 tinfomove,
126 tinfoeeol,
127 tinfoeeop,
128 tinfobeep,
129 tinforev,
130 tinfoeri
135 * Add default keypad sequences to the trie.
137 static void
138 setup_dflt_esc_seq(void)
141 * this is sort of a hack [no kidding], but it allows us to use
142 * the function keys on pc's running telnet
146 * UW-NDC/UCS vt10[02] application mode.
148 kpinsert("\033OP", F1, 1);
149 kpinsert("\033OQ", F2, 1);
150 kpinsert("\033OR", F3, 1);
151 kpinsert("\033OS", F4, 1);
152 kpinsert("\033Op", F5, 1);
153 kpinsert("\033Oq", F6, 1);
154 kpinsert("\033Or", F7, 1);
155 kpinsert("\033Os", F8, 1);
156 kpinsert("\033Ot", F9, 1);
157 kpinsert("\033Ou", F10, 1);
158 kpinsert("\033Ov", F11, 1);
159 kpinsert("\033Ow", F12, 1);
162 * DEC vt100, ANSI and cursor key mode.
164 kpinsert("\033OA", KEY_UP, 1);
165 kpinsert("\033OB", KEY_DOWN, 1);
166 kpinsert("\033OC", KEY_RIGHT, 1);
167 kpinsert("\033OD", KEY_LEFT, 1);
170 * special keypad functions
172 kpinsert("\033[4J", KEY_PGUP, 1);
173 kpinsert("\033[3J", KEY_PGDN, 1);
174 kpinsert("\033[2J", KEY_HOME, 1);
175 kpinsert("\033[N", KEY_END, 1);
178 * vt220?
180 kpinsert("\033[5~", KEY_PGUP, 1);
181 kpinsert("\033[6~", KEY_PGDN, 1);
182 kpinsert("\033[1~", KEY_HOME, 1);
183 kpinsert("\033[4~", KEY_END, 1);
186 * konsole, XTerm (XFree 4.x.x) keyboard setting
188 kpinsert("\033[H", KEY_HOME, 1);
189 kpinsert("\033[F", KEY_END, 1);
192 * gnome-terminal 2.6.0, don't know why it
193 * changed from 2.2.1
195 kpinsert("\033OH", KEY_HOME, 1);
196 kpinsert("\033OF", KEY_END, 1);
199 * "\033[2~" was common for KEY_HOME in a quick survey
200 * of terminals (though typically the Insert key).
201 * Teraterm 2.33 sends the following escape sequences,
202 * which is quite incompatible with everything
203 * else:
204 * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
205 * PgDn: "\033[6~"
206 * The best thing to do would be to fix TeraTerm
207 * keymappings or to tweak terminfo.
211 * ANSI mode.
213 kpinsert("\033[=a", F1, 1);
214 kpinsert("\033[=b", F2, 1);
215 kpinsert("\033[=c", F3, 1);
216 kpinsert("\033[=d", F4, 1);
217 kpinsert("\033[=e", F5, 1);
218 kpinsert("\033[=f", F6, 1);
219 kpinsert("\033[=g", F7, 1);
220 kpinsert("\033[=h", F8, 1);
221 kpinsert("\033[=i", F9, 1);
222 kpinsert("\033[=j", F10, 1);
223 kpinsert("\033[=k", F11, 1);
224 kpinsert("\033[=l", F12, 1);
227 * DEC vt100, ANSI and cursor key mode reset.
229 kpinsert("\033[A", KEY_UP, 1);
230 kpinsert("\033[B", KEY_DOWN, 1);
231 kpinsert("\033[C", KEY_RIGHT, 1);
232 kpinsert("\033[D", KEY_LEFT, 1);
235 * DEC vt52 mode.
237 kpinsert("\033A", KEY_UP, 1);
238 kpinsert("\033B", KEY_DOWN, 1);
239 kpinsert("\033C", KEY_RIGHT, 1);
240 kpinsert("\033D", KEY_LEFT, 1);
243 * DEC vt52 application keys, and some Zenith 19.
245 kpinsert("\033?r", KEY_DOWN, 1);
246 kpinsert("\033?t", KEY_LEFT, 1);
247 kpinsert("\033?v", KEY_RIGHT, 1);
248 kpinsert("\033?x", KEY_UP, 1);
251 * Some Ctrl-Arrow keys
253 kpinsert("\033[5A", CTRL_KEY_UP, 1);
254 kpinsert("\033[5B", CTRL_KEY_DOWN, 1);
255 kpinsert("\033[5C", CTRL_KEY_RIGHT, 1);
256 kpinsert("\033[5D", CTRL_KEY_LEFT, 1);
258 kpinsert("\033[1;5A", CTRL_KEY_UP, 1);
259 kpinsert("\033[1;5B", CTRL_KEY_DOWN, 1);
260 kpinsert("\033[1;5C", CTRL_KEY_RIGHT, 1);
261 kpinsert("\033[1;5D", CTRL_KEY_LEFT, 1);
264 * Map some shift+up/down/left/right to their shiftless counterparts
266 kpinsert("\033[1;2A", KEY_UP, 1);
267 kpinsert("\033[1;2B", KEY_DOWN, 1);
268 kpinsert("\033[1;2C", KEY_RIGHT, 1);
269 kpinsert("\033[1;2D", KEY_LEFT, 1);
270 kpinsert("\033[a", KEY_UP, 1);
271 kpinsert("\033[b", KEY_DOWN, 1);
272 kpinsert("\033[c", KEY_RIGHT, 1);
273 kpinsert("\033[d", KEY_LEFT, 1);
276 * Sun Console sequences.
278 kpinsert("\033[1", KEY_SWALLOW_Z, 1);
279 kpinsert("\033[215", KEY_SWAL_UP, 1);
280 kpinsert("\033[217", KEY_SWAL_LEFT, 1);
281 kpinsert("\033[219", KEY_SWAL_RIGHT, 1);
282 kpinsert("\033[221", KEY_SWAL_DOWN, 1);
285 * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
287 kpinsert("\033_", KEY_KERMIT, 1);
290 * Fake a control character.
292 kpinsert("\033\033", KEY_DOUBLE_ESC, 1);
296 static int
297 tinfoterminalinfo(int termcap_wins)
299 char *_ku, *_kd, *_kl, *_kr,
300 *_kppu, *_kppd, *_kphome, *_kpend, *_kpdel,
301 *_kf1, *_kf2, *_kf3, *_kf4, *_kf5, *_kf6,
302 *_kf7, *_kf8, *_kf9, *_kf10, *_kf11, *_kf12;
303 char *ttnm;
305 if (Pmaster) {
307 * setupterm() automatically retrieves the value
308 * of the TERM variable.
310 int err;
311 ttnm = getenv("TERM");
312 if(!ttnm)
313 return(-1);
315 strncpy(term_name, ttnm, sizeof(term_name));
316 term_name[sizeof(term_name)-1] = '\0';
317 setupterm ((char *) 0, 1, &err);
318 if (err != 1) return(err-2);
320 else {
322 * setupterm() issues a message and exits, if the
323 * terminfo data base is gone or the term type is
324 * unknown, if arg2 is 0.
326 setupterm ((char *) 0, 1, (int *) 0);
329 _clearscreen = tigetstr("clear");
330 _moveto = tigetstr("cup");
331 _up = tigetstr("cuu1");
332 _down = tigetstr("cud1");
333 _right = tigetstr("cuf1");
334 _left = tigetstr("cub1");
335 _setinverse = tigetstr("smso");
336 _clearinverse = tigetstr("rmso");
337 _setunderline = tigetstr("smul");
338 _clearunderline = tigetstr("rmul");
339 _setbold = tigetstr("bold");
340 _clearallattr = tigetstr("sgr0");
341 _cleartoeoln = tigetstr("el");
342 _cleartoeos = tigetstr("ed");
343 _deletechar = tigetstr("dch1");
344 _insertchar = tigetstr("ich1");
345 _startinsert = tigetstr("smir");
346 _endinsert = tigetstr("rmir");
347 _deleteline = tigetstr("dl1");
348 _insertline = tigetstr("il1");
349 _scrollregion = tigetstr("csr");
350 _scrolldown = tigetstr("ind");
351 _scrollup = tigetstr("ri");
352 _termcap_init = tigetstr("smcup");
353 _termcap_end = tigetstr("rmcup");
354 _startdelete = tigetstr("smdc");
355 _enddelete = tigetstr("rmdc");
356 _ku = tigetstr("kcuu1");
357 _kd = tigetstr("kcud1");
358 _kl = tigetstr("kcub1");
359 _kr = tigetstr("kcuf1");
360 _kppu = tigetstr("kpp");
361 _kppd = tigetstr("knp");
362 _kphome = tigetstr("khome");
363 _kpend = tigetstr("kend");
364 _kpdel = tigetstr("kdch1");
365 _kf1 = tigetstr("kf1");
366 _kf2 = tigetstr("kf2");
367 _kf3 = tigetstr("kf3");
368 _kf4 = tigetstr("kf4");
369 _kf5 = tigetstr("kf5");
370 _kf6 = tigetstr("kf6");
371 _kf7 = tigetstr("kf7");
372 _kf8 = tigetstr("kf8");
373 _kf9 = tigetstr("kf9");
374 _kf10 = tigetstr("kf10");
375 _kf11 = tigetstr("kf11");
376 _kf12 = tigetstr("kf12");
378 _colors = tigetnum("colors");
379 _pairs = tigetnum("pairs");
380 _setaf = tigetstr("setaf");
381 _setab = tigetstr("setab");
382 _setf = tigetstr("setf");
383 _setb = tigetstr("setb");
384 _scp = tigetstr("scp");
385 _op = tigetstr("op");
386 _oc = tigetstr("oc");
387 _bce = tigetflag("bce");
388 _xhp = tigetflag("xhp");
390 _tlines = tigetnum("lines");
391 if(_tlines == -1){
392 char *er;
393 int rr;
395 /* tigetnum failed, try $LINES */
396 er = getenv("LINES");
397 if(er && (rr = atoi(er)) > 0)
398 _tlines = rr;
401 _tcolumns = tigetnum("cols");
402 if(_tcolumns == -1){
403 char *ec;
404 int cc;
406 /* tigetnum failed, try $COLUMNS */
407 ec = getenv("COLUMNS");
408 if(ec && (cc = atoi(ec)) > 0)
409 _tcolumns = cc;
413 * Add default keypad sequences to the trie.
414 * Since these come first, they will override any conflicting termcap
415 * or terminfo escape sequences defined below. An escape sequence is
416 * considered conflicting if one is a prefix of the other.
417 * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
418 * escape sequences that don't work, because they conflict with default
419 * sequences defined here.
421 if(!termcap_wins)
422 setup_dflt_esc_seq();
425 * add termcap/info escape sequences to the trie...
428 if(_ku != NULL && _kd != NULL && _kl != NULL && _kr != NULL){
429 kpinsert(_ku, KEY_UP, termcap_wins);
430 kpinsert(_kd, KEY_DOWN, termcap_wins);
431 kpinsert(_kl, KEY_LEFT, termcap_wins);
432 kpinsert(_kr, KEY_RIGHT, termcap_wins);
435 if(_kppu != NULL && _kppd != NULL){
436 kpinsert(_kppu, KEY_PGUP, termcap_wins);
437 kpinsert(_kppd, KEY_PGDN, termcap_wins);
440 kpinsert(_kphome, KEY_HOME, termcap_wins);
441 kpinsert(_kpend, KEY_END, termcap_wins);
442 kpinsert(_kpdel, KEY_DEL, termcap_wins);
444 kpinsert(_kf1, F1, termcap_wins);
445 kpinsert(_kf2, F2, termcap_wins);
446 kpinsert(_kf3, F3, termcap_wins);
447 kpinsert(_kf4, F4, termcap_wins);
448 kpinsert(_kf5, F5, termcap_wins);
449 kpinsert(_kf6, F6, termcap_wins);
450 kpinsert(_kf7, F7, termcap_wins);
451 kpinsert(_kf8, F8, termcap_wins);
452 kpinsert(_kf9, F9, termcap_wins);
453 kpinsert(_kf10, F10, termcap_wins);
454 kpinsert(_kf11, F11, termcap_wins);
455 kpinsert(_kf12, F12, termcap_wins);
458 * Add default keypad sequences to the trie.
459 * Since these come after the termcap/terminfo escape sequences above,
460 * the termcap/info sequences will override any conflicting default
461 * escape sequences defined here.
462 * So, with TERMCAP_WINS, some of the default sequences will be missing.
463 * This means that you'd better get all of your termcap/terminfo entries
464 * correct if you define TERMCAP_WINS.
466 if(termcap_wins)
467 setup_dflt_esc_seq();
469 if(Pmaster)
470 return(0);
471 else
472 return(TRUE);
475 static int
476 tinfoopen(void)
478 int row, col;
481 * determine the terminal's communication speed and decide
482 * if we need to do optimization ...
484 if(ttisslow())
485 term_capabilities |= TT_OPTIMIZE;
487 col = _tcolumns;
488 row = _tlines;
489 if(row >= 0)
490 row--;
492 ttgetwinsz(&row, &col);
493 term.t_nrow = (short) row;
494 term.t_ncol = (short) col;
496 if(_cleartoeoln != NULL) /* able to use clear to EOL? */
497 term_capabilities |= TT_EOLEXIST;
498 else
499 term_capabilities &= ~TT_EOLEXIST;
501 if(_setinverse != NULL)
502 term_capabilities |= TT_REVEXIST;
503 else
504 term_capabilities &= ~TT_REVEXIST;
506 if(_deletechar == NULL && (_startdelete == NULL || _enddelete == NULL))
507 term_capabilities &= ~TT_DELCHAR;
509 if(_insertchar == NULL && (_startinsert == NULL || _endinsert == NULL))
510 term_capabilities &= ~TT_INSCHAR;
512 if((_scrollregion == NULL || _scrolldown == NULL || _scrollup == NULL)
513 && (_deleteline == NULL || _insertline == NULL))
514 term_capabilities &= ~TT_SCROLLEXIST;
516 if(_clearscreen == NULL || _moveto == NULL || _up == NULL){
517 if(Pmaster == NULL){
518 puts("Incomplete terminfo entry\n");
519 exit(1);
523 ttopen();
525 if(_termcap_init && !Pmaster) {
526 putpad(_termcap_init); /* any init terminfo requires */
527 if (_scrollregion)
528 putpad(tgoto(_scrollregion, term.t_nrow, 0)) ;
532 * Initialize UW-modified NCSA telnet to use its functionkeys
534 if((gmode & MDFKEY) && Pmaster == NULL)
535 puts("\033[99h");
537 /* return ignored */
538 return(0);
542 static int
543 tinfoclose(void)
545 if(!Pmaster){
546 if(gmode&MDFKEY)
547 puts("\033[99l"); /* reset UW-NCSA telnet keys */
549 if(_termcap_end) /* any clean up terminfo requires */
550 putpad(_termcap_end);
553 ttclose();
555 /* return ignored */
556 return(0);
561 * tinfoinsert - insert a character at the current character position.
562 * _insertchar takes precedence.
564 static void
565 tinfoinsert(UCS ch)
567 if(_insertchar != NULL){
568 putpad(_insertchar);
569 ttputc(ch);
571 else{
572 putpad(_startinsert);
573 ttputc(ch);
574 putpad(_endinsert);
580 * tinfodelete - delete a character at the current character position.
582 static void
583 tinfodelete(void)
585 if(_startdelete == NULL && _enddelete == NULL)
586 putpad(_deletechar);
587 else{
588 putpad(_startdelete);
589 putpad(_deletechar);
590 putpad(_enddelete);
596 * o_scrolldown() - open a line at the given row position.
597 * use either region scrolling or deleteline/insertline
598 * to open a new line.
601 o_scrolldown(int row, int n)
603 register int i;
605 if(_scrollregion != NULL){
606 putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
607 tinfomove(row, 0);
608 for(i = 0; i < n; i++)
609 putpad((_scrollup != NULL && *_scrollup != '\0') ? _scrollup : "\n" );
610 putpad(tgoto(_scrollregion, term.t_nrow, 0));
611 tinfomove(row, 0);
613 else{
615 * this code causes a jiggly motion of the keymenu when scrolling
617 for(i = 0; i < n; i++){
618 tinfomove(term.t_nrow - (term.t_mrow+1), 0);
619 putpad(_deleteline);
620 tinfomove(row, 0);
621 putpad(_insertline);
623 #ifdef NOWIGGLYLINES
625 * this code causes a sweeping motion up and down the display
627 tinfomove(term.t_nrow - term.t_mrow - n, 0);
628 for(i = 0; i < n; i++)
629 putpad(_deleteline);
630 tinfomove(row, 0);
631 for(i = 0; i < n; i++)
632 putpad(_insertline);
633 #endif
636 /* return ignored */
637 return(0);
642 * o_scrollup() - open a line at the given row position.
643 * use either region scrolling or deleteline/insertline
644 * to open a new line.
647 o_scrollup(int row, int n)
649 register int i;
651 if(_scrollregion != NULL){
652 putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
653 /* setting scrolling region moves cursor to home */
654 tinfomove(term.t_nrow-(term.t_mrow+1), 0);
655 for(i = 0;i < n; i++)
656 putpad((_scrolldown == NULL || _scrolldown[0] == '\0') ? "\n"
657 : _scrolldown);
658 putpad(tgoto(_scrollregion, term.t_nrow, 0));
659 tinfomove(2, 0);
661 else{
662 for(i = 0; i < n; i++){
663 tinfomove(row, 0);
664 putpad(_deleteline);
665 tinfomove(term.t_nrow - (term.t_mrow+1), 0);
666 putpad(_insertline);
668 #ifdef NOWIGGLYLINES
669 /* see note above */
670 tinfomove(row, 0);
671 for(i = 0; i < n; i++)
672 putpad(_deleteline);
673 tinfomove(term.t_nrow - term.t_mrow - n, 0);
674 for(i = 0;i < n; i++)
675 putpad(_insertline);
676 #endif
679 /* return ignored */
680 return(0);
686 * o_insert - use terminfo to optimized character insert
687 * returns: true if it optimized output, false otherwise
690 o_insert(UCS c)
692 if(term_capabilities & TT_INSCHAR){
693 tinfoinsert(c);
694 return(1); /* no problems! */
697 return(0); /* can't do it. */
702 * o_delete - use terminfo to optimized character insert
703 * returns true if it optimized output, false otherwise
706 o_delete(void)
708 if(term_capabilities & TT_DELCHAR){
709 tinfodelete();
710 return(1); /* deleted, no problem! */
713 return(0); /* no dice. */
717 static int
718 tinfomove(int row, int col)
720 putpad(tgoto(_moveto, col, row));
722 /* return ignored */
723 return(0);
727 static int
728 tinfoeeol(void)
730 int c, starting_col, starting_line;
731 char *last_bg_color;
734 * If the terminal doesn't have back color erase, then we have to
735 * erase manually to preserve the background color.
737 if(pico_usingcolor() && (!_bce || !_cleartoeoln)){
738 extern int ttcol, ttrow;
740 starting_col = ttcol;
741 starting_line = ttrow;
742 last_bg_color = pico_get_last_bg_color();
743 pico_set_nbg_color();
744 for(c = ttcol; c < term.t_ncol; c++)
745 ttputc(' ');
747 tinfomove(starting_line, starting_col);
748 if(last_bg_color){
749 pico_set_bg_color(last_bg_color);
750 free(last_bg_color);
753 else if(_cleartoeoln)
754 putpad(_cleartoeoln);
756 /* return ignored */
757 return(0);
761 static int
762 tinfoeeop(void)
764 int i, starting_col, starting_row;
767 * If the terminal doesn't have back color erase, then we have to
768 * erase manually to preserve the background color.
770 if(pico_usingcolor() && (!_bce || !_cleartoeos)){
771 extern int ttcol, ttrow;
773 starting_col = ttcol;
774 starting_row = ttrow;
775 tinfoeeol(); /* rest of this line */
776 for(i = ttrow+1; i <= term.t_nrow; i++){ /* the remaining lines */
777 tinfomove(i, 0);
778 tinfoeeol();
781 tinfomove(starting_row, starting_col);
783 else if(_cleartoeos)
784 putpad(_cleartoeos);
786 /* return ignored */
787 return(0);
791 static int
792 tinforev(int state) /* change reverse video status */
793 { /* FALSE = normal video, TRUE = rev video */
794 if(state)
795 StartInverse();
796 else
797 EndInverse();
799 return(1);
803 static int
804 tinfoeri(void)
806 if(_xhp && _clearinverse)
807 putpad(_clearinverse);
809 return(1);
813 static int
814 tinfobeep(void)
816 ttputc(BELL);
818 /* return ignored */
819 return(0);
823 void
824 putpad(char *str)
826 tputs(str, 1, putchar);
829 #elif HAS_TERMCAP
832 * termcap-based terminal i/o and control routines
836 /* internal prototypes */
837 static int tcapmove(int, int);
838 static int tcapeeol(void);
839 static int tcapeeop(void);
840 static int tcapbeep(void);
841 static int tcaprev(int);
842 static int tcaperi(void);
843 static int tcapopen(void);
844 static int tcapterminalinfo(int);
845 static int tcapclose(void);
846 static void setup_dflt_esc_seq(void);
847 static void tcapinsert(UCS);
848 static void tcapdelete(void);
850 extern int tput();
851 extern char *tgoto(char *, int, int);
854 * This number used to be 315. No doubt there was a reason for that but we
855 * don't know what it was. It's a bit of a hassle to make it dynamic, and most
856 * modern systems seem to be using terminfo, so we'll just change it to 800.
857 * We weren't stopping on overflow before, so we'll do that, too.
859 #define TCAPSLEN 800
860 char tcapbuf[TCAPSLEN];
861 int _tlines, _tcolumns;
862 char *_clearscreen, *_moveto, *_up, *_down, *_right, *_left,
863 *_setinverse, *_clearinverse,
864 *_setunderline, *_clearunderline,
865 *_setbold, *_clearallattr, /* there is no clear only bold! */
866 *_cleartoeoln, *_cleartoeos,
867 *_deleteline, /* delete line */
868 *_insertline, /* insert line */
869 *_scrollregion, /* define a scrolling region, vt100 */
870 *_insertchar, /* insert character, preferable to : */
871 *_startinsert, /* set insert mode and, */
872 *_endinsert, /* end insert mode */
873 *_deletechar, /* delete character */
874 *_startdelete, /* set delete mode and, */
875 *_enddelete, /* end delete mode */
876 *_scrolldown, /* scroll down */
877 *_scrollup, /* scroll up */
878 *_termcap_init, /* string to start termcap */
879 *_termcap_end, /* string to end termcap */
880 *_op, *_oc, *_setaf, *_setab, *_setf, *_setb, *_scp;
881 int _colors, _pairs, _bce, _xhp;
882 char term_name[40];
884 TERM term = {
885 NROW-1,
886 NCOL,
887 MARGIN,
888 MROW,
889 tcapopen,
890 tcapterminalinfo,
891 tcapclose,
892 ttgetc,
893 ttputc,
894 ttflush,
895 tcapmove,
896 tcapeeol,
897 tcapeeop,
898 tcapbeep,
899 tcaprev,
900 tcaperi
905 * Add default keypad sequences to the trie.
907 static void
908 setup_dflt_esc_seq(void)
911 * this is sort of a hack, but it allows us to use
912 * the function keys on pc's running telnet
916 * UW-NDC/UCS vt10[02] application mode.
918 kpinsert("\033OP", F1, 1);
919 kpinsert("\033OQ", F2, 1);
920 kpinsert("\033OR", F3, 1);
921 kpinsert("\033OS", F4, 1);
922 kpinsert("\033Op", F5, 1);
923 kpinsert("\033Oq", F6, 1);
924 kpinsert("\033Or", F7, 1);
925 kpinsert("\033Os", F8, 1);
926 kpinsert("\033Ot", F9, 1);
927 kpinsert("\033Ou", F10, 1);
928 kpinsert("\033Ov", F11, 1);
929 kpinsert("\033Ow", F12, 1);
932 * DEC vt100, ANSI and cursor key mode.
934 kpinsert("\033OA", KEY_UP, 1);
935 kpinsert("\033OB", KEY_DOWN, 1);
936 kpinsert("\033OC", KEY_RIGHT, 1);
937 kpinsert("\033OD", KEY_LEFT, 1);
940 * special keypad functions
942 kpinsert("\033[4J", KEY_PGUP, 1);
943 kpinsert("\033[3J", KEY_PGDN, 1);
944 kpinsert("\033[2J", KEY_HOME, 1);
945 kpinsert("\033[N", KEY_END, 1);
948 * vt220?
950 kpinsert("\033[5~", KEY_PGUP, 1);
951 kpinsert("\033[6~", KEY_PGDN, 1);
952 kpinsert("\033[1~", KEY_HOME, 1);
953 kpinsert("\033[4~", KEY_END, 1);
956 * konsole, XTerm (XFree 4.x.x) keyboard setting
958 kpinsert("\033[H", KEY_HOME, 1);
959 kpinsert("\033[F", KEY_END, 1);
962 * gnome-terminal 2.6.0, don't know why it
963 * changed from 2.2.1
965 kpinsert("\033OH", KEY_HOME, 1);
966 kpinsert("\033OF", KEY_END, 1);
969 * "\033[2~" was common for KEY_HOME in a quick survey
970 * of terminals (though typically the Insert key).
971 * Teraterm 2.33 sends the following escape sequences,
972 * which is quite incompatible with everything
973 * else:
974 * Home: "\033[2~" End: "\033[5~" PgUp: "\033[3~"
975 * PgDn: "\033[6~"
976 * The best thing to do would be to fix TeraTerm
977 * keymappings or to tweak terminfo.
981 * ANSI mode.
983 kpinsert("\033[=a", F1, 1);
984 kpinsert("\033[=b", F2, 1);
985 kpinsert("\033[=c", F3, 1);
986 kpinsert("\033[=d", F4, 1);
987 kpinsert("\033[=e", F5, 1);
988 kpinsert("\033[=f", F6, 1);
989 kpinsert("\033[=g", F7, 1);
990 kpinsert("\033[=h", F8, 1);
991 kpinsert("\033[=i", F9, 1);
992 kpinsert("\033[=j", F10, 1);
993 kpinsert("\033[=k", F11, 1);
994 kpinsert("\033[=l", F12, 1);
997 * DEC vt100, ANSI and cursor key mode reset.
999 kpinsert("\033[A", KEY_UP, 1);
1000 kpinsert("\033[B", KEY_DOWN, 1);
1001 kpinsert("\033[C", KEY_RIGHT, 1);
1002 kpinsert("\033[D", KEY_LEFT, 1);
1005 * DEC vt52 mode.
1007 kpinsert("\033A", KEY_UP, 1);
1008 kpinsert("\033B", KEY_DOWN, 1);
1009 kpinsert("\033C", KEY_RIGHT, 1);
1010 kpinsert("\033D", KEY_LEFT, 1);
1013 * DEC vt52 application keys, and some Zenith 19.
1015 kpinsert("\033?r", KEY_DOWN, 1);
1016 kpinsert("\033?t", KEY_LEFT, 1);
1017 kpinsert("\033?v", KEY_RIGHT, 1);
1018 kpinsert("\033?x", KEY_UP, 1);
1021 * Some Ctrl-Arrow keys
1023 kpinsert("\033[5A", CTRL_KEY_UP, 1);
1024 kpinsert("\033[5B", CTRL_KEY_DOWN, 1);
1025 kpinsert("\033[5C", CTRL_KEY_RIGHT, 1);
1026 kpinsert("\033[5D", CTRL_KEY_LEFT, 1);
1028 kpinsert("\033[1;5A", CTRL_KEY_UP, 1);
1029 kpinsert("\033[1;5B", CTRL_KEY_DOWN, 1);
1030 kpinsert("\033[1;5C", CTRL_KEY_RIGHT, 1);
1031 kpinsert("\033[1;5D", CTRL_KEY_LEFT, 1);
1034 * Map some shift+up/down/left/right to their shiftless counterparts
1036 kpinsert("\033[1;2A", KEY_UP, 1);
1037 kpinsert("\033[1;2B", KEY_DOWN, 1);
1038 kpinsert("\033[1;2C", KEY_RIGHT, 1);
1039 kpinsert("\033[1;2D", KEY_LEFT, 1);
1040 kpinsert("\033[a", KEY_UP, 1);
1041 kpinsert("\033[b", KEY_DOWN, 1);
1042 kpinsert("\033[c", KEY_RIGHT, 1);
1043 kpinsert("\033[d", KEY_LEFT, 1);
1046 * Sun Console sequences.
1048 kpinsert("\033[1", KEY_SWALLOW_Z, 1);
1049 kpinsert("\033[215", KEY_SWAL_UP, 1);
1050 kpinsert("\033[217", KEY_SWAL_LEFT, 1);
1051 kpinsert("\033[219", KEY_SWAL_RIGHT, 1);
1052 kpinsert("\033[221", KEY_SWAL_DOWN, 1);
1055 * Kermit App Prog Cmd, gobble until ESC \ (kermit should intercept this)
1057 kpinsert("\033_", KEY_KERMIT, 1);
1060 * Fake a control character.
1062 kpinsert("\033\033", KEY_DOUBLE_ESC, 1);
1067 * Read termcap and set some global variables. Initialize input trie to
1068 * decode escape sequences.
1070 static int
1071 tcapterminalinfo(int termcap_wins)
1073 char *p, *tgetstr();
1074 char tcbuf[2*1024];
1075 char *tv_stype;
1076 char err_str[72];
1077 int err;
1078 char *_ku, *_kd, *_kl, *_kr,
1079 *_kppu, *_kppd, *_kphome, *_kpend, *_kpdel,
1080 *_kf1, *_kf2, *_kf3, *_kf4, *_kf5, *_kf6,
1081 *_kf7, *_kf8, *_kf9, *_kf10, *_kf11, *_kf12;
1083 if (!(tv_stype = getenv("TERM")) || !strncpy(term_name, tv_stype, sizeof(term_name))){
1084 if(Pmaster){
1085 return(-1);
1087 else{
1088 puts("Environment variable TERM not defined!");
1089 exit(1);
1093 term_name[sizeof(term_name)-1] = '\0';
1095 if((err = tgetent(tcbuf, tv_stype)) != 1){
1096 if(Pmaster){
1097 return(err - 2);
1099 else{
1100 snprintf(err_str, sizeof(err_str), "Unknown terminal type %s!", tv_stype);
1101 puts(err_str);
1102 exit(1);
1106 p = tcapbuf;
1108 _clearscreen = tgetstr("cl", &p);
1109 _moveto = tgetstr("cm", &p);
1110 _up = tgetstr("up", &p);
1111 _down = tgetstr("do", &p);
1112 _right = tgetstr("nd", &p);
1113 _left = tgetstr("bs", &p);
1114 _setinverse = tgetstr("so", &p);
1115 _clearinverse = tgetstr("se", &p);
1116 _setunderline = tgetstr("us", &p);
1117 _clearunderline = tgetstr("ue", &p);
1118 _setbold = tgetstr("md", &p);
1119 _clearallattr = tgetstr("me", &p);
1120 _cleartoeoln = tgetstr("ce", &p);
1121 _cleartoeos = tgetstr("cd", &p);
1122 _deletechar = tgetstr("dc", &p);
1123 _insertchar = tgetstr("ic", &p);
1124 _startinsert = tgetstr("im", &p);
1125 _endinsert = tgetstr("ei", &p);
1126 _deleteline = tgetstr("dl", &p);
1127 _insertline = tgetstr("al", &p);
1128 _scrollregion = tgetstr("cs", &p);
1129 _scrolldown = tgetstr("sf", &p);
1130 _scrollup = tgetstr("sr", &p);
1131 _termcap_init = tgetstr("ti", &p);
1132 _termcap_end = tgetstr("te", &p);
1133 _startdelete = tgetstr("dm", &p);
1134 _enddelete = tgetstr("ed", &p);
1135 _ku = tgetstr("ku", &p);
1136 _kd = tgetstr("kd", &p);
1137 _kl = tgetstr("kl", &p);
1138 _kr = tgetstr("kr", &p);
1139 _kppu = tgetstr("kP", &p);
1140 _kppd = tgetstr("kN", &p);
1141 _kphome = tgetstr("kh", &p);
1142 _kpend = tgetstr("kH", &p);
1143 _kpdel = tgetstr("kD", &p);
1144 _kf1 = tgetstr("k1", &p);
1145 _kf2 = tgetstr("k2", &p);
1146 _kf3 = tgetstr("k3", &p);
1147 _kf4 = tgetstr("k4", &p);
1148 _kf5 = tgetstr("k5", &p);
1149 _kf6 = tgetstr("k6", &p);
1150 _kf7 = tgetstr("k7", &p);
1151 _kf8 = tgetstr("k8", &p);
1152 _kf9 = tgetstr("k9", &p);
1153 if((_kf10 = tgetstr("k;", &p)) == NULL)
1154 _kf10 = tgetstr("k0", &p);
1155 _kf11 = tgetstr("F1", &p);
1156 _kf12 = tgetstr("F2", &p);
1158 _colors = tgetnum("Co");
1159 _pairs = tgetnum("pa");
1160 _setaf = tgetstr("AF", &p);
1161 _setab = tgetstr("AB", &p);
1162 _setf = tgetstr("Sf", &p);
1163 _setb = tgetstr("Sb", &p);
1164 _scp = tgetstr("sp", &p);
1165 _op = tgetstr("op", &p);
1166 _oc = tgetstr("oc", &p);
1167 _bce = tgetflag("ut");
1168 _xhp = tgetflag("xs");
1170 if (p >= &tcapbuf[TCAPSLEN]){
1171 puts("Terminal description too big!\n");
1172 if(Pmaster)
1173 return(-3);
1174 else
1175 exit(1);
1178 _tlines = tgetnum("li");
1179 if(_tlines == -1){
1180 char *er;
1181 int rr;
1183 /* tgetnum failed, try $LINES */
1184 er = getenv("LINES");
1185 if(er && (rr = atoi(er)) > 0)
1186 _tlines = rr;
1189 _tcolumns = tgetnum("co");
1190 if(_tcolumns == -1){
1191 char *ec;
1192 int cc;
1194 /* tgetnum failed, try $COLUMNS */
1195 ec = getenv("COLUMNS");
1196 if(ec && (cc = atoi(ec)) > 0)
1197 _tcolumns = cc;
1201 * Add default keypad sequences to the trie.
1202 * Since these come first, they will override any conflicting termcap
1203 * or terminfo escape sequences defined below. An escape sequence is
1204 * considered conflicting if one is a prefix of the other.
1205 * So, without TERMCAP_WINS, there will likely be some termcap/terminfo
1206 * escape sequences that don't work, because they conflict with default
1207 * sequences defined here.
1209 if(!termcap_wins)
1210 setup_dflt_esc_seq();
1213 * add termcap/info escape sequences to the trie...
1216 if(_ku != NULL && _kd != NULL && _kl != NULL && _kr != NULL){
1217 kpinsert(_ku, KEY_UP, termcap_wins);
1218 kpinsert(_kd, KEY_DOWN, termcap_wins);
1219 kpinsert(_kl, KEY_LEFT, termcap_wins);
1220 kpinsert(_kr, KEY_RIGHT, termcap_wins);
1223 if(_kppu != NULL && _kppd != NULL){
1224 kpinsert(_kppu, KEY_PGUP, termcap_wins);
1225 kpinsert(_kppd, KEY_PGDN, termcap_wins);
1228 kpinsert(_kphome, KEY_HOME, termcap_wins);
1229 kpinsert(_kpend, KEY_END, termcap_wins);
1230 kpinsert(_kpdel, KEY_DEL, termcap_wins);
1232 kpinsert(_kf1, F1, termcap_wins);
1233 kpinsert(_kf2, F2, termcap_wins);
1234 kpinsert(_kf3, F3, termcap_wins);
1235 kpinsert(_kf4, F4, termcap_wins);
1236 kpinsert(_kf5, F5, termcap_wins);
1237 kpinsert(_kf6, F6, termcap_wins);
1238 kpinsert(_kf7, F7, termcap_wins);
1239 kpinsert(_kf8, F8, termcap_wins);
1240 kpinsert(_kf9, F9, termcap_wins);
1241 kpinsert(_kf10, F10, termcap_wins);
1242 kpinsert(_kf11, F11, termcap_wins);
1243 kpinsert(_kf12, F12, termcap_wins);
1246 * Add default keypad sequences to the trie.
1247 * Since these come after the termcap/terminfo escape sequences above,
1248 * the termcap/info sequences will override any conflicting default
1249 * escape sequences defined here.
1250 * So, with TERMCAP_WINS, some of the default sequences will be missing.
1251 * This means that you'd better get all of your termcap/terminfo entries
1252 * correct if you define TERMCAP_WINS.
1254 if(termcap_wins)
1255 setup_dflt_esc_seq();
1257 if(Pmaster)
1258 return(0);
1259 else
1260 return(TRUE);
1263 static int
1264 tcapopen(void)
1266 int row, col;
1269 * determine the terminal's communication speed and decide
1270 * if we need to do optimization ...
1272 if(ttisslow())
1273 term_capabilities |= TT_OPTIMIZE;
1275 col = _tcolumns;
1276 row = _tlines;
1277 if(row >= 0)
1278 row--;
1280 ttgetwinsz(&row, &col);
1281 term.t_nrow = (short) row;
1282 term.t_ncol = (short) col;
1284 if(_cleartoeoln != NULL) /* able to use clear to EOL? */
1285 term_capabilities |= TT_EOLEXIST;
1286 else
1287 term_capabilities &= ~TT_EOLEXIST;
1289 if(_setinverse != NULL)
1290 term_capabilities |= TT_REVEXIST;
1291 else
1292 term_capabilities &= ~TT_REVEXIST;
1294 if(_deletechar == NULL && (_startdelete == NULL || _enddelete == NULL))
1295 term_capabilities &= ~TT_DELCHAR;
1297 if(_insertchar == NULL && (_startinsert == NULL || _endinsert == NULL))
1298 term_capabilities &= ~TT_INSCHAR;
1300 if((_scrollregion == NULL || _scrolldown == NULL || _scrollup == NULL)
1301 && (_deleteline == NULL || _insertline == NULL))
1302 term_capabilities &= ~TT_SCROLLEXIST;
1304 if(_clearscreen == NULL || _moveto == NULL || _up == NULL){
1305 if(Pmaster == NULL){
1306 puts("Incomplete termcap entry\n");
1307 exit(1);
1311 ttopen();
1313 if(_termcap_init && !Pmaster) {
1314 putpad(_termcap_init); /* any init termcap requires */
1315 if (_scrollregion)
1316 putpad(tgoto(_scrollregion, term.t_nrow, 0)) ;
1320 * Initialize UW-modified NCSA telnet to use it's functionkeys
1322 if(gmode&MDFKEY && Pmaster == NULL)
1323 puts("\033[99h");
1325 /* return ignored */
1326 return(0);
1330 static int
1331 tcapclose(void)
1333 if(!Pmaster){
1334 if(gmode&MDFKEY)
1335 puts("\033[99l"); /* reset UW-NCSA telnet keys */
1337 if(_termcap_end) /* any cleanup termcap requires */
1338 putpad(_termcap_end);
1341 ttclose();
1343 /* return ignored */
1344 return(0);
1350 * tcapinsert - insert a character at the current character position.
1351 * _insertchar takes precedence.
1353 static void
1354 tcapinsert(UCS ch)
1356 if(_insertchar != NULL){
1357 putpad(_insertchar);
1358 ttputc(ch);
1360 else{
1361 putpad(_startinsert);
1362 ttputc(ch);
1363 putpad(_endinsert);
1369 * tcapdelete - delete a character at the current character position.
1371 static void
1372 tcapdelete(void)
1374 if(_startdelete == NULL && _enddelete == NULL)
1375 putpad(_deletechar);
1376 else{
1377 putpad(_startdelete);
1378 putpad(_deletechar);
1379 putpad(_enddelete);
1385 * o_scrolldown - open a line at the given row position.
1386 * use either region scrolling or deleteline/insertline
1387 * to open a new line.
1390 o_scrolldown(int row, int n)
1392 register int i;
1394 if(_scrollregion != NULL){
1395 putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
1396 tcapmove(row, 0);
1397 for(i = 0; i < n; i++)
1398 putpad( (_scrollup != NULL && *_scrollup != '\0')
1399 ? _scrollup : "\n" );
1400 putpad(tgoto(_scrollregion, term.t_nrow, 0));
1401 tcapmove(row, 0);
1403 else{
1405 * this code causes a jiggly motion of the keymenu when scrolling
1407 for(i = 0; i < n; i++){
1408 tcapmove(term.t_nrow - (term.t_mrow+1), 0);
1409 putpad(_deleteline);
1410 tcapmove(row, 0);
1411 putpad(_insertline);
1413 #ifdef NOWIGGLYLINES
1415 * this code causes a sweeping motion up and down the display
1417 tcapmove(term.t_nrow - term.t_mrow - n, 0);
1418 for(i = 0; i < n; i++)
1419 putpad(_deleteline);
1420 tcapmove(row, 0);
1421 for(i = 0; i < n; i++)
1422 putpad(_insertline);
1423 #endif
1426 /* return ignored */
1427 return(0);
1432 * o_scrollup - open a line at the given row position.
1433 * use either region scrolling or deleteline/insertline
1434 * to open a new line.
1437 o_scrollup(int row, int n)
1439 register int i;
1441 if(_scrollregion != NULL){
1442 putpad(tgoto(_scrollregion, term.t_nrow - (term.t_mrow+1), row));
1443 /* setting scrolling region moves cursor to home */
1444 tcapmove(term.t_nrow-(term.t_mrow+1), 0);
1445 for(i = 0;i < n; i++)
1446 putpad((_scrolldown == NULL || _scrolldown[0] == '\0')
1447 ? "\n" : _scrolldown);
1448 putpad(tgoto(_scrollregion, term.t_nrow, 0));
1449 tcapmove(2, 0);
1451 else{
1452 for(i = 0; i < n; i++){
1453 tcapmove(row, 0);
1454 putpad(_deleteline);
1455 tcapmove(term.t_nrow - (term.t_mrow+1), 0);
1456 putpad(_insertline);
1458 #ifdef NOWIGGLYLINES
1459 /* see note above */
1460 tcapmove(row, 0);
1461 for(i = 0; i < n; i++)
1462 putpad(_deleteline);
1463 tcapmove(term.t_nrow - term.t_mrow - n, 0);
1464 for(i = 0;i < n; i++)
1465 putpad(_insertline);
1466 #endif
1469 /* return ignored */
1470 return(0);
1475 * o_insert - use termcap info to optimized character insert
1476 * returns: true if it optimized output, false otherwise
1479 o_insert(UCS c)
1481 if(term_capabilities & TT_INSCHAR){
1482 tcapinsert(c);
1483 return(1); /* no problems! */
1486 return(0); /* can't do it. */
1491 * o_delete - use termcap info to optimized character insert
1492 * returns true if it optimized output, false otherwise
1495 o_delete(void)
1497 if(term_capabilities & TT_DELCHAR){
1498 tcapdelete();
1499 return(1); /* deleted, no problem! */
1502 return(0); /* no dice. */
1506 static int
1507 tcapmove(int row, int col)
1509 putpad(tgoto(_moveto, col, row));
1511 /* return ignored */
1512 return(0);
1516 static int
1517 tcapeeol(void)
1519 int c, starting_col, starting_line;
1520 char *last_bg_color;
1523 * If the terminal doesn't have back color erase, then we have to
1524 * erase manually to preserve the background color.
1526 if(pico_usingcolor() && (!_bce || !_cleartoeoln)){
1527 extern int ttcol, ttrow;
1529 starting_col = ttcol;
1530 starting_line = ttrow;
1531 last_bg_color = pico_get_last_bg_color();
1532 pico_set_nbg_color();
1533 for(c = ttcol; c < term.t_ncol; c++)
1534 ttputc(' ');
1536 tcapmove(starting_line, starting_col);
1537 if(last_bg_color){
1538 pico_set_bg_color(last_bg_color);
1539 free(last_bg_color);
1542 else if(_cleartoeoln)
1543 putpad(_cleartoeoln);
1545 /* return ignored */
1546 return(0);
1550 static int
1551 tcapeeop(void)
1553 int i, starting_col, starting_row;
1556 * If the terminal doesn't have back color erase, then we have to
1557 * erase manually to preserve the background color.
1559 if(pico_usingcolor() && (!_bce || !_cleartoeos)){
1560 extern int ttcol, ttrow;
1562 starting_col = ttcol;
1563 starting_row = ttrow;
1564 tcapeeol(); /* rest of this line */
1565 for(i = ttrow+1; i <= term.t_nrow; i++){ /* the remaining lines */
1566 tcapmove(i, 0);
1567 tcapeeol();
1570 tcapmove(starting_row, starting_col);
1572 else if(_cleartoeos)
1573 putpad(_cleartoeos);
1575 /* return ignored */
1576 return(0);
1580 static int
1581 tcaperi(void)
1583 if(_xhp && _clearinverse)
1584 putpad(_clearinverse);
1586 return(1);
1590 static int
1591 tcaprev(int state) /* change reverse video status */
1592 { /* FALSE = normal video, TRUE = reverse video */
1593 if(state)
1594 StartInverse();
1595 else
1596 EndInverse();
1598 return(1);
1602 static int
1603 tcapbeep(void)
1605 ttputc(BELL);
1607 /* return ignored */
1608 return(0);
1612 void
1613 putpad(char *str)
1615 tputs(str, 1, putchar);
1618 #else /* HARD_CODED_ANSI_TERMINAL */
1621 * ANSI-specific terminal i/o and control routines
1625 #define BEL 0x07 /* BEL character. */
1626 #define ESC 0x1B /* ESC character. */
1629 extern int ttflush();
1631 extern int ansimove(int, int);
1632 extern int ansieeol(void);
1633 extern int ansieeop(void);
1634 extern int ansibeep(void);
1635 extern int ansiparm(int);
1636 extern int ansiopen(void);
1637 extern int ansiterminalinfo(int);
1638 extern int ansirev(int);
1641 * Standard terminal interface dispatch table. Most of the fields point into
1642 * "termio" code.
1644 #if defined(VAX) && !defined(__ALPHA)
1645 globaldef
1646 #endif
1648 TERM term = {
1649 NROW-1,
1650 NCOL,
1651 MARGIN,
1652 MROW,
1653 ansiopen,
1654 ansiterminalinfo,
1655 ttclose,
1656 ttgetc,
1657 ttputc,
1658 ttflush,
1659 ansimove,
1660 ansieeol,
1661 ansieeop,
1662 ansibeep,
1663 ansirev
1667 ansimove(int row, int col)
1669 ttputc(ESC);
1670 ttputc('[');
1671 ansiparm(row+1);
1672 ttputc(';');
1673 ansiparm(col+1);
1674 ttputc('H');
1678 ansieeol(void)
1680 ttputc(ESC);
1681 ttputc('[');
1682 ttputc('K');
1686 ansieeop(void)
1688 ttputc(ESC);
1689 ttputc('[');
1690 ttputc('J');
1694 ansirev(int state) /* change reverse video state */
1695 { /* TRUE = reverse, FALSE = normal */
1696 static int PrevState = 0;
1698 if(state != PrevState) {
1699 PrevState = state ;
1700 ttputc(ESC);
1701 ttputc('[');
1702 ttputc(state ? '7': '0');
1703 ttputc('m');
1708 ansibeep(void)
1710 ttputc(BEL);
1711 ttflush();
1715 ansiparm(int n)
1717 register int q;
1719 q = n/10;
1720 if (q != 0)
1721 ansiparm(q);
1722 ttputc((n%10) + '0');
1727 ansiterminalinfo(int termcap_wins)
1729 #if V7
1730 register char *cp;
1731 char *getenv();
1733 if ((cp = getenv("TERM")) == NULL) {
1734 puts("Shell variable TERM not defined!");
1735 exit(1);
1737 if (strcmp(cp, "vt100") != 0) {
1738 puts("Terminal type not 'vt100'!");
1739 exit(1);
1741 #endif
1742 /* revexist = TRUE; dead code? */
1746 ansiopen(void)
1748 ttopen();
1752 #endif /* HARD_CODED_ANSI_TERMINAL */
1753 #else /* _WINDOWS */
1755 /* These are all just noops in Windows */
1757 unsigned
1758 tthascap(void)
1760 return(0);
1764 * o_insert - optimize screen insert of char c
1767 o_insert(UCS c)
1769 return(0);
1774 * o_delete - optimized character deletion
1777 o_delete(void)
1779 return(0);
1784 #endif /* _WINDOWS */