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