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