|
|
1.1 ! root 1: /* ! 2: * Routines which deal with the characteristics of the terminal. ! 3: * Uses termcap to be as terminal-independent as possible. ! 4: * ! 5: * {{ Someday this should be rewritten to use curses. }} ! 6: */ ! 7: ! 8: #include "less.h" ! 9: #if XENIX ! 10: #include <sys/types.h> ! 11: #include <sys/ioctl.h> ! 12: #endif ! 13: ! 14: #if TERMIO ! 15: #include <termio.h> ! 16: #else ! 17: #include <sgtty.h> ! 18: #endif ! 19: ! 20: /* ! 21: * Strings passed to tputs() to do various terminal functions. ! 22: */ ! 23: static char ! 24: *sc_pad, /* Pad string */ ! 25: *sc_home, /* Cursor home */ ! 26: *sc_addline, /* Add line, scroll down following lines */ ! 27: *sc_lower_left, /* Cursor to last line, first column */ ! 28: *sc_move, /* General cursor positioning */ ! 29: *sc_clear, /* Clear screen */ ! 30: *sc_eol_clear, /* Clear to end of line */ ! 31: *sc_s_in, /* Enter standout (highlighted) mode */ ! 32: *sc_s_out, /* Exit standout mode */ ! 33: *sc_u_in, /* Enter underline mode */ ! 34: *sc_u_out, /* Exit underline mode */ ! 35: *sc_visual_bell, /* Visual bell (flash screen) sequence */ ! 36: *sc_backspace, /* Backspace cursor */ ! 37: *sc_init, /* Startup terminal initialization */ ! 38: *sc_deinit; /* Exit terminal de-intialization */ ! 39: static int dumb; ! 40: static int hard; ! 41: ! 42: public int auto_wrap; /* Terminal does \r\n when write past margin */ ! 43: public int ignaw; /* Terminal ignores \n immediately after wrap */ ! 44: public int erase_char, kill_char; /* The user's erase and line-kill chars */ ! 45: public int sc_width, sc_height; /* Height & width of screen */ ! 46: public int ul_width, ue_width; /* Printing width of underline sequences */ ! 47: public int so_width, se_width; /* Printing width of standout sequences */ ! 48: ! 49: /* ! 50: * These two variables are sometimes defined in, ! 51: * and needed by, the termcap library. ! 52: * It may be necessary on some systems to declare them extern here. ! 53: */ ! 54: /*extern*/ short ospeed; /* Terminal output baud rate */ ! 55: /*extern*/ char PC; /* Pad character */ ! 56: ! 57: extern int quiet; /* If VERY_QUIET, use visual bell for bell */ ! 58: extern int know_dumb; /* Don't complain about a dumb terminal */ ! 59: extern int back_scroll; ! 60: char *tgetstr(); ! 61: char *tgoto(); ! 62: ! 63: /* ! 64: * Change terminal to "raw mode", or restore to "normal" mode. ! 65: * "Raw mode" means ! 66: * 1. An outstanding read will complete on receipt of a single keystroke. ! 67: * 2. Input is not echoed. ! 68: * 3. On output, \n is mapped to \r\n. ! 69: * 4. \t is NOT be expanded into spaces. ! 70: * 5. Signal-causing characters such as ctrl-C (interrupt), ! 71: * etc. are NOT disabled. ! 72: * It doesn't matter whether an input \n is mapped to \r, or vice versa. ! 73: */ ! 74: public void ! 75: raw_mode(on) ! 76: int on; ! 77: { ! 78: #if TERMIO ! 79: struct termio s; ! 80: static struct termio save_term; ! 81: ! 82: if (on) ! 83: { ! 84: /* ! 85: * Get terminal modes. ! 86: */ ! 87: ioctl(2, TCGETA, &s); ! 88: ! 89: /* ! 90: * Save modes and set certain variables dependent on modes. ! 91: */ ! 92: save_term = s; ! 93: ospeed = s.c_cflag & CBAUD; ! 94: erase_char = s.c_cc[VERASE]; ! 95: kill_char = s.c_cc[VKILL]; ! 96: ! 97: /* ! 98: * Set the modes to the way we want them. ! 99: */ ! 100: s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); ! 101: s.c_oflag |= (OPOST|ONLCR|TAB3); ! 102: s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); ! 103: s.c_cc[VMIN] = 1; ! 104: s.c_cc[VTIME] = 0; ! 105: } else ! 106: { ! 107: /* ! 108: * Restore saved modes. ! 109: */ ! 110: s = save_term; ! 111: } ! 112: ioctl(2, TCSETAW, &s); ! 113: #else ! 114: struct sgttyb s; ! 115: static struct sgttyb save_term; ! 116: ! 117: if (on) ! 118: { ! 119: /* ! 120: * Get terminal modes. ! 121: */ ! 122: ioctl(2, TIOCGETP, &s); ! 123: ! 124: /* ! 125: * Save modes and set certain variables dependent on modes. ! 126: */ ! 127: save_term = s; ! 128: ospeed = s.sg_ospeed; ! 129: erase_char = s.sg_erase; ! 130: kill_char = s.sg_kill; ! 131: ! 132: /* ! 133: * Set the modes to the way we want them. ! 134: */ ! 135: s.sg_flags |= CBREAK; ! 136: s.sg_flags &= ~(ECHO|XTABS); ! 137: } else ! 138: { ! 139: /* ! 140: * Restore saved modes. ! 141: */ ! 142: s = save_term; ! 143: } ! 144: ioctl(2, TIOCSETN, &s); ! 145: #endif ! 146: } ! 147: ! 148: static int couldnt = 0; ! 149: ! 150: static void ! 151: cannot(s) ! 152: char *s; ! 153: { ! 154: if (know_dumb) ! 155: /* ! 156: * He knows he has a dumb terminal, so don't tell him. ! 157: */ ! 158: return; ! 159: ! 160: printf("WARNING: terminal cannot \"%s\"\n", s); ! 161: couldnt = 1; ! 162: } ! 163: ! 164: /* ! 165: * Get terminal capabilities via termcap. ! 166: */ ! 167: public void ! 168: get_term() ! 169: { ! 170: char termbuf[1024]; ! 171: char *sp; ! 172: static char sbuf[150]; ! 173: ! 174: char *getenv(); ! 175: ! 176: /* ! 177: * Find out what kind of terminal this is. ! 178: */ ! 179: if (tgetent(termbuf, getenv("TERM")) <= 0) ! 180: dumb = 1; ! 181: ! 182: /* ! 183: * Get size of the screen. ! 184: */ ! 185: if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc")) ! 186: { ! 187: /* Oh no, this is a hardcopy terminal. */ ! 188: hard = 1; ! 189: sc_height = 24; ! 190: } ! 191: if (dumb || (sc_width = tgetnum("co")) < 0) ! 192: sc_width = 80; ! 193: ! 194: auto_wrap = tgetflag("am"); ! 195: ignaw = tgetflag("xn"); ! 196: ! 197: /* ! 198: * Assumes termcap variable "sg" is the printing width of ! 199: * the standout sequence, the end standout sequence, ! 200: * the underline sequence, and the end underline sequence. ! 201: */ ! 202: if ((ul_width = tgetnum("sg")) < 0) ! 203: ul_width = 0; ! 204: so_width = se_width = ue_width = ul_width; ! 205: ! 206: /* ! 207: * Get various string-valued capabilities. ! 208: */ ! 209: sp = sbuf; ! 210: ! 211: sc_pad = (dumb) ? NULL : tgetstr("pc", &sp); ! 212: if (sc_pad != NULL) ! 213: PC = *sc_pad; ! 214: ! 215: sc_init = (dumb) ? NULL : tgetstr("ti", &sp); ! 216: if (sc_init == NULL) ! 217: sc_init = ""; ! 218: ! 219: sc_deinit= (dumb) ? NULL : tgetstr("te", &sp); ! 220: if (sc_deinit == NULL) ! 221: sc_deinit = ""; ! 222: ! 223: sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp); ! 224: if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0') ! 225: { ! 226: cannot("clear to end of line"); ! 227: sc_eol_clear = ""; ! 228: } ! 229: ! 230: sc_clear = (dumb) ? NULL : tgetstr("cl", &sp); ! 231: if (hard || sc_clear == NULL || *sc_clear == '\0') ! 232: { ! 233: cannot("clear screen"); ! 234: sc_clear = "\n\n"; ! 235: } ! 236: ! 237: sc_move = (dumb) ? NULL : tgetstr("cm", &sp); ! 238: if (hard || sc_move == NULL || *sc_move == '\0') ! 239: { ! 240: /* ! 241: * This is not an error here, because we don't ! 242: * always need sc_move. ! 243: * We need it only if we don't have home or lower-left. ! 244: */ ! 245: sc_move = ""; ! 246: } ! 247: ! 248: sc_s_in = (dumb) ? NULL : tgetstr("so", &sp); ! 249: if (hard || sc_s_in == NULL) ! 250: sc_s_in = ""; ! 251: ! 252: sc_s_out = (dumb) ? NULL : tgetstr("se", &sp); ! 253: if (hard || sc_s_out == NULL) ! 254: sc_s_out = ""; ! 255: ! 256: sc_u_in = (dumb) ? NULL : tgetstr("us", &sp); ! 257: if (hard || sc_u_in == NULL) ! 258: sc_u_in = sc_s_in; ! 259: ! 260: sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp); ! 261: if (hard || sc_u_out == NULL) ! 262: sc_u_out = sc_s_out; ! 263: ! 264: sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp); ! 265: if (hard || sc_visual_bell == NULL) ! 266: sc_visual_bell = ""; ! 267: ! 268: sc_home = (dumb) ? NULL : tgetstr("ho", &sp); ! 269: if (hard || sc_home == NULL || *sc_home == '\0') ! 270: { ! 271: if (*sc_move == '\0') ! 272: { ! 273: cannot("home cursor"); ! 274: /* ! 275: * This last resort for sc_home is supposed to ! 276: * be an up-arrow suggesting moving to the ! 277: * top of the "virtual screen". (The one in ! 278: * your imagination as you try to use this on ! 279: * a hard copy terminal.) ! 280: */ ! 281: sc_home = "|\b^"; ! 282: } else ! 283: { ! 284: /* ! 285: * No "home" string, ! 286: * but we can use "move(0,0)". ! 287: */ ! 288: strcpy(sp, tgoto(sc_move, 0, 0)); ! 289: sc_home = sp; ! 290: sp += strlen(sp) + 1; ! 291: } ! 292: } ! 293: ! 294: sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp); ! 295: if (hard || sc_lower_left == NULL || *sc_lower_left == '\0') ! 296: { ! 297: if (*sc_move == '\0') ! 298: { ! 299: cannot("move cursor to lower left of screen"); ! 300: sc_lower_left = "\r"; ! 301: } else ! 302: { ! 303: /* ! 304: * No "lower-left" string, ! 305: * but we can use "move(0,last-line)". ! 306: */ ! 307: strcpy(sp, tgoto(sc_move, 0, sc_height-1)); ! 308: sc_lower_left = sp; ! 309: sp += strlen(sp) + 1; ! 310: } ! 311: } ! 312: ! 313: /* ! 314: * To add a line at top of screen and scroll the display down, ! 315: * we use "al" (add line) or "sr" (scroll reverse). ! 316: */ ! 317: if (dumb) ! 318: sc_addline = NULL; ! 319: else if ((sc_addline = tgetstr("al", &sp)) == NULL || ! 320: *sc_addline == '\0') ! 321: sc_addline = tgetstr("sr", &sp); ! 322: ! 323: if (hard || sc_addline == NULL || *sc_addline == '\0') ! 324: { ! 325: cannot("scroll backwards"); ! 326: sc_addline = ""; ! 327: /* Force repaint on any backward movement */ ! 328: back_scroll = 0; ! 329: } ! 330: ! 331: if (dumb || tgetflag("bs")) ! 332: sc_backspace = "\b"; ! 333: else ! 334: { ! 335: sc_backspace = tgetstr("bc", &sp); ! 336: if (sc_backspace == NULL || *sc_backspace == '\0') ! 337: sc_backspace = "\b"; ! 338: } ! 339: ! 340: if (couldnt) ! 341: /* Give him time to read all the "cannot" messages. */ ! 342: error(""); ! 343: } ! 344: ! 345: ! 346: /* ! 347: * Below are the functions which perform all the ! 348: * terminal-specific screen manipulation. ! 349: */ ! 350: ! 351: ! 352: /* ! 353: * Initialize terminal ! 354: */ ! 355: public void ! 356: init() ! 357: { ! 358: tputs(sc_init, sc_height, putc); ! 359: } ! 360: ! 361: /* ! 362: * Deinitialize terminal ! 363: */ ! 364: public void ! 365: deinit() ! 366: { ! 367: tputs(sc_deinit, sc_height, putc); ! 368: } ! 369: ! 370: /* ! 371: * Home cursor (move to upper left corner of screen). ! 372: */ ! 373: public void ! 374: home() ! 375: { ! 376: tputs(sc_home, 1, putc); ! 377: } ! 378: ! 379: /* ! 380: * Add a blank line (called with cursor at home). ! 381: * Should scroll the display down. ! 382: */ ! 383: public void ! 384: add_line() ! 385: { ! 386: tputs(sc_addline, sc_height, putc); ! 387: } ! 388: ! 389: /* ! 390: * Move cursor to lower left corner of screen. ! 391: */ ! 392: public void ! 393: lower_left() ! 394: { ! 395: tputs(sc_lower_left, 1, putc); ! 396: } ! 397: ! 398: /* ! 399: * Ring the terminal bell. ! 400: */ ! 401: public void ! 402: bell() ! 403: { ! 404: if (quiet == VERY_QUIET) ! 405: vbell(); ! 406: else ! 407: putc('\7'); ! 408: } ! 409: ! 410: /* ! 411: * Output the "visual bell", if there is one. ! 412: */ ! 413: public void ! 414: vbell() ! 415: { ! 416: if (*sc_visual_bell == '\0') ! 417: return; ! 418: tputs(sc_visual_bell, sc_height, putc); ! 419: } ! 420: ! 421: /* ! 422: * Clear the screen. ! 423: */ ! 424: public void ! 425: clear() ! 426: { ! 427: tputs(sc_clear, sc_height, putc); ! 428: } ! 429: ! 430: /* ! 431: * Clear from the cursor to the end of the cursor's line. ! 432: * {{ This must not move the cursor. }} ! 433: */ ! 434: public void ! 435: clear_eol() ! 436: { ! 437: tputs(sc_eol_clear, 1, putc); ! 438: } ! 439: ! 440: /* ! 441: * Begin "standout" (bold, underline, or whatever). ! 442: */ ! 443: public void ! 444: so_enter() ! 445: { ! 446: tputs(sc_s_in, 1, putc); ! 447: } ! 448: ! 449: /* ! 450: * End "standout". ! 451: */ ! 452: public void ! 453: so_exit() ! 454: { ! 455: tputs(sc_s_out, 1, putc); ! 456: } ! 457: ! 458: /* ! 459: * Begin "underline" (hopefully real underlining, ! 460: * otherwise whatever the terminal provides). ! 461: */ ! 462: public void ! 463: ul_enter() ! 464: { ! 465: tputs(sc_u_in, 1, putc); ! 466: } ! 467: ! 468: /* ! 469: * End "underline". ! 470: */ ! 471: public void ! 472: ul_exit() ! 473: { ! 474: tputs(sc_u_out, 1, putc); ! 475: } ! 476: ! 477: /* ! 478: * Erase the character to the left of the cursor ! 479: * and move the cursor left. ! 480: */ ! 481: public void ! 482: backspace() ! 483: { ! 484: /* ! 485: * Try to erase the previous character by overstriking with a space. ! 486: */ ! 487: tputs(sc_backspace, 1, putc); ! 488: putc(' '); ! 489: tputs(sc_backspace, 1, putc); ! 490: } ! 491: ! 492: /* ! 493: * Output a plain backspace, without erasing the previous char. ! 494: */ ! 495: public void ! 496: putbs() ! 497: { ! 498: tputs(sc_backspace, 1, putc); ! 499: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.