Annotation of src/usr.bin/less/screen.c, Revision 1.6
1.1 etheisen 1: /*
2: * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice in the documentation and/or other materials provided with
12: * the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
15: * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
20: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27:
28: /*
29: * Routines which deal with the characteristics of the terminal.
30: * Uses termcap to be as terminal-independent as possible.
31: *
32: * {{ Maybe someday this should be rewritten to use curses or terminfo. }}
33: */
34:
35: #include "less.h"
36: #include "cmd.h"
37:
38: #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
39: #include <termios.h>
40: #if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)
41: #include <sys/ioctl.h>
42: #endif
43: #else
44: #if HAVE_TERMIO_H
45: #include <termio.h>
46: #else
47: #include <sgtty.h>
48: #if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD))
49: #include <sys/ioctl.h>
50: #endif
51: #endif
52: #endif
53: #if HAVE_TERMCAP_H
54: #include <termcap.h>
55: #endif
56:
57: #ifndef TIOCGWINSZ
58: /*
59: * For the Unix PC (ATT 7300 & 3B1):
60: * Since WIOCGETD is defined in sys/window.h, we can't use that to decide
61: * whether to include sys/window.h. Use SIGPHONE from sys/signal.h instead.
62: */
63: #include <sys/signal.h>
64: #ifdef SIGPHONE
65: #include <sys/window.h>
66: #endif
67: #endif
68:
69: #if HAVE_SYS_STREAM_H
70: #include <sys/stream.h>
71: #endif
72: #if HAVE_SYS_PTEM_H
73: #include <sys/ptem.h>
74: #endif
75:
76: #if OS2
77: #define DEFAULT_TERM "ansi"
78: #else
79: #define DEFAULT_TERM "unknown"
80: #endif
81:
82: /*
83: * Strings passed to tputs() to do various terminal functions.
84: */
85: static char
86: *sc_pad, /* Pad string */
87: *sc_home, /* Cursor home */
88: *sc_addline, /* Add line, scroll down following lines */
89: *sc_lower_left, /* Cursor to last line, first column */
90: *sc_move, /* General cursor positioning */
91: *sc_clear, /* Clear screen */
92: *sc_eol_clear, /* Clear to end of line */
93: *sc_eos_clear, /* Clear to end of screen */
94: *sc_s_in, /* Enter standout (highlighted) mode */
95: *sc_s_out, /* Exit standout mode */
96: *sc_u_in, /* Enter underline mode */
97: *sc_u_out, /* Exit underline mode */
98: *sc_b_in, /* Enter bold mode */
99: *sc_b_out, /* Exit bold mode */
100: *sc_bl_in, /* Enter blink mode */
101: *sc_bl_out, /* Exit blink mode */
102: *sc_visual_bell, /* Visual bell (flash screen) sequence */
103: *sc_backspace, /* Backspace cursor */
104: *sc_s_keypad, /* Start keypad mode */
105: *sc_e_keypad, /* End keypad mode */
106: *sc_init, /* Startup terminal initialization */
107: *sc_deinit; /* Exit terminal de-initialization */
108:
109: static int init_done = 0;
1.5 millert 110: static int tty_fd = -1;
1.1 etheisen 111:
112: public int auto_wrap; /* Terminal does \r\n when write past margin */
113: public int ignaw; /* Terminal ignores \n immediately after wrap */
114: public int erase_char, kill_char; /* The user's erase and line-kill chars */
115: public int werase_char; /* The user's word-erase char */
116: public int sc_width, sc_height; /* Height & width of screen */
117: public int bo_s_width, bo_e_width; /* Printing width of boldface seq */
118: public int ul_s_width, ul_e_width; /* Printing width of underline seq */
119: public int so_s_width, so_e_width; /* Printing width of standout seq */
120: public int bl_s_width, bl_e_width; /* Printing width of blink seq */
121: public int above_mem, below_mem; /* Memory retained above/below screen */
122: public int can_goto_line; /* Can move cursor to any line */
123:
124: static char *cheaper();
125:
126: /*
127: * These two variables are sometimes defined in,
128: * and needed by, the termcap library.
129: */
130: #if MUST_DEFINE_OSPEED
131: extern short ospeed; /* Terminal output baud rate */
132: extern char PC; /* Pad character */
133: #endif
134:
135: extern int quiet; /* If VERY_QUIET, use visual bell for bell */
136: extern int know_dumb; /* Don't complain about a dumb terminal */
137: extern int back_scroll;
138: extern int swindow;
139: extern int no_init;
1.2 etheisen 140: extern int quit_at_eof;
141: extern int more_mode;
1.1 etheisen 142: #if HILITE_SEARCH
143: extern int hilite_search;
144: #endif
145:
146: extern char *tgetstr();
147: extern char *tgoto();
148:
149:
150: /*
151: * Change terminal to "raw mode", or restore to "normal" mode.
152: * "Raw mode" means
153: * 1. An outstanding read will complete on receipt of a single keystroke.
154: * 2. Input is not echoed.
155: * 3. On output, \n is mapped to \r\n.
156: * 4. \t is NOT expanded into spaces.
157: * 5. Signal-causing characters such as ctrl-C (interrupt),
158: * etc. are NOT disabled.
159: * It doesn't matter whether an input \n is mapped to \r, or vice versa.
160: */
161: public void
162: raw_mode(on)
163: int on;
164: {
165: static int curr_on = 0;
166:
167: if (on == curr_on)
168: return;
1.5 millert 169:
170: if (tty_fd == -1 && (tty_fd = open("/dev/tty", O_RDWR)) < 0)
171: tty_fd = 2;
172:
1.1 etheisen 173: #if OS2
174: signal(SIGINT, SIG_IGN);
175: erase_char = '\b';
176: kill_char = '\033';
177: #else
178: #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
179: {
180: struct termios s;
181: static struct termios save_term;
182:
183: if (on)
184: {
185: /*
186: * Get terminal modes.
187: */
1.5 millert 188: if (tcgetattr(tty_fd, &s) == -1)
189: return;
1.1 etheisen 190:
191: /*
192: * Save modes and set certain variables dependent on modes.
193: */
194: save_term = s;
195: #if HAVE_OSPEED
196: switch (cfgetospeed(&s))
197: {
198: #ifdef B0
199: case B0: ospeed = 0; break;
200: #endif
201: #ifdef B50
202: case B50: ospeed = 1; break;
203: #endif
204: #ifdef B75
205: case B75: ospeed = 2; break;
206: #endif
207: #ifdef B110
208: case B110: ospeed = 3; break;
209: #endif
210: #ifdef B134
211: case B134: ospeed = 4; break;
212: #endif
213: #ifdef B150
214: case B150: ospeed = 5; break;
215: #endif
216: #ifdef B200
217: case B200: ospeed = 6; break;
218: #endif
219: #ifdef B300
220: case B300: ospeed = 7; break;
221: #endif
222: #ifdef B600
223: case B600: ospeed = 8; break;
224: #endif
225: #ifdef B1200
226: case B1200: ospeed = 9; break;
227: #endif
228: #ifdef B1800
229: case B1800: ospeed = 10; break;
230: #endif
231: #ifdef B2400
232: case B2400: ospeed = 11; break;
233: #endif
234: #ifdef B4800
235: case B4800: ospeed = 12; break;
236: #endif
237: #ifdef B9600
238: case B9600: ospeed = 13; break;
239: #endif
240: #ifdef EXTA
241: case EXTA: ospeed = 14; break;
242: #endif
243: #ifdef EXTB
244: case EXTB: ospeed = 15; break;
245: #endif
246: #ifdef B57600
247: case B57600: ospeed = 16; break;
248: #endif
249: #ifdef B115200
250: case B115200: ospeed = 17; break;
251: #endif
252: default: ;
253: }
254: #endif
255: erase_char = s.c_cc[VERASE];
256: kill_char = s.c_cc[VKILL];
257: #ifdef VWERASE
258: werase_char = s.c_cc[VWERASE];
259: #else
260: werase_char = 0;
261: #endif
262:
263: /*
264: * Set the modes to the way we want them.
265: */
266: s.c_lflag &= ~(0
267: #ifdef ICANON
268: | ICANON
269: #endif
270: #ifdef ECHO
271: | ECHO
272: #endif
273: #ifdef ECHOE
274: | ECHOE
275: #endif
276: #ifdef ECHOK
277: | ECHOK
278: #endif
279: #if ECHONL
280: | ECHONL
281: #endif
282: );
283:
284: s.c_oflag |= (0
285: #ifdef XTABS
286: | XTABS
287: #else
288: #ifdef TAB3
289: | TAB3
290: #else
291: #ifdef OXTABS
292: | OXTABS
293: #endif
294: #endif
295: #endif
296: #ifdef OPOST
297: | OPOST
298: #endif
299: #ifdef ONLCR
300: | ONLCR
301: #endif
302: );
303:
304: s.c_oflag &= ~(0
305: #ifdef ONOEOT
306: | ONOEOT
307: #endif
308: #ifdef OCRNL
309: | OCRNL
310: #endif
311: #ifdef ONOCR
312: | ONOCR
313: #endif
314: #ifdef ONLRET
315: | ONLRET
316: #endif
317: );
318: s.c_cc[VMIN] = 1;
319: s.c_cc[VTIME] = 0;
320: } else
321: {
322: /*
323: * Restore saved modes.
324: */
325: s = save_term;
326: }
1.5 millert 327: if (tcsetattr(tty_fd, TCSANOW, &s) == -1)
328: return;
1.1 etheisen 329: }
330: #else
331: #ifdef TCGETA
332: {
333: struct termio s;
334: static struct termio save_term;
335:
336: if (on)
337: {
338: /*
339: * Get terminal modes.
340: */
1.5 millert 341: ioctl(tty_fd, TCGETA, &s);
1.1 etheisen 342:
343: /*
344: * Save modes and set certain variables dependent on modes.
345: */
346: save_term = s;
347: #if HAVE_OSPEED
348: ospeed = s.c_cflag & CBAUD;
349: #endif
350: erase_char = s.c_cc[VERASE];
351: kill_char = s.c_cc[VKILL];
352: #ifdef VWERASE
353: werase_char = s.c_cc[VWERASE];
354: #else
355: werase_char = 0;
356: #endif
357:
358: /*
359: * Set the modes to the way we want them.
360: */
361: s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
362: s.c_oflag |= (OPOST|ONLCR|TAB3);
363: s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
364: s.c_cc[VMIN] = 1;
365: s.c_cc[VTIME] = 0;
366: } else
367: {
368: /*
369: * Restore saved modes.
370: */
371: s = save_term;
372: }
1.5 millert 373: ioctl(tty_fd, TCSETAW, &s);
1.1 etheisen 374: }
375: #else
376: {
377: struct sgttyb s;
378: static struct sgttyb save_term;
379:
380: if (on)
381: {
382: /*
383: * Get terminal modes.
384: */
1.5 millert 385: ioctl(tty_fd, TIOCGETP, &s);
1.1 etheisen 386:
387: /*
388: * Save modes and set certain variables dependent on modes.
389: */
390: save_term = s;
391: #if HAVE_OSPEED
392: ospeed = s.sg_ospeed;
393: #endif
394: erase_char = s.sg_erase;
395: kill_char = s.sg_kill;
396: werase_char = 0;
397:
398: /*
399: * Set the modes to the way we want them.
400: */
401: s.sg_flags |= CBREAK;
402: s.sg_flags &= ~(ECHO|XTABS);
403: } else
404: {
405: /*
406: * Restore saved modes.
407: */
408: s = save_term;
409: }
1.5 millert 410: ioctl(tty_fd, TIOCSETN, &s);
1.1 etheisen 411: }
412: #endif
413: #endif
414: #endif
415: curr_on = on;
416: }
417:
418: static void
419: cannot(s)
420: char *s;
421: {
422: PARG parg;
423:
1.2 etheisen 424: if (know_dumb || more_mode)
1.1 etheisen 425: /*
426: * User knows this is a dumb terminal, so don't tell him.
1.2 etheisen 427: * more doesn't complain about these, either.
1.1 etheisen 428: */
429: return;
430:
431: parg.p_string = s;
432: error("WARNING: terminal cannot %s", &parg);
433: }
434:
435: /*
436: * Get size of the output screen.
437: */
438: #if OS2
439: public void
440: scrsize()
441: {
442: int s[2];
443:
444: _scrsize(s);
445: sc_width = s[0];
446: sc_height = s[1];
447: }
448:
449: #else
450:
451: public void
452: scrsize()
453: {
454: register char *s;
455: #ifdef TIOCGWINSZ
456: struct winsize w;
457: #else
458: #ifdef WIOCGETD
459: struct uwdata w;
460: #endif
461: #endif
462:
1.5 millert 463: if (tty_fd == -1 && (tty_fd = open("/dev/tty", O_RDWR)) < 0)
464: tty_fd = 2;
465:
1.1 etheisen 466: #ifdef TIOCGWINSZ
1.5 millert 467: if (ioctl(tty_fd, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
1.1 etheisen 468: sc_height = w.ws_row;
469: else
470: #else
471: #ifdef WIOCGETD
1.5 millert 472: if (ioctl(tty_fd, WIOCGETD, &w) == 0 && w.uw_height > 0)
1.1 etheisen 473: sc_height = w.uw_height/w.uw_vs;
474: else
475: #endif
476: #endif
477: if ((s = getenv("LINES")) != NULL)
478: sc_height = atoi(s);
479: else
480: sc_height = tgetnum("li");
481:
482: if (sc_height <= 0)
483: sc_height = 24;
484:
485: #ifdef TIOCGWINSZ
1.5 millert 486: if (ioctl(tty_fd, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
1.1 etheisen 487: sc_width = w.ws_col;
488: else
489: #ifdef WIOCGETD
1.5 millert 490: if (ioctl(tty_fd, WIOCGETD, &w) == 0 && w.uw_width > 0)
1.1 etheisen 491: sc_width = w.uw_width/w.uw_hs;
492: else
493: #endif
494: #endif
495: if ((s = getenv("COLUMNS")) != NULL)
496: sc_width = atoi(s);
497: else
498: sc_width = tgetnum("co");
499:
500: if (sc_width <= 0)
501: sc_width = 80;
502: }
503: #endif /* OS2 */
504:
505: /*
506: * Take care of the "variable" keys.
507: * Certain keys send escape sequences which differ on different terminals
508: * (such as the arrow keys, INSERT, DELETE, etc.)
509: * Construct the commands based on these keys.
510: */
511: public void
512: get_editkeys()
513: {
514: char *sp;
515: char *s;
516: char tbuf[40];
517:
518: static char kfcmdtable[400];
519: int sz_kfcmdtable = 0;
520: static char kecmdtable[400];
521: int sz_kecmdtable = 0;
522:
523: #define put_cmd(str,action,tbl,sz) { \
524: strcpy(tbl+sz, str); \
525: sz += strlen(str) + 1; \
526: tbl[sz++] = action; }
527: #define put_esc_cmd(str,action,tbl,sz) { \
528: tbl[sz++] = ESC; \
529: put_cmd(str,action,tbl,sz); }
530:
531: #define put_fcmd(str,action) put_cmd(str,action,kfcmdtable,sz_kfcmdtable)
532: #define put_ecmd(str,action) put_cmd(str,action,kecmdtable,sz_kecmdtable)
533: #define put_esc_fcmd(str,action) put_esc_cmd(str,action,kfcmdtable,sz_kfcmdtable)
534: #define put_esc_ecmd(str,action) put_esc_cmd(str,action,kecmdtable,sz_kecmdtable)
535:
536: /*
537: * Look at some interesting keys and see what strings they send.
538: * Create commands (both command keys and line-edit keys).
539: */
540:
541: /* RIGHT ARROW */
542: sp = tbuf;
543: if ((s = tgetstr("kr", &sp)) != NULL)
544: {
545: put_ecmd(s, EC_RIGHT);
546: put_esc_ecmd(s, EC_W_RIGHT);
547: }
548:
549: /* LEFT ARROW */
550: sp = tbuf;
551: if ((s = tgetstr("kl", &sp)) != NULL)
552: {
553: put_ecmd(s, EC_LEFT);
554: put_esc_ecmd(s, EC_W_LEFT);
555: }
556:
557: /* UP ARROW */
558: sp = tbuf;
559: if ((s = tgetstr("ku", &sp)) != NULL)
560: {
561: put_ecmd(s, EC_UP);
562: put_fcmd(s, A_B_LINE);
563: }
564:
565: /* DOWN ARROW */
566: sp = tbuf;
567: if ((s = tgetstr("kd", &sp)) != NULL)
568: {
569: put_ecmd(s, EC_DOWN);
570: put_fcmd(s, A_F_LINE);
571: }
572:
573: /* PAGE UP */
574: sp = tbuf;
575: if ((s = tgetstr("kP", &sp)) != NULL)
576: {
577: put_fcmd(s, A_B_SCREEN);
578: }
579:
580: /* PAGE DOWN */
581: sp = tbuf;
582: if ((s = tgetstr("kN", &sp)) != NULL)
583: {
584: put_fcmd(s, A_F_SCREEN);
585: }
586:
587: /* HOME */
588: sp = tbuf;
589: if ((s = tgetstr("kh", &sp)) != NULL)
590: {
591: put_ecmd(s, EC_HOME);
592: }
593:
594: /* END */
595: sp = tbuf;
596: if ((s = tgetstr("@7", &sp)) != NULL)
597: {
598: put_ecmd(s, EC_END);
599: }
600:
601: /* DELETE */
602: sp = tbuf;
603: if ((s = tgetstr("kD", &sp)) == NULL)
604: {
605: /* Use DEL (\177) if no "kD" termcap. */
606: tbuf[1] = '\177';
607: tbuf[2] = '\0';
608: s = tbuf+1;
609: }
610: put_ecmd(s, EC_DELETE);
611: put_esc_ecmd(s, EC_W_DELETE);
612:
613: /* BACKSPACE */
614: tbuf[0] = ESC;
615: tbuf[1] = erase_char;
616: tbuf[2] = '\0';
617: put_ecmd(tbuf, EC_W_BACKSPACE);
618:
619: if (werase_char != 0)
620: {
621: tbuf[0] = werase_char;
622: tbuf[1] = '\0';
623: put_ecmd(tbuf, EC_W_BACKSPACE);
624: }
625:
626: /*
627: * Register the two tables.
628: */
629: add_fcmd_table(kfcmdtable, sz_kfcmdtable);
630: add_ecmd_table(kecmdtable, sz_kecmdtable);
631: }
632:
633: #if DEBUG
634: static void
635: get_debug_term()
636: {
637: auto_wrap = 1;
638: ignaw = 1;
639: so_s_width = so_e_width = 0;
640: bo_s_width = bo_e_width = 0;
641: ul_s_width = ul_e_width = 0;
642: bl_s_width = bl_e_width = 0;
643: sc_s_keypad = "(InitKey)";
644: sc_e_keypad = "(DeinitKey)";
645: sc_init = "(InitTerm)";
646: sc_deinit = "(DeinitTerm)";
647: sc_eol_clear = "(ClearEOL)";
648: sc_eos_clear = "(ClearEOS)";
649: sc_clear = "(ClearScreen)";
650: sc_move = "(Move<%d,%d>)";
651: sc_s_in = "(SO+)";
652: sc_s_out = "(SO-)";
653: sc_u_in = "(UL+)";
654: sc_u_out = "(UL-)";
655: sc_b_in = "(BO+)";
656: sc_b_out = "(BO-)";
657: sc_bl_in = "(BL+)";
658: sc_bl_out = "(BL-)";
659: sc_visual_bell ="(VBell)";
660: sc_backspace = "(BS)";
661: sc_home = "(Home)";
662: sc_lower_left = "(LL)";
663: sc_addline = "(AddLine)";
664: }
665: #endif
666:
667: /*
668: * Get terminal capabilities via termcap.
669: */
670: public void
671: get_term()
672: {
673: char *sp;
674: register char *t1, *t2;
675: register int hard;
676: char *term;
677: char termbuf[2048];
678:
679: static char sbuf[1024];
680:
681: #ifdef OS2
682: /*
683: * Make sure the termcap database is available.
684: */
685: sp = getenv("TERMCAP");
686: if (sp == NULL || *sp == '\0')
687: {
688: char *termcap;
689: if ((sp = homefile("termcap.dat")) != NULL)
690: {
691: termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char));
692: sprintf(termcap, "TERMCAP=%s", sp);
693: free(sp);
694: putenv(termcap);
695: }
696: }
697: #endif
698: /*
699: * Find out what kind of terminal this is.
700: */
701: if ((term = getenv("TERM")) == NULL)
702: term = DEFAULT_TERM;
703: if (tgetent(termbuf, term) <= 0)
704: strcpy(termbuf, "dumb:hc:");
705:
706: hard = tgetflag("hc");
707:
708: /*
709: * Get size of the screen.
710: */
711: scrsize();
712: pos_init();
713:
714: #if DEBUG
715: if (strncmp(term,"LESSDEBUG",9) == 0)
716: {
717: get_debug_term();
718: return;
719: }
720: #endif /* DEBUG */
721:
722: auto_wrap = tgetflag("am");
723: ignaw = tgetflag("xn");
724: above_mem = tgetflag("da");
725: below_mem = tgetflag("db");
726:
727: /*
728: * Assumes termcap variable "sg" is the printing width of:
729: * the standout sequence, the end standout sequence,
730: * the underline sequence, the end underline sequence,
731: * the boldface sequence, and the end boldface sequence.
732: */
733: if ((so_s_width = tgetnum("sg")) < 0)
734: so_s_width = 0;
735: so_e_width = so_s_width;
736:
737: bo_s_width = bo_e_width = so_s_width;
738: ul_s_width = ul_e_width = so_s_width;
739: bl_s_width = bl_e_width = so_s_width;
740:
741: #if HILITE_SEARCH
742: if (so_s_width > 0 || so_e_width > 0)
743: /*
744: * Disable highlighting by default on magic cookie terminals.
745: * Turning on highlighting might change the displayed width
746: * of a line, causing the display to get messed up.
747: * The user can turn it back on with -g,
748: * but she won't like the results.
749: */
750: hilite_search = 0;
751: #endif
752:
753: /*
754: * Get various string-valued capabilities.
755: */
756: sp = sbuf;
757:
758: #if HAVE_OSPEED
759: sc_pad = tgetstr("pc", &sp);
760: if (sc_pad != NULL)
761: PC = *sc_pad;
762: #endif
763:
764: sc_s_keypad = tgetstr("ks", &sp);
765: if (sc_s_keypad == NULL)
766: sc_s_keypad = "";
767: sc_e_keypad = tgetstr("ke", &sp);
768: if (sc_e_keypad == NULL)
769: sc_e_keypad = "";
770:
1.2 etheisen 771: /*
772: * This loses for terminals with termcap entries with ti/te strings
773: * that switch to/from an alternate screen, and we're in quit_at_eof
774: * (eg, more(1)).
775: */
1.6 ! deraadt 776: if (!quit_at_eof && !more_mode) {
1.2 etheisen 777: sc_init = tgetstr("ti", &sp);
778: sc_deinit = tgetstr("te", &sp);
779: }
1.1 etheisen 780: if (sc_init == NULL)
781: sc_init = "";
782: if (sc_deinit == NULL)
783: sc_deinit = "";
784:
785: sc_eol_clear = tgetstr("ce", &sp);
786: if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
787: {
788: cannot("clear to end of line");
789: sc_eol_clear = "";
790: }
791:
792: sc_eos_clear = tgetstr("cd", &sp);
793: if (below_mem &&
794: (hard || sc_eos_clear == NULL || *sc_eos_clear == '\0'))
795: {
796: cannot("clear to end of screen");
797: sc_eol_clear = "";
798: }
799:
800: sc_clear = tgetstr("cl", &sp);
801: if (hard || sc_clear == NULL || *sc_clear == '\0')
802: {
803: cannot("clear screen");
804: sc_clear = "\n\n";
805: }
806:
807: sc_move = tgetstr("cm", &sp);
808: if (hard || sc_move == NULL || *sc_move == '\0')
809: {
810: /*
811: * This is not an error here, because we don't
812: * always need sc_move.
813: * We need it only if we don't have home or lower-left.
814: */
815: sc_move = "";
816: can_goto_line = 0;
817: } else
818: can_goto_line = 1;
819:
820: sc_s_in = tgetstr("so", &sp);
821: if (hard || sc_s_in == NULL)
822: sc_s_in = "";
823:
824: sc_s_out = tgetstr("se", &sp);
825: if (hard || sc_s_out == NULL)
826: sc_s_out = "";
827:
828: sc_u_in = tgetstr("us", &sp);
829: if (hard || sc_u_in == NULL)
830: sc_u_in = sc_s_in;
831:
832: sc_u_out = tgetstr("ue", &sp);
833: if (hard || sc_u_out == NULL)
834: sc_u_out = sc_s_out;
835:
836: sc_b_in = tgetstr("md", &sp);
837: if (hard || sc_b_in == NULL)
838: {
839: sc_b_in = sc_s_in;
840: sc_b_out = sc_s_out;
841: } else
842: {
843: sc_b_out = tgetstr("me", &sp);
844: if (hard || sc_b_out == NULL)
845: sc_b_out = "";
846: }
847:
848: sc_bl_in = tgetstr("mb", &sp);
849: if (hard || sc_bl_in == NULL)
850: {
851: sc_bl_in = sc_s_in;
852: sc_bl_out = sc_s_out;
853: } else
854: {
855: sc_bl_out = tgetstr("me", &sp);
856: if (hard || sc_bl_out == NULL)
857: sc_bl_out = "";
858: }
859:
860: sc_visual_bell = tgetstr("vb", &sp);
861: if (hard || sc_visual_bell == NULL)
862: sc_visual_bell = "";
863:
864: if (tgetflag("bs"))
865: sc_backspace = "\b";
866: else
867: {
868: sc_backspace = tgetstr("bc", &sp);
869: if (sc_backspace == NULL || *sc_backspace == '\0')
870: sc_backspace = "\b";
871: }
872:
873: /*
874: * Choose between using "ho" and "cm" ("home" and "cursor move")
875: * to move the cursor to the upper left corner of the screen.
876: */
877: t1 = tgetstr("ho", &sp);
878: if (hard || t1 == NULL)
879: t1 = "";
880: if (*sc_move == '\0')
881: t2 = "";
882: else
883: {
884: strcpy(sp, tgoto(sc_move, 0, 0));
885: t2 = sp;
886: sp += strlen(sp) + 1;
887: }
888: sc_home = cheaper(t1, t2, "home cursor", "|\b^");
889:
890: /*
891: * Choose between using "ll" and "cm" ("lower left" and "cursor move")
892: * to move the cursor to the lower left corner of the screen.
893: */
894: t1 = tgetstr("ll", &sp);
895: if (hard || t1 == NULL)
896: t1 = "";
897: if (*sc_move == '\0')
898: t2 = "";
899: else
900: {
901: strcpy(sp, tgoto(sc_move, 0, sc_height-1));
902: t2 = sp;
903: sp += strlen(sp) + 1;
904: }
905: sc_lower_left = cheaper(t1, t2,
906: "move cursor to lower left of screen", "\r");
907:
908: /*
909: * Choose between using "al" or "sr" ("add line" or "scroll reverse")
910: * to add a line at the top of the screen.
911: */
912: t1 = tgetstr("al", &sp);
913: if (hard || t1 == NULL)
914: t1 = "";
915: t2 = tgetstr("sr", &sp);
916: if (hard || t2 == NULL)
917: t2 = "";
918: #if OS2
919: if (*t1 == '\0' && *t2 == '\0')
920: sc_addline = "";
921: else
922: #endif
923: if (above_mem)
924: sc_addline = t1;
925: else
926: sc_addline = cheaper(t1, t2, "scroll backwards", "");
927: if (*sc_addline == '\0')
928: {
929: /*
930: * Force repaint on any backward movement.
931: */
932: back_scroll = 0;
933: }
934: }
935:
936: /*
937: * Return the cost of displaying a termcap string.
938: * We use the trick of calling tputs, but as a char printing function
939: * we give it inc_costcount, which just increments "costcount".
940: * This tells us how many chars would be printed by using this string.
941: * {{ Couldn't we just use strlen? }}
942: */
943: static int costcount;
944:
945: /*ARGSUSED*/
946: static int
947: inc_costcount(c)
948: int c;
949: {
950: costcount++;
951: return (c);
952: }
953:
954: static int
955: cost(t)
956: char *t;
957: {
958: costcount = 0;
959: tputs(t, sc_height, inc_costcount);
960: return (costcount);
961: }
962:
963: /*
964: * Return the "best" of the two given termcap strings.
965: * The best, if both exist, is the one with the lower
966: * cost (see cost() function).
967: */
968: static char *
969: cheaper(t1, t2, doit, def)
970: char *t1, *t2;
971: char *doit;
972: char *def;
973: {
974: if (*t1 == '\0' && *t2 == '\0')
975: {
976: cannot(doit);
977: return (def);
978: }
979: if (*t1 == '\0')
980: return (t2);
981: if (*t2 == '\0')
982: return (t1);
983: if (cost(t1) < cost(t2))
984: return (t1);
985: return (t2);
986: }
987:
988:
989: /*
990: * Below are the functions which perform all the
991: * terminal-specific screen manipulation.
992: */
993:
994:
995: /*
996: * Initialize terminal
997: */
998: public void
999: init()
1000: {
1001: if (no_init)
1002: return;
1003: tputs(sc_init, sc_height, putchr);
1004: tputs(sc_s_keypad, sc_height, putchr);
1005: init_done = 1;
1006: }
1007:
1008: /*
1009: * Deinitialize terminal
1010: */
1011: public void
1012: deinit()
1013: {
1014: if (no_init)
1015: return;
1016: if (!init_done)
1017: return;
1018: tputs(sc_e_keypad, sc_height, putchr);
1019: tputs(sc_deinit, sc_height, putchr);
1020: init_done = 0;
1021: }
1022:
1023: /*
1024: * Home cursor (move to upper left corner of screen).
1025: */
1026: public void
1027: home()
1028: {
1029: tputs(sc_home, 1, putchr);
1030: }
1031:
1032: /*
1033: * Add a blank line (called with cursor at home).
1034: * Should scroll the display down.
1035: */
1036: public void
1037: add_line()
1038: {
1039: tputs(sc_addline, sc_height, putchr);
1040: }
1041:
1042: /*
1043: * Move cursor to lower left corner of screen.
1044: */
1045: public void
1046: lower_left()
1047: {
1048: tputs(sc_lower_left, 1, putchr);
1049: }
1050:
1051: /*
1052: * Goto a specific line on the screen.
1053: */
1054: public void
1055: goto_line(slinenum)
1056: int slinenum;
1057: {
1058: char *sc_goto;
1059:
1060: sc_goto = tgoto(sc_move, 0, slinenum);
1061: tputs(sc_goto, 1, putchr);
1062: }
1063:
1064: /*
1065: * Ring the terminal bell.
1066: */
1067: public void
1068: bell()
1069: {
1070: if (quiet == VERY_QUIET)
1071: vbell();
1072: else
1073: putchr('\7');
1074: }
1075:
1076: /*
1077: * Output the "visual bell", if there is one.
1078: */
1079: public void
1080: vbell()
1081: {
1082: if (*sc_visual_bell == '\0')
1083: return;
1084: tputs(sc_visual_bell, sc_height, putchr);
1085: }
1086:
1087: /*
1088: * Clear the screen.
1089: */
1090: public void
1091: clear()
1092: {
1093: tputs(sc_clear, sc_height, putchr);
1094: }
1095:
1096: /*
1097: * Clear from the cursor to the end of the cursor's line.
1098: * {{ This must not move the cursor. }}
1099: */
1100: public void
1101: clear_eol()
1102: {
1103: tputs(sc_eol_clear, 1, putchr);
1104: }
1105:
1106: /*
1107: * Clear the bottom line of the display.
1108: * Leave the cursor at the beginning of the bottom line.
1109: */
1110: public void
1111: clear_bot()
1112: {
1113: lower_left();
1114: if (below_mem)
1115: tputs(sc_eos_clear, 1, putchr);
1116: else
1117: tputs(sc_eol_clear, 1, putchr);
1118: }
1119:
1120: /*
1121: * Begin "standout" (bold, underline, or whatever).
1122: */
1123: public void
1124: so_enter()
1125: {
1126: tputs(sc_s_in, 1, putchr);
1127: }
1128:
1129: /*
1130: * End "standout".
1131: */
1132: public void
1133: so_exit()
1134: {
1135: tputs(sc_s_out, 1, putchr);
1136: }
1137:
1138: /*
1139: * Begin "underline" (hopefully real underlining,
1140: * otherwise whatever the terminal provides).
1141: */
1142: public void
1143: ul_enter()
1144: {
1145: tputs(sc_u_in, 1, putchr);
1146: }
1147:
1148: /*
1149: * End "underline".
1150: */
1151: public void
1152: ul_exit()
1153: {
1154: tputs(sc_u_out, 1, putchr);
1155: }
1156:
1157: /*
1158: * Begin "bold"
1159: */
1160: public void
1161: bo_enter()
1162: {
1163: tputs(sc_b_in, 1, putchr);
1164: }
1165:
1166: /*
1167: * End "bold".
1168: */
1169: public void
1170: bo_exit()
1171: {
1172: tputs(sc_b_out, 1, putchr);
1173: }
1174:
1175: /*
1176: * Begin "blink"
1177: */
1178: public void
1179: bl_enter()
1180: {
1181: tputs(sc_bl_in, 1, putchr);
1182: }
1183:
1184: /*
1185: * End "blink".
1186: */
1187: public void
1188: bl_exit()
1189: {
1190: tputs(sc_bl_out, 1, putchr);
1191: }
1192:
1193: /*
1194: * Erase the character to the left of the cursor
1195: * and move the cursor left.
1196: */
1197: public void
1198: backspace()
1199: {
1200: /*
1201: * Try to erase the previous character by overstriking with a space.
1202: */
1203: tputs(sc_backspace, 1, putchr);
1204: putchr(' ');
1205: tputs(sc_backspace, 1, putchr);
1206: }
1207:
1208: /*
1209: * Output a plain backspace, without erasing the previous char.
1210: */
1211: public void
1212: putbs()
1213: {
1214: tputs(sc_backspace, 1, putchr);
1215: }