Annotation of src/usr.bin/less/screen.c, Revision 1.19
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);
160: (void) fsync(tty);
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.18 nicm 175: char *s;
1.11 millert 176: int sys_height;
177: int sys_width;
178: int n;
1.18 nicm 179: #ifdef TIOCGWINSIZE
180: struct winsize w;
1.11 millert 181: #endif
1.1 etheisen 182:
1.11 millert 183: #define DEF_SC_WIDTH 80
184: #define DEF_SC_HEIGHT 24
1.1 etheisen 185:
1.11 millert 186: sys_width = sys_height = 0;
1.1 etheisen 187:
1.18 nicm 188: #ifdef TIOCGWINSIZE
189: if (ioctl(2, TIOCGWINSZ, &w) == 0) {
190: if (w.ws_row > 0)
191: sys_height = w.ws_row;
192: if (w.ws_col > 0)
193: sys_width = w.ws_col;
1.1 etheisen 194: }
1.11 millert 195: #endif
1.1 etheisen 196:
1.11 millert 197: if (sys_height > 0)
198: sc_height = sys_height;
199: else if ((s = lgetenv("LINES")) != NULL)
200: sc_height = atoi(s);
1.18 nicm 201: else if (!hardcopy && (n = lines) > 0)
202: sc_height = n;
1.17 shadchin 203: if (sc_height <= 0)
1.11 millert 204: sc_height = DEF_SC_HEIGHT;
1.1 etheisen 205:
1.11 millert 206: if (sys_width > 0)
207: sc_width = sys_width;
208: else if ((s = lgetenv("COLUMNS")) != NULL)
209: sc_width = atoi(s);
1.18 nicm 210: else if (!hardcopy && (n = columns) > 0)
211: sc_width = n;
1.17 shadchin 212: if (sc_width <= 0)
1.11 millert 213: sc_width = DEF_SC_WIDTH;
214: }
1.1 etheisen 215:
216: /*
1.11 millert 217: * Return the characters actually input by a "special" key.
1.1 etheisen 218: */
1.18 nicm 219: char *
220: special_key_str(int key)
1.1 etheisen 221: {
1.11 millert 222: char *s;
1.18 nicm 223: static char ctrlk[] = { CONTROL('K'), 0 };
224:
225: if (hardcopy)
226: return (NULL);
1.1 etheisen 227:
1.18 nicm 228: switch (key) {
1.11 millert 229: case SK_RIGHT_ARROW:
1.18 nicm 230: s = key_right;
1.11 millert 231: break;
232: case SK_LEFT_ARROW:
1.18 nicm 233: s = key_left;
1.11 millert 234: break;
235: case SK_UP_ARROW:
1.18 nicm 236: s = key_up;
1.11 millert 237: break;
238: case SK_DOWN_ARROW:
1.18 nicm 239: s = key_down;
1.11 millert 240: break;
241: case SK_PAGE_UP:
1.18 nicm 242: s = key_ppage;
1.11 millert 243: break;
244: case SK_PAGE_DOWN:
1.18 nicm 245: s = key_npage;
1.11 millert 246: break;
247: case SK_HOME:
1.18 nicm 248: s = key_home;
1.11 millert 249: break;
250: case SK_END:
1.18 nicm 251: s = key_end;
1.11 millert 252: break;
253: case SK_DELETE:
1.18 nicm 254: s = key_dc;
255: if (s == NULL) {
256: s = "\177\0";
1.11 millert 257: }
258: break;
259: case SK_CONTROL_K:
1.18 nicm 260: s = ctrlk;
1.11 millert 261: break;
262: default:
263: return (NULL);
264: }
265: return (s);
266: }
267:
268: /*
269: * Get terminal capabilities via termcap.
270: */
1.18 nicm 271: void
272: get_term(void)
1.11 millert 273: {
1.18 nicm 274: char *t1, *t2;
1.11 millert 275: char *term;
276:
1.1 etheisen 277: /*
278: * Find out what kind of terminal this is.
279: */
1.18 nicm 280: if ((term = lgetenv("TERM")) == NULL)
281: term = DEFAULT_TERM;
1.11 millert 282: hardcopy = 0;
1.18 nicm 283:
284: if (setupterm(term, 1, NULL) < 0) {
285: hardcopy = 1;
286: }
287: if (hard_copy == 1)
1.11 millert 288: hardcopy = 1;
1.1 etheisen 289:
290: /*
291: * Get size of the screen.
292: */
293: scrsize();
294: pos_init();
295:
1.18 nicm 296: auto_wrap = hardcopy ? 0 : auto_right_margin;
297: ignaw = hardcopy ? 0 : eat_newline_glitch;
298: above_mem = hardcopy ? 0 : memory_above;
299: below_mem = hardcopy ? 0 : memory_below;
1.1 etheisen 300:
301: /*
302: * Assumes termcap variable "sg" is the printing width of:
303: * the standout sequence, the end standout sequence,
304: * the underline sequence, the end underline sequence,
305: * the boldface sequence, and the end boldface sequence.
306: */
1.18 nicm 307: if (hardcopy || (so_s_width = magic_cookie_glitch) < 0)
1.1 etheisen 308: so_s_width = 0;
309: so_e_width = so_s_width;
310:
311: bo_s_width = bo_e_width = so_s_width;
312: ul_s_width = ul_e_width = so_s_width;
313: bl_s_width = bl_e_width = so_s_width;
314:
315: if (so_s_width > 0 || so_e_width > 0)
316: /*
317: * Disable highlighting by default on magic cookie terminals.
318: * Turning on highlighting might change the displayed width
319: * of a line, causing the display to get messed up.
1.18 nicm 320: * The user can turn it back on with -g,
1.1 etheisen 321: * but she won't like the results.
322: */
323: hilite_search = 0;
324:
325: /*
326: * Get various string-valued capabilities.
327: */
328:
1.18 nicm 329: sc_s_keypad = keypad_xmit;
330: if (hardcopy || sc_s_keypad == NULL)
1.1 etheisen 331: sc_s_keypad = "";
1.18 nicm 332: sc_e_keypad = keypad_local;
333: if (hardcopy || sc_e_keypad == NULL)
1.1 etheisen 334: sc_e_keypad = "";
1.18 nicm 335:
336: sc_init = enter_ca_mode;
337: if (hardcopy || sc_init == NULL)
1.1 etheisen 338: sc_init = "";
1.11 millert 339:
1.18 nicm 340: sc_deinit = exit_ca_mode;
341: if (hardcopy || sc_deinit == NULL)
1.1 etheisen 342: sc_deinit = "";
343:
1.18 nicm 344: sc_eol_clear = clr_eol;
345: if (hardcopy || sc_eol_clear == NULL || *sc_eol_clear == '\0') {
1.11 millert 346: missing_cap = 1;
1.1 etheisen 347: sc_eol_clear = "";
348: }
349:
1.18 nicm 350: sc_eos_clear = clr_eos;
351: if (below_mem &&
352: (hardcopy || sc_eos_clear == NULL || *sc_eos_clear == '\0')) {
1.11 millert 353: missing_cap = 1;
1.15 shadchin 354: sc_eos_clear = "";
1.1 etheisen 355: }
356:
1.18 nicm 357: sc_clear = clear_screen;
358: if (hardcopy || sc_clear == NULL || *sc_clear == '\0') {
1.11 millert 359: missing_cap = 1;
1.1 etheisen 360: sc_clear = "\n\n";
361: }
362:
1.18 nicm 363: sc_move = cursor_address;
364: if (hardcopy || sc_move == NULL || *sc_move == '\0') {
1.1 etheisen 365: /*
1.18 nicm 366: * This is not an error here, because we don't
1.1 etheisen 367: * always need sc_move.
368: * We need it only if we don't have home or lower-left.
369: */
370: sc_move = "";
371: can_goto_line = 0;
1.18 nicm 372: } else {
1.1 etheisen 373: can_goto_line = 1;
1.18 nicm 374: }
1.1 etheisen 375:
1.18 nicm 376: tmodes(enter_standout_mode, exit_standout_mode, &sc_s_in, &sc_s_out,
377: "", "");
378: tmodes(enter_underline_mode, exit_underline_mode, &sc_u_in, &sc_u_out,
379: sc_s_in, sc_s_out);
380: tmodes(enter_bold_mode, exit_attribute_mode, &sc_b_in, &sc_b_out,
381: sc_s_in, sc_s_out);
382: tmodes(enter_blink_mode, exit_attribute_mode, &sc_bl_in, &sc_bl_out,
383: sc_s_in, sc_s_out);
1.1 etheisen 384:
1.18 nicm 385: sc_visual_bell = flash_screen;
386: if (hardcopy || sc_visual_bell == NULL)
1.1 etheisen 387: sc_visual_bell = "";
388:
1.18 nicm 389: sc_backspace = "\b";
1.1 etheisen 390:
391: /*
392: * Choose between using "ho" and "cm" ("home" and "cursor move")
393: * to move the cursor to the upper left corner of the screen.
394: */
1.18 nicm 395: t1 = cursor_home;
396: if (hardcopy || t1 == NULL)
1.1 etheisen 397: t1 = "";
1.18 nicm 398: if (*sc_move == '\0') {
1.1 etheisen 399: t2 = "";
1.18 nicm 400: } else {
401: t2 = estrdup(tparm(sc_move, 0, 0, 0, 0, 0, 0, 0, 0, 0));
1.1 etheisen 402: }
1.11 millert 403: sc_home = cheaper(t1, t2, "|\b^");
1.1 etheisen 404:
405: /*
406: * Choose between using "ll" and "cm" ("lower left" and "cursor move")
407: * to move the cursor to the lower left corner of the screen.
408: */
1.18 nicm 409: t1 = cursor_to_ll;
410: if (hardcopy || t1 == NULL)
1.1 etheisen 411: t1 = "";
1.18 nicm 412: if (*sc_move == '\0') {
1.1 etheisen 413: t2 = "";
1.18 nicm 414: } else {
415: t2 = estrdup(tparm(sc_move, sc_height-1,
416: 0, 0, 0, 0, 0, 0, 0, 0));
1.1 etheisen 417: }
1.11 millert 418: sc_lower_left = cheaper(t1, t2, "\r");
1.1 etheisen 419:
420: /*
1.15 shadchin 421: * Get carriage return string.
422: */
1.18 nicm 423: sc_return = carriage_return;
424: if (hardcopy || sc_return == NULL)
1.15 shadchin 425: sc_return = "\r";
426:
427: /*
1.18 nicm 428: * Choose between using insert_line or scroll_reverse
1.1 etheisen 429: * to add a line at the top of the screen.
430: */
1.18 nicm 431: t1 = insert_line;
432: if (hardcopy || t1 == NULL)
1.1 etheisen 433: t1 = "";
1.18 nicm 434: t2 = scroll_reverse;
435: if (hardcopy || t2 == NULL)
1.1 etheisen 436: t2 = "";
437: if (above_mem)
438: sc_addline = t1;
439: else
1.11 millert 440: sc_addline = cheaper(t1, t2, "");
1.18 nicm 441: if (*sc_addline == '\0') {
1.1 etheisen 442: /*
443: * Force repaint on any backward movement.
444: */
1.11 millert 445: no_back_scroll = 1;
1.1 etheisen 446: }
447: }
448:
449: /*
450: * Return the cost of displaying a termcap string.
451: * We use the trick of calling tputs, but as a char printing function
452: * we give it inc_costcount, which just increments "costcount".
453: * This tells us how many chars would be printed by using this string.
454: * {{ Couldn't we just use strlen? }}
455: */
456: static int costcount;
457:
1.18 nicm 458: static int
459: inc_costcount(int c)
1.1 etheisen 460: {
461: costcount++;
462: return (c);
463: }
464:
1.18 nicm 465: static int
466: cost(char *t)
1.1 etheisen 467: {
468: costcount = 0;
1.18 nicm 469: (void) tputs(t, sc_height, inc_costcount);
1.1 etheisen 470: return (costcount);
471: }
472:
473: /*
474: * Return the "best" of the two given termcap strings.
1.18 nicm 475: * The best, if both exist, is the one with the lower
1.1 etheisen 476: * cost (see cost() function).
477: */
1.18 nicm 478: static char *
479: cheaper(char *t1, char *t2, char *def)
1.1 etheisen 480: {
1.18 nicm 481: if (*t1 == '\0' && *t2 == '\0') {
1.11 millert 482: missing_cap = 1;
1.1 etheisen 483: return (def);
484: }
485: if (*t1 == '\0')
486: return (t2);
487: if (*t2 == '\0')
488: return (t1);
489: if (cost(t1) < cost(t2))
490: return (t1);
491: return (t2);
492: }
493:
1.18 nicm 494: static void
495: tmodes(char *incap, char *outcap, char **instr, char **outstr,
496: char *def_instr, char *def_outstr)
1.11 millert 497: {
1.18 nicm 498: if (hardcopy) {
499: *instr = "";
500: *outstr = "";
501: return;
502: }
503:
504: *instr = incap;
505: *outstr = outcap;
506:
507: if (*instr == NULL) {
1.11 millert 508: /* Use defaults. */
509: *instr = def_instr;
510: *outstr = def_outstr;
511: return;
512: }
513:
514: if (*outstr == NULL)
1.18 nicm 515: /* No specific out capability; use exit_attribute_mode. */
516: *outstr = exit_attribute_mode;
1.11 millert 517: if (*outstr == NULL)
1.18 nicm 518: /* Don't even have that, use an empty string */
1.11 millert 519: *outstr = "";
520: }
521:
1.1 etheisen 522: /*
1.18 nicm 523: * Below are the functions which perform all the
1.1 etheisen 524: * terminal-specific screen manipulation.
525: */
526:
527: /*
528: * Initialize terminal
529: */
1.18 nicm 530: void
531: init(void)
1.1 etheisen 532: {
1.11 millert 533: if (!no_init)
1.18 nicm 534: (void) tputs(sc_init, sc_height, putchr);
1.11 millert 535: if (!no_keypad)
1.18 nicm 536: (void) tputs(sc_s_keypad, sc_height, putchr);
537: if (top_scroll) {
1.15 shadchin 538: int i;
539:
540: /*
541: * This is nice to terminals with no alternate screen,
542: * but with saved scrolled-off-the-top lines. This way,
543: * no previous line is lost, but we start with a whole
544: * screen to ourself.
545: */
546: for (i = 1; i < sc_height; i++)
1.18 nicm 547: (void) putchr('\n');
1.15 shadchin 548: } else
549: line_left();
1.1 etheisen 550: init_done = 1;
551: }
552:
553: /*
554: * Deinitialize terminal
555: */
1.18 nicm 556: void
557: deinit(void)
1.1 etheisen 558: {
559: if (!init_done)
560: return;
1.11 millert 561: if (!no_keypad)
1.18 nicm 562: (void) tputs(sc_e_keypad, sc_height, putchr);
1.11 millert 563: if (!no_init)
1.18 nicm 564: (void) tputs(sc_deinit, sc_height, putchr);
1.1 etheisen 565: init_done = 0;
566: }
567:
568: /*
569: * Home cursor (move to upper left corner of screen).
570: */
1.18 nicm 571: void
572: home(void)
1.1 etheisen 573: {
1.18 nicm 574: (void) tputs(sc_home, 1, putchr);
1.1 etheisen 575: }
576:
577: /*
578: * Add a blank line (called with cursor at home).
579: * Should scroll the display down.
580: */
1.18 nicm 581: void
582: add_line(void)
1.11 millert 583: {
1.18 nicm 584: (void) tputs(sc_addline, sc_height, putchr);
1.11 millert 585: }
1.1 etheisen 586:
587: /*
588: * Move cursor to lower left corner of screen.
589: */
1.18 nicm 590: void
591: lower_left(void)
1.1 etheisen 592: {
1.18 nicm 593: (void) tputs(sc_lower_left, 1, putchr);
1.11 millert 594: }
595:
596: /*
1.15 shadchin 597: * Move cursor to left position of current line.
598: */
1.18 nicm 599: void
600: line_left(void)
1.15 shadchin 601: {
1.18 nicm 602: (void) tputs(sc_return, 1, putchr);
1.15 shadchin 603: }
604:
605: /*
1.18 nicm 606: * Goto a specific line on the screen.
1.11 millert 607: */
1.18 nicm 608: void
609: goto_line(int slinenum)
1.11 millert 610: {
1.18 nicm 611: (void) tputs(tparm(sc_move, slinenum, 0, 0, 0, 0, 0, 0, 0, 0), 1,
612: putchr);
1.1 etheisen 613: }
614:
615: /*
616: * Output the "visual bell", if there is one.
617: */
1.18 nicm 618: void
619: vbell(void)
1.1 etheisen 620: {
621: if (*sc_visual_bell == '\0')
622: return;
1.18 nicm 623: (void) tputs(sc_visual_bell, sc_height, putchr);
1.11 millert 624: }
625:
626: /*
627: * Make a noise.
628: */
1.18 nicm 629: static void
630: beep(void)
1.11 millert 631: {
1.18 nicm 632: (void) putchr(CONTROL('G'));
1.11 millert 633: }
634:
635: /*
636: * Ring the terminal bell.
637: */
1.18 nicm 638: void
639: ring_bell(void)
1.11 millert 640: {
641: if (quiet == VERY_QUIET)
642: vbell();
643: else
644: beep();
1.1 etheisen 645: }
646:
647: /*
648: * Clear the screen.
649: */
1.18 nicm 650: void
651: do_clear(void)
1.1 etheisen 652: {
1.18 nicm 653: (void) tputs(sc_clear, sc_height, putchr);
1.1 etheisen 654: }
655:
656: /*
657: * Clear from the cursor to the end of the cursor's line.
658: * {{ This must not move the cursor. }}
659: */
1.18 nicm 660: void
661: clear_eol(void)
1.1 etheisen 662: {
1.18 nicm 663: (void) tputs(sc_eol_clear, 1, putchr);
1.11 millert 664: }
665:
666: /*
667: * Clear the current line.
668: * Clear the screen if there's off-screen memory below the display.
669: */
1.18 nicm 670: static void
671: clear_eol_bot(void)
1.11 millert 672: {
673: if (below_mem)
1.18 nicm 674: (void) tputs(sc_eos_clear, 1, putchr);
1.11 millert 675: else
1.18 nicm 676: (void) tputs(sc_eol_clear, 1, putchr);
1.1 etheisen 677: }
678:
679: /*
680: * Clear the bottom line of the display.
681: * Leave the cursor at the beginning of the bottom line.
682: */
1.18 nicm 683: void
684: clear_bot(void)
1.1 etheisen 685: {
1.11 millert 686: /*
687: * If we're in a non-normal attribute mode, temporarily exit
688: * the mode while we do the clear. Some terminals fill the
689: * cleared area with the current attribute.
690: */
1.15 shadchin 691: if (oldbot)
692: lower_left();
693: else
694: line_left();
695:
696: if (attrmode == AT_NORMAL)
697: clear_eol_bot();
698: else
1.11 millert 699: {
1.15 shadchin 700: int saved_attrmode = attrmode;
701:
702: at_exit();
1.11 millert 703: clear_eol_bot();
1.15 shadchin 704: at_enter(saved_attrmode);
1.11 millert 705: }
1.1 etheisen 706: }
707:
1.18 nicm 708: void
709: at_enter(int attr)
1.1 etheisen 710: {
1.15 shadchin 711: attr = apply_at_specials(attr);
712:
713: /* The one with the most priority is last. */
714: if (attr & AT_UNDERLINE)
1.18 nicm 715: (void) tputs(sc_u_in, 1, putchr);
1.15 shadchin 716: if (attr & AT_BOLD)
1.18 nicm 717: (void) tputs(sc_b_in, 1, putchr);
1.15 shadchin 718: if (attr & AT_BLINK)
1.18 nicm 719: (void) tputs(sc_bl_in, 1, putchr);
1.15 shadchin 720: if (attr & AT_STANDOUT)
1.18 nicm 721: (void) tputs(sc_s_in, 1, putchr);
1.15 shadchin 722:
723: attrmode = attr;
1.1 etheisen 724: }
725:
1.18 nicm 726: void
727: at_exit(void)
1.1 etheisen 728: {
1.15 shadchin 729: /* Undo things in the reverse order we did them. */
730: if (attrmode & AT_STANDOUT)
1.18 nicm 731: (void) tputs(sc_s_out, 1, putchr);
1.15 shadchin 732: if (attrmode & AT_BLINK)
1.18 nicm 733: (void) tputs(sc_bl_out, 1, putchr);
1.15 shadchin 734: if (attrmode & AT_BOLD)
1.18 nicm 735: (void) tputs(sc_b_out, 1, putchr);
1.15 shadchin 736: if (attrmode & AT_UNDERLINE)
1.18 nicm 737: (void) tputs(sc_u_out, 1, putchr);
1.15 shadchin 738:
1.11 millert 739: attrmode = AT_NORMAL;
1.1 etheisen 740: }
741:
1.18 nicm 742: void
743: at_switch(int attr)
1.1 etheisen 744: {
1.15 shadchin 745: int new_attrmode = apply_at_specials(attr);
746: int ignore_modes = AT_ANSI;
1.1 etheisen 747:
1.18 nicm 748: if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) {
1.15 shadchin 749: at_exit();
750: at_enter(attr);
751: }
1.1 etheisen 752: }
753:
1.18 nicm 754: int
755: is_at_equiv(int attr1, int attr2)
1.1 etheisen 756: {
1.15 shadchin 757: attr1 = apply_at_specials(attr1);
758: attr2 = apply_at_specials(attr2);
1.1 etheisen 759:
1.15 shadchin 760: return (attr1 == attr2);
1.1 etheisen 761: }
762:
1.18 nicm 763: int
764: apply_at_specials(int attr)
1.1 etheisen 765: {
1.15 shadchin 766: if (attr & AT_BINARY)
767: attr |= binattr;
768: if (attr & AT_HILITE)
769: attr |= AT_STANDOUT;
770: attr &= ~(AT_BINARY|AT_HILITE);
1.1 etheisen 771:
1.18 nicm 772: return (attr);
1.1 etheisen 773: }
774:
775: /*
776: * Output a plain backspace, without erasing the previous char.
777: */
1.18 nicm 778: void
779: putbs(void)
1.15 shadchin 780: {
1.18 nicm 781: (void) tputs(sc_backspace, 1, putchr);
1.11 millert 782: }