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