Annotation of src/usr.bin/less/screen.c, Revision 1.18
1.1 etheisen 1: /*
1.17 shadchin 2: * Copyright (C) 1984-2012 Mark Nudelman
1.1 etheisen 3: *
1.11 millert 4: * You may distribute under the terms of either the GNU General Public
5: * License or the Less License, as specified in the README file.
1.1 etheisen 6: *
1.17 shadchin 7: * For more information, see the README file.
1.1 etheisen 8: */
1.18 ! nicm 9: /*
! 10: * Modified for use with illumos.
! 11: * Copyright 2014 Garrett D'Amore <garrett@damore.org>
! 12: */
1.1 etheisen 13:
14: /*
15: * Routines which deal with the characteristics of the terminal.
16: * Uses termcap to be as terminal-independent as possible.
17: */
18:
19: #include "less.h"
20: #include "cmd.h"
21:
1.15 shadchin 22: #include <termios.h>
1.18 ! nicm 23: #include <term.h>
1.11 millert 24:
1.1 etheisen 25: #define DEFAULT_TERM "unknown"
1.11 millert 26:
1.1 etheisen 27: /*
28: * Strings passed to tputs() to do various terminal functions.
29: */
30: static char
31: *sc_home, /* Cursor home */
32: *sc_addline, /* Add line, scroll down following lines */
33: *sc_lower_left, /* Cursor to last line, first column */
1.15 shadchin 34: *sc_return, /* Cursor to beginning of current line */
1.1 etheisen 35: *sc_move, /* General cursor positioning */
36: *sc_clear, /* Clear screen */
37: *sc_eol_clear, /* Clear to end of line */
38: *sc_eos_clear, /* Clear to end of screen */
39: *sc_s_in, /* Enter standout (highlighted) mode */
40: *sc_s_out, /* Exit standout mode */
41: *sc_u_in, /* Enter underline mode */
42: *sc_u_out, /* Exit underline mode */
43: *sc_b_in, /* Enter bold mode */
44: *sc_b_out, /* Exit bold mode */
45: *sc_bl_in, /* Enter blink mode */
46: *sc_bl_out, /* Exit blink mode */
47: *sc_visual_bell, /* Visual bell (flash screen) sequence */
48: *sc_backspace, /* Backspace cursor */
49: *sc_s_keypad, /* Start keypad mode */
50: *sc_e_keypad, /* End keypad mode */
51: *sc_init, /* Startup terminal initialization */
52: *sc_deinit; /* Exit terminal de-initialization */
53:
54: static int init_done = 0;
55:
1.18 ! nicm 56: int auto_wrap; /* Terminal does \r\n when write past margin */
! 57: int ignaw; /* Terminal ignores \n immediately after wrap */
! 58: int erase_char; /* The user's erase char */
! 59: int erase2_char; /* The user's other erase char */
! 60: int kill_char; /* The user's line-kill char */
! 61: int werase_char; /* The user's word-erase char */
! 62: int sc_width, sc_height; /* Height & width of screen */
! 63: int bo_s_width, bo_e_width; /* Printing width of boldface seq */
! 64: int ul_s_width, ul_e_width; /* Printing width of underline seq */
! 65: int so_s_width, so_e_width; /* Printing width of standout seq */
! 66: int bl_s_width, bl_e_width; /* Printing width of blink seq */
! 67: int can_goto_line; /* Can move cursor to any line */
! 68: int missing_cap = 0; /* Some capability is missing */
! 69: static int above_mem; /* Memory retained above screen */
! 70: static int below_mem; /* Memory retained below screen */
1.11 millert 71:
72: static int attrmode = AT_NORMAL;
1.15 shadchin 73: extern int binattr;
1.1 etheisen 74:
1.18 ! nicm 75: static char *cheaper(char *, char *, char *);
! 76: static void tmodes(char *, char *, char **, char **, char *, char *);
1.1 etheisen 77:
78: extern int quiet; /* If VERY_QUIET, use visual bell for bell */
1.11 millert 79: extern int no_back_scroll;
1.1 etheisen 80: extern int swindow;
81: extern int no_init;
1.11 millert 82: extern int no_keypad;
1.16 millert 83: extern volatile sig_atomic_t sigs;
1.11 millert 84: extern int wscroll;
85: extern int screen_trashed;
86: extern int tty;
1.15 shadchin 87: extern int top_scroll;
88: extern int oldbot;
1.1 etheisen 89: extern int hilite_search;
90:
91: /*
92: * Change terminal to "raw mode", or restore to "normal" mode.
1.18 ! nicm 93: * "Raw mode" means
1.1 etheisen 94: * 1. An outstanding read will complete on receipt of a single keystroke.
1.18 ! nicm 95: * 2. Input is not echoed.
1.1 etheisen 96: * 3. On output, \n is mapped to \r\n.
97: * 4. \t is NOT expanded into spaces.
98: * 5. Signal-causing characters such as ctrl-C (interrupt),
99: * etc. are NOT disabled.
100: * It doesn't matter whether an input \n is mapped to \r, or vice versa.
101: */
1.18 ! nicm 102: void
! 103: raw_mode(int on)
1.1 etheisen 104: {
105: static int curr_on = 0;
1.18 ! nicm 106: struct termios s;
! 107: static struct termios save_term;
! 108: static int saved_term = 0;
1.1 etheisen 109:
110: if (on == curr_on)
111: return;
1.15 shadchin 112: erase2_char = '\b'; /* in case OS doesn't know about erase2 */
1.1 etheisen 113:
1.18 ! nicm 114: if (on) {
1.1 etheisen 115: /*
116: * Get terminal modes.
117: */
1.18 ! nicm 118: (void) tcgetattr(tty, &s);
1.1 etheisen 119:
120: /*
121: * Save modes and set certain variables dependent on modes.
122: */
1.18 ! nicm 123: if (!saved_term) {
1.11 millert 124: save_term = s;
125: saved_term = 1;
126: }
1.18 ! nicm 127:
1.1 etheisen 128: erase_char = s.c_cc[VERASE];
1.15 shadchin 129: #ifdef VERASE2
130: erase2_char = s.c_cc[VERASE2];
131: #endif
1.1 etheisen 132: kill_char = s.c_cc[VKILL];
133: #ifdef VWERASE
134: werase_char = s.c_cc[VWERASE];
135: #endif
136:
137: /*
138: * Set the modes to the way we want them.
139: */
1.18 ! nicm 140: s.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
1.1 etheisen 141:
1.18 ! nicm 142: #ifndef TAB3
! 143: #define TAB3 0 /* Its a lie, but TAB3 isn't defined by POSIX. */
1.1 etheisen 144: #endif
1.18 ! nicm 145: s.c_oflag |= (TAB3 | OPOST | ONLCR);
! 146: s.c_oflag &= ~(OCRNL | ONOCR | ONLRET);
1.1 etheisen 147: s.c_cc[VMIN] = 1;
148: s.c_cc[VTIME] = 0;
1.11 millert 149: #ifdef VLNEXT
150: s.c_cc[VLNEXT] = 0;
151: #endif
152: #ifdef VDSUSP
153: s.c_cc[VDSUSP] = 0;
154: #endif
1.18 ! nicm 155: } else {
1.11 millert 156: /*
157: * Restore saved modes.
158: */
159: s = save_term;
160: }
1.18 ! nicm 161: (void) tcsetattr(tty, TCSASOFT | TCSADRAIN, &s);
! 162: (void) fsync(tty);
1.1 etheisen 163: curr_on = on;
164: }
165:
1.11 millert 166: /*
167: * Some glue to prevent calling termcap functions if tgetent() failed.
168: */
169: static int hardcopy;
170:
1.1 etheisen 171: /*
1.11 millert 172: * Get size of the output screen.
1.1 etheisen 173: */
1.18 ! nicm 174: static void
! 175: scrsize(void)
1.1 etheisen 176: {
1.18 ! nicm 177: char *s;
1.11 millert 178: int sys_height;
179: int sys_width;
180: int n;
1.18 ! nicm 181: #ifdef TIOCGWINSIZE
! 182: struct winsize w;
1.11 millert 183: #endif
1.1 etheisen 184:
1.11 millert 185: #define DEF_SC_WIDTH 80
186: #define DEF_SC_HEIGHT 24
1.1 etheisen 187:
1.11 millert 188: sys_width = sys_height = 0;
1.1 etheisen 189:
1.18 ! nicm 190: #ifdef TIOCGWINSIZE
! 191: if (ioctl(2, TIOCGWINSZ, &w) == 0) {
! 192: if (w.ws_row > 0)
! 193: sys_height = w.ws_row;
! 194: if (w.ws_col > 0)
! 195: sys_width = w.ws_col;
1.1 etheisen 196: }
1.11 millert 197: #endif
1.1 etheisen 198:
1.11 millert 199: if (sys_height > 0)
200: sc_height = sys_height;
201: else if ((s = lgetenv("LINES")) != NULL)
202: sc_height = atoi(s);
1.18 ! nicm 203: else if (!hardcopy && (n = lines) > 0)
! 204: sc_height = n;
1.17 shadchin 205: if (sc_height <= 0)
1.11 millert 206: sc_height = DEF_SC_HEIGHT;
1.1 etheisen 207:
1.11 millert 208: if (sys_width > 0)
209: sc_width = sys_width;
210: else if ((s = lgetenv("COLUMNS")) != NULL)
211: sc_width = atoi(s);
1.18 ! nicm 212: else if (!hardcopy && (n = columns) > 0)
! 213: sc_width = n;
1.17 shadchin 214: if (sc_width <= 0)
1.11 millert 215: sc_width = DEF_SC_WIDTH;
216: }
1.1 etheisen 217:
218: /*
1.11 millert 219: * Return the characters actually input by a "special" key.
1.1 etheisen 220: */
1.18 ! nicm 221: char *
! 222: special_key_str(int key)
1.1 etheisen 223: {
1.11 millert 224: char *s;
1.18 ! nicm 225: static char ctrlk[] = { CONTROL('K'), 0 };
! 226:
! 227: if (hardcopy)
! 228: return (NULL);
1.1 etheisen 229:
1.18 ! nicm 230: switch (key) {
1.11 millert 231: case SK_RIGHT_ARROW:
1.18 ! nicm 232: s = key_right;
1.11 millert 233: break;
234: case SK_LEFT_ARROW:
1.18 ! nicm 235: s = key_left;
1.11 millert 236: break;
237: case SK_UP_ARROW:
1.18 ! nicm 238: s = key_up;
1.11 millert 239: break;
240: case SK_DOWN_ARROW:
1.18 ! nicm 241: s = key_down;
1.11 millert 242: break;
243: case SK_PAGE_UP:
1.18 ! nicm 244: s = key_ppage;
1.11 millert 245: break;
246: case SK_PAGE_DOWN:
1.18 ! nicm 247: s = key_npage;
1.11 millert 248: break;
249: case SK_HOME:
1.18 ! nicm 250: s = key_home;
1.11 millert 251: break;
252: case SK_END:
1.18 ! nicm 253: s = key_end;
1.11 millert 254: break;
255: case SK_DELETE:
1.18 ! nicm 256: s = key_dc;
! 257: if (s == NULL) {
! 258: s = "\177\0";
1.11 millert 259: }
260: break;
261: case SK_CONTROL_K:
1.18 ! nicm 262: s = ctrlk;
1.11 millert 263: break;
264: default:
265: return (NULL);
266: }
267: return (s);
268: }
269:
270: /*
271: * Get terminal capabilities via termcap.
272: */
1.18 ! nicm 273: void
! 274: get_term(void)
1.11 millert 275: {
1.18 ! nicm 276: char *t1, *t2;
1.11 millert 277: char *term;
278:
1.1 etheisen 279: /*
280: * Find out what kind of terminal this is.
281: */
1.18 ! nicm 282: if ((term = lgetenv("TERM")) == NULL)
! 283: term = DEFAULT_TERM;
1.11 millert 284: hardcopy = 0;
1.18 ! nicm 285:
! 286: if (setupterm(term, 1, NULL) < 0) {
! 287: hardcopy = 1;
! 288: }
! 289: if (hard_copy == 1)
1.11 millert 290: hardcopy = 1;
1.1 etheisen 291:
292: /*
293: * Get size of the screen.
294: */
295: scrsize();
296: pos_init();
297:
1.18 ! nicm 298: auto_wrap = hardcopy ? 0 : auto_right_margin;
! 299: ignaw = hardcopy ? 0 : eat_newline_glitch;
! 300: above_mem = hardcopy ? 0 : memory_above;
! 301: below_mem = hardcopy ? 0 : memory_below;
1.1 etheisen 302:
303: /*
304: * Assumes termcap variable "sg" is the printing width of:
305: * the standout sequence, the end standout sequence,
306: * the underline sequence, the end underline sequence,
307: * the boldface sequence, and the end boldface sequence.
308: */
1.18 ! nicm 309: if (hardcopy || (so_s_width = magic_cookie_glitch) < 0)
1.1 etheisen 310: so_s_width = 0;
311: so_e_width = so_s_width;
312:
313: bo_s_width = bo_e_width = so_s_width;
314: ul_s_width = ul_e_width = so_s_width;
315: bl_s_width = bl_e_width = so_s_width;
316:
317: if (so_s_width > 0 || so_e_width > 0)
318: /*
319: * Disable highlighting by default on magic cookie terminals.
320: * Turning on highlighting might change the displayed width
321: * of a line, causing the display to get messed up.
1.18 ! nicm 322: * The user can turn it back on with -g,
1.1 etheisen 323: * but she won't like the results.
324: */
325: hilite_search = 0;
326:
327: /*
328: * Get various string-valued capabilities.
329: */
330:
1.18 ! nicm 331: sc_s_keypad = keypad_xmit;
! 332: if (hardcopy || sc_s_keypad == NULL)
1.1 etheisen 333: sc_s_keypad = "";
1.18 ! nicm 334: sc_e_keypad = keypad_local;
! 335: if (hardcopy || sc_e_keypad == NULL)
1.1 etheisen 336: sc_e_keypad = "";
1.18 ! nicm 337:
! 338: sc_init = enter_ca_mode;
! 339: if (hardcopy || sc_init == NULL)
1.1 etheisen 340: sc_init = "";
1.11 millert 341:
1.18 ! nicm 342: sc_deinit = exit_ca_mode;
! 343: if (hardcopy || sc_deinit == NULL)
1.1 etheisen 344: sc_deinit = "";
345:
1.18 ! nicm 346: sc_eol_clear = clr_eol;
! 347: if (hardcopy || sc_eol_clear == NULL || *sc_eol_clear == '\0') {
1.11 millert 348: missing_cap = 1;
1.1 etheisen 349: sc_eol_clear = "";
350: }
351:
1.18 ! nicm 352: sc_eos_clear = clr_eos;
! 353: if (below_mem &&
! 354: (hardcopy || sc_eos_clear == NULL || *sc_eos_clear == '\0')) {
1.11 millert 355: missing_cap = 1;
1.15 shadchin 356: sc_eos_clear = "";
1.1 etheisen 357: }
358:
1.18 ! nicm 359: sc_clear = clear_screen;
! 360: if (hardcopy || sc_clear == NULL || *sc_clear == '\0') {
1.11 millert 361: missing_cap = 1;
1.1 etheisen 362: sc_clear = "\n\n";
363: }
364:
1.18 ! nicm 365: sc_move = cursor_address;
! 366: if (hardcopy || sc_move == NULL || *sc_move == '\0') {
1.1 etheisen 367: /*
1.18 ! nicm 368: * This is not an error here, because we don't
1.1 etheisen 369: * always need sc_move.
370: * We need it only if we don't have home or lower-left.
371: */
372: sc_move = "";
373: can_goto_line = 0;
1.18 ! nicm 374: } else {
1.1 etheisen 375: can_goto_line = 1;
1.18 ! nicm 376: }
1.1 etheisen 377:
1.18 ! nicm 378: tmodes(enter_standout_mode, exit_standout_mode, &sc_s_in, &sc_s_out,
! 379: "", "");
! 380: tmodes(enter_underline_mode, exit_underline_mode, &sc_u_in, &sc_u_out,
! 381: sc_s_in, sc_s_out);
! 382: tmodes(enter_bold_mode, exit_attribute_mode, &sc_b_in, &sc_b_out,
! 383: sc_s_in, sc_s_out);
! 384: tmodes(enter_blink_mode, exit_attribute_mode, &sc_bl_in, &sc_bl_out,
! 385: sc_s_in, sc_s_out);
1.1 etheisen 386:
1.18 ! nicm 387: sc_visual_bell = flash_screen;
! 388: if (hardcopy || sc_visual_bell == NULL)
1.1 etheisen 389: sc_visual_bell = "";
390:
1.18 ! nicm 391: sc_backspace = "\b";
1.1 etheisen 392:
393: /*
394: * Choose between using "ho" and "cm" ("home" and "cursor move")
395: * to move the cursor to the upper left corner of the screen.
396: */
1.18 ! nicm 397: t1 = cursor_home;
! 398: if (hardcopy || t1 == NULL)
1.1 etheisen 399: t1 = "";
1.18 ! nicm 400: if (*sc_move == '\0') {
1.1 etheisen 401: t2 = "";
1.18 ! nicm 402: } else {
! 403: t2 = estrdup(tparm(sc_move, 0, 0, 0, 0, 0, 0, 0, 0, 0));
1.1 etheisen 404: }
1.11 millert 405: sc_home = cheaper(t1, t2, "|\b^");
1.1 etheisen 406:
407: /*
408: * Choose between using "ll" and "cm" ("lower left" and "cursor move")
409: * to move the cursor to the lower left corner of the screen.
410: */
1.18 ! nicm 411: t1 = cursor_to_ll;
! 412: if (hardcopy || t1 == NULL)
1.1 etheisen 413: t1 = "";
1.18 ! nicm 414: if (*sc_move == '\0') {
1.1 etheisen 415: t2 = "";
1.18 ! nicm 416: } else {
! 417: t2 = estrdup(tparm(sc_move, sc_height-1,
! 418: 0, 0, 0, 0, 0, 0, 0, 0));
1.1 etheisen 419: }
1.11 millert 420: sc_lower_left = cheaper(t1, t2, "\r");
1.1 etheisen 421:
422: /*
1.15 shadchin 423: * Get carriage return string.
424: */
1.18 ! nicm 425: sc_return = carriage_return;
! 426: if (hardcopy || sc_return == NULL)
1.15 shadchin 427: sc_return = "\r";
428:
429: /*
1.18 ! nicm 430: * Choose between using insert_line or scroll_reverse
1.1 etheisen 431: * to add a line at the top of the screen.
432: */
1.18 ! nicm 433: t1 = insert_line;
! 434: if (hardcopy || t1 == NULL)
1.1 etheisen 435: t1 = "";
1.18 ! nicm 436: t2 = scroll_reverse;
! 437: if (hardcopy || t2 == NULL)
1.1 etheisen 438: t2 = "";
439: if (above_mem)
440: sc_addline = t1;
441: else
1.11 millert 442: sc_addline = cheaper(t1, t2, "");
1.18 ! nicm 443: if (*sc_addline == '\0') {
1.1 etheisen 444: /*
445: * Force repaint on any backward movement.
446: */
1.11 millert 447: no_back_scroll = 1;
1.1 etheisen 448: }
449: }
450:
451: /*
452: * Return the cost of displaying a termcap string.
453: * We use the trick of calling tputs, but as a char printing function
454: * we give it inc_costcount, which just increments "costcount".
455: * This tells us how many chars would be printed by using this string.
456: * {{ Couldn't we just use strlen? }}
457: */
458: static int costcount;
459:
1.18 ! nicm 460: static int
! 461: inc_costcount(int c)
1.1 etheisen 462: {
463: costcount++;
464: return (c);
465: }
466:
1.18 ! nicm 467: static int
! 468: cost(char *t)
1.1 etheisen 469: {
470: costcount = 0;
1.18 ! nicm 471: (void) tputs(t, sc_height, inc_costcount);
1.1 etheisen 472: return (costcount);
473: }
474:
475: /*
476: * Return the "best" of the two given termcap strings.
1.18 ! nicm 477: * The best, if both exist, is the one with the lower
1.1 etheisen 478: * cost (see cost() function).
479: */
1.18 ! nicm 480: static char *
! 481: cheaper(char *t1, char *t2, char *def)
1.1 etheisen 482: {
1.18 ! nicm 483: if (*t1 == '\0' && *t2 == '\0') {
1.11 millert 484: missing_cap = 1;
1.1 etheisen 485: return (def);
486: }
487: if (*t1 == '\0')
488: return (t2);
489: if (*t2 == '\0')
490: return (t1);
491: if (cost(t1) < cost(t2))
492: return (t1);
493: return (t2);
494: }
495:
1.18 ! nicm 496: static void
! 497: tmodes(char *incap, char *outcap, char **instr, char **outstr,
! 498: char *def_instr, char *def_outstr)
1.11 millert 499: {
1.18 ! nicm 500: if (hardcopy) {
! 501: *instr = "";
! 502: *outstr = "";
! 503: return;
! 504: }
! 505:
! 506: *instr = incap;
! 507: *outstr = outcap;
! 508:
! 509: if (*instr == NULL) {
1.11 millert 510: /* Use defaults. */
511: *instr = def_instr;
512: *outstr = def_outstr;
513: return;
514: }
515:
516: if (*outstr == NULL)
1.18 ! nicm 517: /* No specific out capability; use exit_attribute_mode. */
! 518: *outstr = exit_attribute_mode;
1.11 millert 519: if (*outstr == NULL)
1.18 ! nicm 520: /* Don't even have that, use an empty string */
1.11 millert 521: *outstr = "";
522: }
523:
1.1 etheisen 524: /*
1.18 ! nicm 525: * Below are the functions which perform all the
1.1 etheisen 526: * terminal-specific screen manipulation.
527: */
528:
529: /*
530: * Initialize terminal
531: */
1.18 ! nicm 532: void
! 533: init(void)
1.1 etheisen 534: {
1.11 millert 535: if (!no_init)
1.18 ! nicm 536: (void) tputs(sc_init, sc_height, putchr);
1.11 millert 537: if (!no_keypad)
1.18 ! nicm 538: (void) tputs(sc_s_keypad, sc_height, putchr);
! 539: if (top_scroll) {
1.15 shadchin 540: int i;
541:
542: /*
543: * This is nice to terminals with no alternate screen,
544: * but with saved scrolled-off-the-top lines. This way,
545: * no previous line is lost, but we start with a whole
546: * screen to ourself.
547: */
548: for (i = 1; i < sc_height; i++)
1.18 ! nicm 549: (void) putchr('\n');
1.15 shadchin 550: } else
551: line_left();
1.1 etheisen 552: init_done = 1;
553: }
554:
555: /*
556: * Deinitialize terminal
557: */
1.18 ! nicm 558: void
! 559: deinit(void)
1.1 etheisen 560: {
561: if (!init_done)
562: return;
1.11 millert 563: if (!no_keypad)
1.18 ! nicm 564: (void) tputs(sc_e_keypad, sc_height, putchr);
1.11 millert 565: if (!no_init)
1.18 ! nicm 566: (void) tputs(sc_deinit, sc_height, putchr);
1.1 etheisen 567: init_done = 0;
568: }
569:
570: /*
571: * Home cursor (move to upper left corner of screen).
572: */
1.18 ! nicm 573: void
! 574: home(void)
1.1 etheisen 575: {
1.18 ! nicm 576: (void) tputs(sc_home, 1, putchr);
1.1 etheisen 577: }
578:
579: /*
580: * Add a blank line (called with cursor at home).
581: * Should scroll the display down.
582: */
1.18 ! nicm 583: void
! 584: add_line(void)
1.11 millert 585: {
1.18 ! nicm 586: (void) tputs(sc_addline, sc_height, putchr);
1.11 millert 587: }
1.1 etheisen 588:
589: /*
590: * Move cursor to lower left corner of screen.
591: */
1.18 ! nicm 592: void
! 593: lower_left(void)
1.1 etheisen 594: {
1.18 ! nicm 595: (void) tputs(sc_lower_left, 1, putchr);
1.11 millert 596: }
597:
598: /*
1.15 shadchin 599: * Move cursor to left position of current line.
600: */
1.18 ! nicm 601: void
! 602: line_left(void)
1.15 shadchin 603: {
1.18 ! nicm 604: (void) tputs(sc_return, 1, putchr);
1.15 shadchin 605: }
606:
607: /*
1.18 ! nicm 608: * Goto a specific line on the screen.
1.11 millert 609: */
1.18 ! nicm 610: void
! 611: goto_line(int slinenum)
1.11 millert 612: {
1.18 ! nicm 613: (void) tputs(tparm(sc_move, slinenum, 0, 0, 0, 0, 0, 0, 0, 0), 1,
! 614: putchr);
1.1 etheisen 615: }
616:
617: /*
618: * Output the "visual bell", if there is one.
619: */
1.18 ! nicm 620: void
! 621: vbell(void)
1.1 etheisen 622: {
623: if (*sc_visual_bell == '\0')
624: return;
1.18 ! nicm 625: (void) tputs(sc_visual_bell, sc_height, putchr);
1.11 millert 626: }
627:
628: /*
629: * Make a noise.
630: */
1.18 ! nicm 631: static void
! 632: beep(void)
1.11 millert 633: {
1.18 ! nicm 634: (void) putchr(CONTROL('G'));
1.11 millert 635: }
636:
637: /*
638: * Ring the terminal bell.
639: */
1.18 ! nicm 640: void
! 641: ring_bell(void)
1.11 millert 642: {
643: if (quiet == VERY_QUIET)
644: vbell();
645: else
646: beep();
1.1 etheisen 647: }
648:
649: /*
650: * Clear the screen.
651: */
1.18 ! nicm 652: void
! 653: do_clear(void)
1.1 etheisen 654: {
1.18 ! nicm 655: (void) tputs(sc_clear, sc_height, putchr);
1.1 etheisen 656: }
657:
658: /*
659: * Clear from the cursor to the end of the cursor's line.
660: * {{ This must not move the cursor. }}
661: */
1.18 ! nicm 662: void
! 663: clear_eol(void)
1.1 etheisen 664: {
1.18 ! nicm 665: (void) tputs(sc_eol_clear, 1, putchr);
1.11 millert 666: }
667:
668: /*
669: * Clear the current line.
670: * Clear the screen if there's off-screen memory below the display.
671: */
1.18 ! nicm 672: static void
! 673: clear_eol_bot(void)
1.11 millert 674: {
675: if (below_mem)
1.18 ! nicm 676: (void) tputs(sc_eos_clear, 1, putchr);
1.11 millert 677: else
1.18 ! nicm 678: (void) tputs(sc_eol_clear, 1, putchr);
1.1 etheisen 679: }
680:
681: /*
682: * Clear the bottom line of the display.
683: * Leave the cursor at the beginning of the bottom line.
684: */
1.18 ! nicm 685: void
! 686: clear_bot(void)
1.1 etheisen 687: {
1.11 millert 688: /*
689: * If we're in a non-normal attribute mode, temporarily exit
690: * the mode while we do the clear. Some terminals fill the
691: * cleared area with the current attribute.
692: */
1.15 shadchin 693: if (oldbot)
694: lower_left();
695: else
696: line_left();
697:
698: if (attrmode == AT_NORMAL)
699: clear_eol_bot();
700: else
1.11 millert 701: {
1.15 shadchin 702: int saved_attrmode = attrmode;
703:
704: at_exit();
1.11 millert 705: clear_eol_bot();
1.15 shadchin 706: at_enter(saved_attrmode);
1.11 millert 707: }
1.1 etheisen 708: }
709:
1.18 ! nicm 710: void
! 711: at_enter(int attr)
1.1 etheisen 712: {
1.15 shadchin 713: attr = apply_at_specials(attr);
714:
715: /* The one with the most priority is last. */
716: if (attr & AT_UNDERLINE)
1.18 ! nicm 717: (void) tputs(sc_u_in, 1, putchr);
1.15 shadchin 718: if (attr & AT_BOLD)
1.18 ! nicm 719: (void) tputs(sc_b_in, 1, putchr);
1.15 shadchin 720: if (attr & AT_BLINK)
1.18 ! nicm 721: (void) tputs(sc_bl_in, 1, putchr);
1.15 shadchin 722: if (attr & AT_STANDOUT)
1.18 ! nicm 723: (void) tputs(sc_s_in, 1, putchr);
1.15 shadchin 724:
725: attrmode = attr;
1.1 etheisen 726: }
727:
1.18 ! nicm 728: void
! 729: at_exit(void)
1.1 etheisen 730: {
1.15 shadchin 731: /* Undo things in the reverse order we did them. */
732: if (attrmode & AT_STANDOUT)
1.18 ! nicm 733: (void) tputs(sc_s_out, 1, putchr);
1.15 shadchin 734: if (attrmode & AT_BLINK)
1.18 ! nicm 735: (void) tputs(sc_bl_out, 1, putchr);
1.15 shadchin 736: if (attrmode & AT_BOLD)
1.18 ! nicm 737: (void) tputs(sc_b_out, 1, putchr);
1.15 shadchin 738: if (attrmode & AT_UNDERLINE)
1.18 ! nicm 739: (void) tputs(sc_u_out, 1, putchr);
1.15 shadchin 740:
1.11 millert 741: attrmode = AT_NORMAL;
1.1 etheisen 742: }
743:
1.18 ! nicm 744: void
! 745: at_switch(int attr)
1.1 etheisen 746: {
1.15 shadchin 747: int new_attrmode = apply_at_specials(attr);
748: int ignore_modes = AT_ANSI;
1.1 etheisen 749:
1.18 ! nicm 750: if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) {
1.15 shadchin 751: at_exit();
752: at_enter(attr);
753: }
1.1 etheisen 754: }
755:
1.18 ! nicm 756: int
! 757: is_at_equiv(int attr1, int attr2)
1.1 etheisen 758: {
1.15 shadchin 759: attr1 = apply_at_specials(attr1);
760: attr2 = apply_at_specials(attr2);
1.1 etheisen 761:
1.15 shadchin 762: return (attr1 == attr2);
1.1 etheisen 763: }
764:
1.18 ! nicm 765: int
! 766: apply_at_specials(int attr)
1.1 etheisen 767: {
1.15 shadchin 768: if (attr & AT_BINARY)
769: attr |= binattr;
770: if (attr & AT_HILITE)
771: attr |= AT_STANDOUT;
772: attr &= ~(AT_BINARY|AT_HILITE);
1.1 etheisen 773:
1.18 ! nicm 774: return (attr);
1.1 etheisen 775: }
776:
777: /*
778: * Output a plain backspace, without erasing the previous char.
779: */
1.18 ! nicm 780: void
! 781: putbs(void)
1.15 shadchin 782: {
1.18 ! nicm 783: (void) tputs(sc_backspace, 1, putchr);
1.11 millert 784: }