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