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