[BACK]Return to screen.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

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: }