[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.10

1.10    ! deraadt     1: /*     $OpenBSD: screen.c,v 1.9 2003/04/05 01:03:35 deraadt Exp $      */
1.7       niklas      2:
1.1       etheisen    3: /*
                      4:  * Copyright (c) 1984,1985,1989,1994,1995  Mark Nudelman
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice in the documentation and/or other materials provided with
                     14:  *    the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
                     17:  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     19:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
                     20:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     21:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
                     22:  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
                     23:  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     24:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
                     25:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
                     26:  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     27:  */
                     28:
                     29:
                     30: /*
                     31:  * Routines which deal with the characteristics of the terminal.
                     32:  * Uses termcap to be as terminal-independent as possible.
                     33:  *
                     34:  * {{ Maybe someday this should be rewritten to use curses or terminfo. }}
                     35:  */
                     36:
                     37: #include "less.h"
                     38: #include "cmd.h"
                     39:
                     40: #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
                     41: #include <termios.h>
                     42: #if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)
                     43: #include <sys/ioctl.h>
                     44: #endif
                     45: #else
                     46: #if HAVE_TERMIO_H
                     47: #include <termio.h>
                     48: #else
                     49: #include <sgtty.h>
                     50: #if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD))
                     51: #include <sys/ioctl.h>
                     52: #endif
                     53: #endif
                     54: #endif
                     55: #if HAVE_TERMCAP_H
                     56: #include <termcap.h>
                     57: #endif
                     58:
                     59: #ifndef TIOCGWINSZ
                     60: /*
                     61:  * For the Unix PC (ATT 7300 & 3B1):
                     62:  * Since WIOCGETD is defined in sys/window.h, we can't use that to decide
                     63:  * whether to include sys/window.h.  Use SIGPHONE from sys/signal.h instead.
                     64:  */
                     65: #include <sys/signal.h>
                     66: #ifdef SIGPHONE
                     67: #include <sys/window.h>
                     68: #endif
                     69: #endif
                     70:
                     71: #if HAVE_SYS_STREAM_H
                     72: #include <sys/stream.h>
                     73: #endif
                     74: #if HAVE_SYS_PTEM_H
                     75: #include <sys/ptem.h>
                     76: #endif
                     77:
                     78: #if OS2
                     79: #define        DEFAULT_TERM            "ansi"
                     80: #else
                     81: #define        DEFAULT_TERM            "unknown"
                     82: #endif
                     83:
                     84: /*
                     85:  * Strings passed to tputs() to do various terminal functions.
                     86:  */
                     87: static char
                     88:        *sc_pad,                /* Pad string */
                     89:        *sc_home,               /* Cursor home */
                     90:        *sc_addline,            /* Add line, scroll down following lines */
                     91:        *sc_lower_left,         /* Cursor to last line, first column */
                     92:        *sc_move,               /* General cursor positioning */
                     93:        *sc_clear,              /* Clear screen */
                     94:        *sc_eol_clear,          /* Clear to end of line */
                     95:        *sc_eos_clear,          /* Clear to end of screen */
                     96:        *sc_s_in,               /* Enter standout (highlighted) mode */
                     97:        *sc_s_out,              /* Exit standout mode */
                     98:        *sc_u_in,               /* Enter underline mode */
                     99:        *sc_u_out,              /* Exit underline mode */
                    100:        *sc_b_in,               /* Enter bold mode */
                    101:        *sc_b_out,              /* Exit bold mode */
                    102:        *sc_bl_in,              /* Enter blink mode */
                    103:        *sc_bl_out,             /* Exit blink mode */
                    104:        *sc_visual_bell,        /* Visual bell (flash screen) sequence */
                    105:        *sc_backspace,          /* Backspace cursor */
                    106:        *sc_s_keypad,           /* Start keypad mode */
                    107:        *sc_e_keypad,           /* End keypad mode */
                    108:        *sc_init,               /* Startup terminal initialization */
                    109:        *sc_deinit;             /* Exit terminal de-initialization */
                    110:
                    111: static int init_done = 0;
1.5       millert   112: static int tty_fd = -1;
1.1       etheisen  113:
                    114: public int auto_wrap;          /* Terminal does \r\n when write past margin */
                    115: public int ignaw;              /* Terminal ignores \n immediately after wrap */
                    116: public int erase_char, kill_char; /* The user's erase and line-kill chars */
                    117: public int werase_char;                /* The user's word-erase char */
                    118: public int sc_width, sc_height;        /* Height & width of screen */
                    119: public int bo_s_width, bo_e_width;     /* Printing width of boldface seq */
                    120: public int ul_s_width, ul_e_width;     /* Printing width of underline seq */
                    121: public int so_s_width, so_e_width;     /* Printing width of standout seq */
                    122: public int bl_s_width, bl_e_width;     /* Printing width of blink seq */
                    123: public int above_mem, below_mem;       /* Memory retained above/below screen */
                    124: public int can_goto_line;              /* Can move cursor to any line */
                    125:
                    126: static char *cheaper();
                    127:
                    128: /*
                    129:  * These two variables are sometimes defined in,
                    130:  * and needed by, the termcap library.
                    131:  */
                    132: #if MUST_DEFINE_OSPEED
                    133: extern short ospeed;   /* Terminal output baud rate */
                    134: extern char PC;                /* Pad character */
                    135: #endif
                    136:
                    137: extern int quiet;              /* If VERY_QUIET, use visual bell for bell */
                    138: extern int know_dumb;          /* Don't complain about a dumb terminal */
                    139: extern int back_scroll;
                    140: extern int swindow;
                    141: extern int no_init;
1.2       etheisen  142: extern int quit_at_eof;
                    143: extern int more_mode;
1.1       etheisen  144: #if HILITE_SEARCH
                    145: extern int hilite_search;
                    146: #endif
                    147:
                    148: extern char *tgetstr();
                    149: extern char *tgoto();
                    150:
                    151:
                    152: /*
                    153:  * Change terminal to "raw mode", or restore to "normal" mode.
                    154:  * "Raw mode" means
                    155:  *     1. An outstanding read will complete on receipt of a single keystroke.
                    156:  *     2. Input is not echoed.
                    157:  *     3. On output, \n is mapped to \r\n.
                    158:  *     4. \t is NOT expanded into spaces.
                    159:  *     5. Signal-causing characters such as ctrl-C (interrupt),
                    160:  *        etc. are NOT disabled.
                    161:  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
                    162:  */
                    163:        public void
                    164: raw_mode(on)
                    165:        int on;
                    166: {
                    167:        static int curr_on = 0;
                    168:
                    169:        if (on == curr_on)
                    170:                return;
1.5       millert   171:
                    172:        if (tty_fd == -1 && (tty_fd = open("/dev/tty", O_RDWR)) < 0)
                    173:                tty_fd = 2;
                    174:
1.1       etheisen  175: #if OS2
                    176:        signal(SIGINT, SIG_IGN);
                    177:        erase_char = '\b';
                    178:        kill_char = '\033';
                    179: #else
                    180: #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
                    181:     {
                    182:        struct termios s;
                    183:        static struct termios save_term;
                    184:
                    185:        if (on)
                    186:        {
                    187:                /*
                    188:                 * Get terminal modes.
                    189:                 */
1.5       millert   190:                if (tcgetattr(tty_fd, &s) == -1)
                    191:                        return;
1.1       etheisen  192:
                    193:                /*
                    194:                 * Save modes and set certain variables dependent on modes.
                    195:                 */
                    196:                save_term = s;
                    197: #if HAVE_OSPEED
                    198:                switch (cfgetospeed(&s))
                    199:                {
                    200: #ifdef B0
                    201:                case B0: ospeed = 0; break;
                    202: #endif
                    203: #ifdef B50
                    204:                case B50: ospeed = 1; break;
                    205: #endif
                    206: #ifdef B75
                    207:                case B75: ospeed = 2; break;
                    208: #endif
                    209: #ifdef B110
                    210:                case B110: ospeed = 3; break;
                    211: #endif
                    212: #ifdef B134
                    213:                case B134: ospeed = 4; break;
                    214: #endif
                    215: #ifdef B150
                    216:                case B150: ospeed = 5; break;
                    217: #endif
                    218: #ifdef B200
                    219:                case B200: ospeed = 6; break;
                    220: #endif
                    221: #ifdef B300
                    222:                case B300: ospeed = 7; break;
                    223: #endif
                    224: #ifdef B600
                    225:                case B600: ospeed = 8; break;
                    226: #endif
                    227: #ifdef B1200
                    228:                case B1200: ospeed = 9; break;
                    229: #endif
                    230: #ifdef B1800
                    231:                case B1800: ospeed = 10; break;
                    232: #endif
                    233: #ifdef B2400
                    234:                case B2400: ospeed = 11; break;
                    235: #endif
                    236: #ifdef B4800
                    237:                case B4800: ospeed = 12; break;
                    238: #endif
                    239: #ifdef B9600
                    240:                case B9600: ospeed = 13; break;
                    241: #endif
                    242: #ifdef EXTA
                    243:                case EXTA: ospeed = 14; break;
                    244: #endif
                    245: #ifdef EXTB
                    246:                case EXTB: ospeed = 15; break;
                    247: #endif
                    248: #ifdef B57600
                    249:                case B57600: ospeed = 16; break;
                    250: #endif
                    251: #ifdef B115200
                    252:                case B115200: ospeed = 17; break;
                    253: #endif
                    254:                default: ;
                    255:                }
                    256: #endif
                    257:                erase_char = s.c_cc[VERASE];
                    258:                kill_char = s.c_cc[VKILL];
                    259: #ifdef VWERASE
                    260:                werase_char = s.c_cc[VWERASE];
                    261: #else
                    262:                werase_char = 0;
                    263: #endif
                    264:
                    265:                /*
                    266:                 * Set the modes to the way we want them.
                    267:                 */
                    268:                s.c_lflag &= ~(0
                    269: #ifdef ICANON
                    270:                        | ICANON
                    271: #endif
                    272: #ifdef ECHO
                    273:                        | ECHO
                    274: #endif
                    275: #ifdef ECHOE
                    276:                        | ECHOE
                    277: #endif
                    278: #ifdef ECHOK
                    279:                        | ECHOK
                    280: #endif
                    281: #if ECHONL
                    282:                        | ECHONL
                    283: #endif
                    284:                );
                    285:
                    286:                s.c_oflag |= (0
                    287: #ifdef XTABS
                    288:                        | XTABS
                    289: #else
                    290: #ifdef TAB3
                    291:                        | TAB3
                    292: #else
                    293: #ifdef OXTABS
                    294:                        | OXTABS
                    295: #endif
                    296: #endif
                    297: #endif
                    298: #ifdef OPOST
                    299:                        | OPOST
                    300: #endif
                    301: #ifdef ONLCR
                    302:                        | ONLCR
                    303: #endif
                    304:                );
                    305:
                    306:                s.c_oflag &= ~(0
                    307: #ifdef ONOEOT
                    308:                        | ONOEOT
                    309: #endif
                    310: #ifdef OCRNL
                    311:                        | OCRNL
                    312: #endif
                    313: #ifdef ONOCR
                    314:                        | ONOCR
                    315: #endif
                    316: #ifdef ONLRET
                    317:                        | ONLRET
                    318: #endif
                    319:                );
                    320:                s.c_cc[VMIN] = 1;
                    321:                s.c_cc[VTIME] = 0;
                    322:        } else
                    323:        {
                    324:                /*
                    325:                 * Restore saved modes.
                    326:                 */
                    327:                s = save_term;
                    328:        }
1.5       millert   329:        if (tcsetattr(tty_fd, TCSANOW, &s) == -1)
                    330:                return;
1.1       etheisen  331:     }
                    332: #else
                    333: #ifdef TCGETA
                    334:     {
                    335:        struct termio s;
                    336:        static struct termio save_term;
                    337:
                    338:        if (on)
                    339:        {
                    340:                /*
                    341:                 * Get terminal modes.
                    342:                 */
1.5       millert   343:                ioctl(tty_fd, TCGETA, &s);
1.1       etheisen  344:
                    345:                /*
                    346:                 * Save modes and set certain variables dependent on modes.
                    347:                 */
                    348:                save_term = s;
                    349: #if HAVE_OSPEED
                    350:                ospeed = s.c_cflag & CBAUD;
                    351: #endif
                    352:                erase_char = s.c_cc[VERASE];
                    353:                kill_char = s.c_cc[VKILL];
                    354: #ifdef VWERASE
                    355:                werase_char = s.c_cc[VWERASE];
                    356: #else
                    357:                werase_char = 0;
                    358: #endif
                    359:
                    360:                /*
                    361:                 * Set the modes to the way we want them.
                    362:                 */
                    363:                s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
                    364:                s.c_oflag |=  (OPOST|ONLCR|TAB3);
                    365:                s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
                    366:                s.c_cc[VMIN] = 1;
                    367:                s.c_cc[VTIME] = 0;
                    368:        } else
                    369:        {
                    370:                /*
                    371:                 * Restore saved modes.
                    372:                 */
                    373:                s = save_term;
                    374:        }
1.5       millert   375:        ioctl(tty_fd, TCSETAW, &s);
1.1       etheisen  376:     }
                    377: #else
                    378:     {
                    379:        struct sgttyb s;
                    380:        static struct sgttyb save_term;
                    381:
                    382:        if (on)
                    383:        {
                    384:                /*
                    385:                 * Get terminal modes.
                    386:                 */
1.5       millert   387:                ioctl(tty_fd, TIOCGETP, &s);
1.1       etheisen  388:
                    389:                /*
                    390:                 * Save modes and set certain variables dependent on modes.
                    391:                 */
                    392:                save_term = s;
                    393: #if HAVE_OSPEED
                    394:                ospeed = s.sg_ospeed;
                    395: #endif
                    396:                erase_char = s.sg_erase;
                    397:                kill_char = s.sg_kill;
                    398:                werase_char = 0;
                    399:
                    400:                /*
                    401:                 * Set the modes to the way we want them.
                    402:                 */
                    403:                s.sg_flags |= CBREAK;
                    404:                s.sg_flags &= ~(ECHO|XTABS);
                    405:        } else
                    406:        {
                    407:                /*
                    408:                 * Restore saved modes.
                    409:                 */
                    410:                s = save_term;
                    411:        }
1.5       millert   412:        ioctl(tty_fd, TIOCSETN, &s);
1.1       etheisen  413:     }
                    414: #endif
                    415: #endif
                    416: #endif
                    417:        curr_on = on;
                    418: }
                    419:
                    420:        static void
                    421: cannot(s)
                    422:        char *s;
                    423: {
                    424:        PARG parg;
                    425:
1.2       etheisen  426:        if (know_dumb || more_mode)
1.1       etheisen  427:                /*
                    428:                 * User knows this is a dumb terminal, so don't tell him.
1.2       etheisen  429:                 * more doesn't complain about these, either.
1.1       etheisen  430:                 */
                    431:                return;
                    432:
                    433:        parg.p_string = s;
                    434:        error("WARNING: terminal cannot %s", &parg);
                    435: }
                    436:
                    437: /*
                    438:  * Get size of the output screen.
                    439:  */
                    440: #if OS2
                    441:        public void
                    442: scrsize()
                    443: {
                    444:        int s[2];
                    445:
                    446:        _scrsize(s);
                    447:        sc_width = s[0];
                    448:        sc_height = s[1];
                    449: }
                    450:
                    451: #else
                    452:
                    453:        public void
                    454: scrsize()
                    455: {
1.8       mpech     456:        char *s;
1.1       etheisen  457: #ifdef TIOCGWINSZ
                    458:        struct winsize w;
                    459: #else
                    460: #ifdef WIOCGETD
                    461:        struct uwdata w;
                    462: #endif
                    463: #endif
                    464:
1.5       millert   465:        if (tty_fd == -1 && (tty_fd = open("/dev/tty", O_RDWR)) < 0)
                    466:                tty_fd = 2;
                    467:
1.1       etheisen  468: #ifdef TIOCGWINSZ
1.5       millert   469:        if (ioctl(tty_fd, TIOCGWINSZ, &w) == 0 && w.ws_row > 0)
1.1       etheisen  470:                sc_height = w.ws_row;
                    471:        else
                    472: #else
                    473: #ifdef WIOCGETD
1.5       millert   474:        if (ioctl(tty_fd, WIOCGETD, &w) == 0 && w.uw_height > 0)
1.1       etheisen  475:                sc_height = w.uw_height/w.uw_vs;
                    476:        else
                    477: #endif
                    478: #endif
                    479:        if ((s = getenv("LINES")) != NULL)
                    480:                sc_height = atoi(s);
                    481:        else
                    482:                sc_height = tgetnum("li");
                    483:
                    484:        if (sc_height <= 0)
                    485:                sc_height = 24;
                    486:
                    487: #ifdef TIOCGWINSZ
1.5       millert   488:        if (ioctl(tty_fd, TIOCGWINSZ, &w) == 0 && w.ws_col > 0)
1.1       etheisen  489:                sc_width = w.ws_col;
                    490:        else
                    491: #ifdef WIOCGETD
1.5       millert   492:        if (ioctl(tty_fd, WIOCGETD, &w) == 0 && w.uw_width > 0)
1.1       etheisen  493:                sc_width = w.uw_width/w.uw_hs;
                    494:        else
                    495: #endif
                    496: #endif
                    497:        if ((s = getenv("COLUMNS")) != NULL)
                    498:                sc_width = atoi(s);
                    499:        else
                    500:                sc_width = tgetnum("co");
                    501:
                    502:        if (sc_width <= 0)
                    503:                sc_width = 80;
                    504: }
                    505: #endif /* OS2 */
                    506:
                    507: /*
                    508:  * Take care of the "variable" keys.
                    509:  * Certain keys send escape sequences which differ on different terminals
                    510:  * (such as the arrow keys, INSERT, DELETE, etc.)
                    511:  * Construct the commands based on these keys.
                    512:  */
                    513:        public void
                    514: get_editkeys()
                    515: {
                    516:        char *sp;
                    517:        char *s;
                    518:        char tbuf[40];
                    519:
                    520:        static char kfcmdtable[400];
                    521:        int sz_kfcmdtable = 0;
                    522:        static char kecmdtable[400];
                    523:        int sz_kecmdtable = 0;
                    524:
                    525: #define        put_cmd(str,action,tbl,sz) { \
                    526:        strcpy(tbl+sz, str);    \
                    527:        sz += strlen(str) + 1;  \
                    528:        tbl[sz++] = action; }
                    529: #define        put_esc_cmd(str,action,tbl,sz) { \
                    530:        tbl[sz++] = ESC; \
                    531:        put_cmd(str,action,tbl,sz); }
                    532:
                    533: #define        put_fcmd(str,action)    put_cmd(str,action,kfcmdtable,sz_kfcmdtable)
                    534: #define        put_ecmd(str,action)    put_cmd(str,action,kecmdtable,sz_kecmdtable)
                    535: #define        put_esc_fcmd(str,action) put_esc_cmd(str,action,kfcmdtable,sz_kfcmdtable)
                    536: #define        put_esc_ecmd(str,action) put_esc_cmd(str,action,kecmdtable,sz_kecmdtable)
                    537:
                    538:        /*
                    539:         * Look at some interesting keys and see what strings they send.
                    540:         * Create commands (both command keys and line-edit keys).
                    541:         */
                    542:
                    543:        /* RIGHT ARROW */
                    544:        sp = tbuf;
                    545:        if ((s = tgetstr("kr", &sp)) != NULL)
                    546:        {
                    547:                put_ecmd(s, EC_RIGHT);
                    548:                put_esc_ecmd(s, EC_W_RIGHT);
                    549:        }
                    550:
                    551:        /* LEFT ARROW */
                    552:        sp = tbuf;
                    553:        if ((s = tgetstr("kl", &sp)) != NULL)
                    554:        {
                    555:                put_ecmd(s, EC_LEFT);
                    556:                put_esc_ecmd(s, EC_W_LEFT);
                    557:        }
                    558:
                    559:        /* UP ARROW */
                    560:        sp = tbuf;
                    561:        if ((s = tgetstr("ku", &sp)) != NULL)
                    562:        {
                    563:                put_ecmd(s, EC_UP);
                    564:                put_fcmd(s, A_B_LINE);
                    565:        }
                    566:
                    567:        /* DOWN ARROW */
                    568:        sp = tbuf;
                    569:        if ((s = tgetstr("kd", &sp)) != NULL)
                    570:        {
                    571:                put_ecmd(s, EC_DOWN);
                    572:                put_fcmd(s, A_F_LINE);
                    573:        }
                    574:
                    575:        /* PAGE UP */
                    576:        sp = tbuf;
                    577:        if ((s = tgetstr("kP", &sp)) != NULL)
                    578:        {
                    579:                put_fcmd(s, A_B_SCREEN);
                    580:        }
                    581:
                    582:        /* PAGE DOWN */
                    583:        sp = tbuf;
                    584:        if ((s = tgetstr("kN", &sp)) != NULL)
                    585:        {
                    586:                put_fcmd(s, A_F_SCREEN);
                    587:        }
                    588:
                    589:        /* HOME */
                    590:        sp = tbuf;
                    591:        if ((s = tgetstr("kh", &sp)) != NULL)
                    592:        {
                    593:                put_ecmd(s, EC_HOME);
                    594:        }
                    595:
                    596:        /* END */
                    597:        sp = tbuf;
                    598:        if ((s = tgetstr("@7", &sp)) != NULL)
                    599:        {
                    600:                put_ecmd(s, EC_END);
                    601:        }
                    602:
                    603:        /* DELETE */
                    604:        sp = tbuf;
                    605:        if ((s = tgetstr("kD", &sp)) == NULL)
                    606:        {
                    607:                /* Use DEL (\177) if no "kD" termcap. */
                    608:                tbuf[1] = '\177';
                    609:                tbuf[2] = '\0';
                    610:                s = tbuf+1;
                    611:        }
                    612:        put_ecmd(s, EC_DELETE);
                    613:        put_esc_ecmd(s, EC_W_DELETE);
                    614:
                    615:        /* BACKSPACE */
                    616:        tbuf[0] = ESC;
                    617:        tbuf[1] = erase_char;
                    618:        tbuf[2] = '\0';
                    619:        put_ecmd(tbuf, EC_W_BACKSPACE);
                    620:
                    621:        if (werase_char != 0)
                    622:        {
                    623:                tbuf[0] = werase_char;
                    624:                tbuf[1] = '\0';
                    625:                put_ecmd(tbuf, EC_W_BACKSPACE);
                    626:        }
                    627:
                    628:        /*
                    629:         * Register the two tables.
                    630:         */
                    631:        add_fcmd_table(kfcmdtable, sz_kfcmdtable);
                    632:        add_ecmd_table(kecmdtable, sz_kecmdtable);
                    633: }
                    634:
                    635: #if DEBUG
                    636:        static void
                    637: get_debug_term()
                    638: {
                    639:        auto_wrap = 1;
                    640:        ignaw = 1;
                    641:        so_s_width = so_e_width = 0;
                    642:        bo_s_width = bo_e_width = 0;
                    643:        ul_s_width = ul_e_width = 0;
                    644:        bl_s_width = bl_e_width = 0;
                    645:        sc_s_keypad =   "(InitKey)";
                    646:        sc_e_keypad =   "(DeinitKey)";
                    647:        sc_init =       "(InitTerm)";
                    648:        sc_deinit =     "(DeinitTerm)";
                    649:        sc_eol_clear =  "(ClearEOL)";
                    650:        sc_eos_clear =  "(ClearEOS)";
                    651:        sc_clear =      "(ClearScreen)";
                    652:        sc_move =       "(Move<%d,%d>)";
                    653:        sc_s_in =       "(SO+)";
                    654:        sc_s_out =      "(SO-)";
                    655:        sc_u_in =       "(UL+)";
                    656:        sc_u_out =      "(UL-)";
                    657:        sc_b_in =       "(BO+)";
                    658:        sc_b_out =      "(BO-)";
                    659:        sc_bl_in =      "(BL+)";
                    660:        sc_bl_out =     "(BL-)";
                    661:        sc_visual_bell ="(VBell)";
                    662:        sc_backspace =  "(BS)";
                    663:        sc_home =       "(Home)";
                    664:        sc_lower_left = "(LL)";
                    665:        sc_addline =    "(AddLine)";
                    666: }
                    667: #endif
                    668:
                    669: /*
                    670:  * Get terminal capabilities via termcap.
                    671:  */
                    672:        public void
                    673: get_term()
                    674: {
                    675:        char *sp;
1.8       mpech     676:        char *t1, *t2;
                    677:        int hard;
1.1       etheisen  678:        char *term;
                    679:        char termbuf[2048];
                    680:
                    681:        static char sbuf[1024];
                    682:
                    683: #ifdef OS2
                    684:        /*
                    685:         * Make sure the termcap database is available.
                    686:         */
                    687:        sp = getenv("TERMCAP");
                    688:        if (sp == NULL || *sp == '\0')
                    689:        {
                    690:                char *termcap;
                    691:                if ((sp = homefile("termcap.dat")) != NULL)
                    692:                {
1.10    ! deraadt   693:                        size_t l = strlen(sp)+9;
        !           694:                        termcap = (char *) ecalloc(l, sizeof(char));
        !           695:                        snprintf(termcap, l, "TERMCAP=%s", sp);
1.1       etheisen  696:                        free(sp);
                    697:                        putenv(termcap);
                    698:                }
                    699:        }
                    700: #endif
                    701:        /*
                    702:         * Find out what kind of terminal this is.
                    703:         */
                    704:        if ((term = getenv("TERM")) == NULL)
                    705:                term = DEFAULT_TERM;
                    706:        if (tgetent(termbuf, term) <= 0)
1.9       deraadt   707:                strlcpy(termbuf, "dumb:hc:", sizeof termbuf);
1.1       etheisen  708:
                    709:        hard = tgetflag("hc");
                    710:
                    711:        /*
                    712:         * Get size of the screen.
                    713:         */
                    714:        scrsize();
                    715:        pos_init();
                    716:
                    717: #if DEBUG
                    718:        if (strncmp(term,"LESSDEBUG",9) == 0)
                    719:        {
                    720:                get_debug_term();
                    721:                return;
                    722:        }
                    723: #endif /* DEBUG */
                    724:
                    725:        auto_wrap = tgetflag("am");
                    726:        ignaw = tgetflag("xn");
                    727:        above_mem = tgetflag("da");
                    728:        below_mem = tgetflag("db");
                    729:
                    730:        /*
                    731:         * Assumes termcap variable "sg" is the printing width of:
                    732:         * the standout sequence, the end standout sequence,
                    733:         * the underline sequence, the end underline sequence,
                    734:         * the boldface sequence, and the end boldface sequence.
                    735:         */
                    736:        if ((so_s_width = tgetnum("sg")) < 0)
                    737:                so_s_width = 0;
                    738:        so_e_width = so_s_width;
                    739:
                    740:        bo_s_width = bo_e_width = so_s_width;
                    741:        ul_s_width = ul_e_width = so_s_width;
                    742:        bl_s_width = bl_e_width = so_s_width;
                    743:
                    744: #if HILITE_SEARCH
                    745:        if (so_s_width > 0 || so_e_width > 0)
                    746:                /*
                    747:                 * Disable highlighting by default on magic cookie terminals.
                    748:                 * Turning on highlighting might change the displayed width
                    749:                 * of a line, causing the display to get messed up.
                    750:                 * The user can turn it back on with -g,
                    751:                 * but she won't like the results.
                    752:                 */
                    753:                hilite_search = 0;
                    754: #endif
                    755:
                    756:        /*
                    757:         * Get various string-valued capabilities.
                    758:         */
                    759:        sp = sbuf;
                    760:
                    761: #if HAVE_OSPEED
                    762:        sc_pad = tgetstr("pc", &sp);
                    763:        if (sc_pad != NULL)
                    764:                PC = *sc_pad;
                    765: #endif
                    766:
                    767:        sc_s_keypad = tgetstr("ks", &sp);
                    768:        if (sc_s_keypad == NULL)
                    769:                sc_s_keypad = "";
                    770:        sc_e_keypad = tgetstr("ke", &sp);
                    771:        if (sc_e_keypad == NULL)
                    772:                sc_e_keypad = "";
                    773:
1.2       etheisen  774:        /*
                    775:         * This loses for terminals with termcap entries with ti/te strings
                    776:         * that switch to/from an alternate screen, and we're in quit_at_eof
                    777:         * (eg, more(1)).
                    778:         */
1.6       deraadt   779:        if (!quit_at_eof && !more_mode) {
1.2       etheisen  780:                sc_init = tgetstr("ti", &sp);
                    781:                sc_deinit = tgetstr("te", &sp);
                    782:        }
1.1       etheisen  783:        if (sc_init == NULL)
                    784:                sc_init = "";
                    785:        if (sc_deinit == NULL)
                    786:                sc_deinit = "";
                    787:
                    788:        sc_eol_clear = tgetstr("ce", &sp);
                    789:        if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
                    790:        {
                    791:                cannot("clear to end of line");
                    792:                sc_eol_clear = "";
                    793:        }
                    794:
                    795:        sc_eos_clear = tgetstr("cd", &sp);
                    796:        if (below_mem &&
                    797:                (hard || sc_eos_clear == NULL || *sc_eos_clear == '\0'))
                    798:        {
                    799:                cannot("clear to end of screen");
                    800:                sc_eol_clear = "";
                    801:        }
                    802:
                    803:        sc_clear = tgetstr("cl", &sp);
                    804:        if (hard || sc_clear == NULL || *sc_clear == '\0')
                    805:        {
                    806:                cannot("clear screen");
                    807:                sc_clear = "\n\n";
                    808:        }
                    809:
                    810:        sc_move = tgetstr("cm", &sp);
                    811:        if (hard || sc_move == NULL || *sc_move == '\0')
                    812:        {
                    813:                /*
                    814:                 * This is not an error here, because we don't
                    815:                 * always need sc_move.
                    816:                 * We need it only if we don't have home or lower-left.
                    817:                 */
                    818:                sc_move = "";
                    819:                can_goto_line = 0;
                    820:        } else
                    821:                can_goto_line = 1;
                    822:
                    823:        sc_s_in = tgetstr("so", &sp);
                    824:        if (hard || sc_s_in == NULL)
                    825:                sc_s_in = "";
                    826:
                    827:        sc_s_out = tgetstr("se", &sp);
                    828:        if (hard || sc_s_out == NULL)
                    829:                sc_s_out = "";
                    830:
                    831:        sc_u_in = tgetstr("us", &sp);
                    832:        if (hard || sc_u_in == NULL)
                    833:                sc_u_in = sc_s_in;
                    834:
                    835:        sc_u_out = tgetstr("ue", &sp);
                    836:        if (hard || sc_u_out == NULL)
                    837:                sc_u_out = sc_s_out;
                    838:
                    839:        sc_b_in = tgetstr("md", &sp);
                    840:        if (hard || sc_b_in == NULL)
                    841:        {
                    842:                sc_b_in = sc_s_in;
                    843:                sc_b_out = sc_s_out;
                    844:        } else
                    845:        {
                    846:                sc_b_out = tgetstr("me", &sp);
                    847:                if (hard || sc_b_out == NULL)
                    848:                        sc_b_out = "";
                    849:        }
                    850:
                    851:        sc_bl_in = tgetstr("mb", &sp);
                    852:        if (hard || sc_bl_in == NULL)
                    853:        {
                    854:                sc_bl_in = sc_s_in;
                    855:                sc_bl_out = sc_s_out;
                    856:        } else
                    857:        {
                    858:                sc_bl_out = tgetstr("me", &sp);
                    859:                if (hard || sc_bl_out == NULL)
                    860:                        sc_bl_out = "";
                    861:        }
                    862:
                    863:        sc_visual_bell = tgetstr("vb", &sp);
                    864:        if (hard || sc_visual_bell == NULL)
                    865:                sc_visual_bell = "";
                    866:
                    867:        if (tgetflag("bs"))
                    868:                sc_backspace = "\b";
                    869:        else
                    870:        {
                    871:                sc_backspace = tgetstr("bc", &sp);
                    872:                if (sc_backspace == NULL || *sc_backspace == '\0')
                    873:                        sc_backspace = "\b";
                    874:        }
                    875:
                    876:        /*
                    877:         * Choose between using "ho" and "cm" ("home" and "cursor move")
                    878:         * to move the cursor to the upper left corner of the screen.
                    879:         */
                    880:        t1 = tgetstr("ho", &sp);
                    881:        if (hard || t1 == NULL)
                    882:                t1 = "";
                    883:        if (*sc_move == '\0')
                    884:                t2 = "";
                    885:        else
                    886:        {
1.10    ! deraadt   887:                strlcpy(sp, tgoto(sc_move, 0, 0), sbuf + sizeof sbuf - sp);
1.1       etheisen  888:                t2 = sp;
                    889:                sp += strlen(sp) + 1;
                    890:        }
                    891:        sc_home = cheaper(t1, t2, "home cursor", "|\b^");
                    892:
                    893:        /*
                    894:         * Choose between using "ll" and "cm"  ("lower left" and "cursor move")
                    895:         * to move the cursor to the lower left corner of the screen.
                    896:         */
                    897:        t1 = tgetstr("ll", &sp);
                    898:        if (hard || t1 == NULL)
                    899:                t1 = "";
                    900:        if (*sc_move == '\0')
                    901:                t2 = "";
                    902:        else
                    903:        {
1.10    ! deraadt   904:                strlcpy(sp, tgoto(sc_move, 0, sc_height-1), sbuf + sizeof sbuf - sp);
1.1       etheisen  905:                t2 = sp;
                    906:                sp += strlen(sp) + 1;
                    907:        }
                    908:        sc_lower_left = cheaper(t1, t2,
                    909:                "move cursor to lower left of screen", "\r");
                    910:
                    911:        /*
                    912:         * Choose between using "al" or "sr" ("add line" or "scroll reverse")
                    913:         * to add a line at the top of the screen.
                    914:         */
                    915:        t1 = tgetstr("al", &sp);
                    916:        if (hard || t1 == NULL)
                    917:                t1 = "";
                    918:        t2 = tgetstr("sr", &sp);
                    919:        if (hard || t2 == NULL)
                    920:                t2 = "";
                    921: #if OS2
                    922:        if (*t1 == '\0' && *t2 == '\0')
                    923:                sc_addline = "";
                    924:        else
                    925: #endif
                    926:        if (above_mem)
                    927:                sc_addline = t1;
                    928:        else
                    929:                sc_addline = cheaper(t1, t2, "scroll backwards", "");
                    930:        if (*sc_addline == '\0')
                    931:        {
                    932:                /*
                    933:                 * Force repaint on any backward movement.
                    934:                 */
                    935:                back_scroll = 0;
                    936:        }
                    937: }
                    938:
                    939: /*
                    940:  * Return the cost of displaying a termcap string.
                    941:  * We use the trick of calling tputs, but as a char printing function
                    942:  * we give it inc_costcount, which just increments "costcount".
                    943:  * This tells us how many chars would be printed by using this string.
                    944:  * {{ Couldn't we just use strlen? }}
                    945:  */
                    946: static int costcount;
                    947:
                    948: /*ARGSUSED*/
                    949:        static int
                    950: inc_costcount(c)
                    951:        int c;
                    952: {
                    953:        costcount++;
                    954:        return (c);
                    955: }
                    956:
                    957:        static int
                    958: cost(t)
                    959:        char *t;
                    960: {
                    961:        costcount = 0;
                    962:        tputs(t, sc_height, inc_costcount);
                    963:        return (costcount);
                    964: }
                    965:
                    966: /*
                    967:  * Return the "best" of the two given termcap strings.
                    968:  * The best, if both exist, is the one with the lower
                    969:  * cost (see cost() function).
                    970:  */
                    971:        static char *
                    972: cheaper(t1, t2, doit, def)
                    973:        char *t1, *t2;
                    974:        char *doit;
                    975:        char *def;
                    976: {
                    977:        if (*t1 == '\0' && *t2 == '\0')
                    978:        {
                    979:                cannot(doit);
                    980:                return (def);
                    981:        }
                    982:        if (*t1 == '\0')
                    983:                return (t2);
                    984:        if (*t2 == '\0')
                    985:                return (t1);
                    986:        if (cost(t1) < cost(t2))
                    987:                return (t1);
                    988:        return (t2);
                    989: }
                    990:
                    991:
                    992: /*
                    993:  * Below are the functions which perform all the
                    994:  * terminal-specific screen manipulation.
                    995:  */
                    996:
                    997:
                    998: /*
                    999:  * Initialize terminal
                   1000:  */
                   1001:        public void
                   1002: init()
                   1003: {
                   1004:        if (no_init)
                   1005:                return;
                   1006:        tputs(sc_init, sc_height, putchr);
                   1007:        tputs(sc_s_keypad, sc_height, putchr);
                   1008:        init_done = 1;
                   1009: }
                   1010:
                   1011: /*
                   1012:  * Deinitialize terminal
                   1013:  */
                   1014:        public void
                   1015: deinit()
                   1016: {
                   1017:        if (no_init)
                   1018:                return;
                   1019:        if (!init_done)
                   1020:                return;
                   1021:        tputs(sc_e_keypad, sc_height, putchr);
                   1022:        tputs(sc_deinit, sc_height, putchr);
                   1023:        init_done = 0;
                   1024: }
                   1025:
                   1026: /*
                   1027:  * Home cursor (move to upper left corner of screen).
                   1028:  */
                   1029:        public void
                   1030: home()
                   1031: {
                   1032:        tputs(sc_home, 1, putchr);
                   1033: }
                   1034:
                   1035: /*
                   1036:  * Add a blank line (called with cursor at home).
                   1037:  * Should scroll the display down.
                   1038:  */
                   1039:        public void
                   1040: add_line()
                   1041: {
                   1042:        tputs(sc_addline, sc_height, putchr);
                   1043: }
                   1044:
                   1045: /*
                   1046:  * Move cursor to lower left corner of screen.
                   1047:  */
                   1048:        public void
                   1049: lower_left()
                   1050: {
                   1051:        tputs(sc_lower_left, 1, putchr);
                   1052: }
                   1053:
                   1054: /*
                   1055:  * Goto a specific line on the screen.
                   1056:  */
                   1057:        public void
                   1058: goto_line(slinenum)
                   1059:        int slinenum;
                   1060: {
                   1061:        char *sc_goto;
                   1062:
                   1063:        sc_goto = tgoto(sc_move, 0, slinenum);
                   1064:        tputs(sc_goto, 1, putchr);
                   1065: }
                   1066:
                   1067: /*
                   1068:  * Ring the terminal bell.
                   1069:  */
                   1070:        public void
                   1071: bell()
                   1072: {
                   1073:        if (quiet == VERY_QUIET)
                   1074:                vbell();
                   1075:        else
                   1076:                putchr('\7');
                   1077: }
                   1078:
                   1079: /*
                   1080:  * Output the "visual bell", if there is one.
                   1081:  */
                   1082:        public void
                   1083: vbell()
                   1084: {
                   1085:        if (*sc_visual_bell == '\0')
                   1086:                return;
                   1087:        tputs(sc_visual_bell, sc_height, putchr);
                   1088: }
                   1089:
                   1090: /*
                   1091:  * Clear the screen.
                   1092:  */
                   1093:        public void
                   1094: clear()
                   1095: {
                   1096:        tputs(sc_clear, sc_height, putchr);
                   1097: }
                   1098:
                   1099: /*
                   1100:  * Clear from the cursor to the end of the cursor's line.
                   1101:  * {{ This must not move the cursor. }}
                   1102:  */
                   1103:        public void
                   1104: clear_eol()
                   1105: {
                   1106:        tputs(sc_eol_clear, 1, putchr);
                   1107: }
                   1108:
                   1109: /*
                   1110:  * Clear the bottom line of the display.
                   1111:  * Leave the cursor at the beginning of the bottom line.
                   1112:  */
                   1113:        public void
                   1114: clear_bot()
                   1115: {
                   1116:        lower_left();
                   1117:        if (below_mem)
                   1118:                tputs(sc_eos_clear, 1, putchr);
                   1119:        else
                   1120:                tputs(sc_eol_clear, 1, putchr);
                   1121: }
                   1122:
                   1123: /*
                   1124:  * Begin "standout" (bold, underline, or whatever).
                   1125:  */
                   1126:        public void
                   1127: so_enter()
                   1128: {
                   1129:        tputs(sc_s_in, 1, putchr);
                   1130: }
                   1131:
                   1132: /*
                   1133:  * End "standout".
                   1134:  */
                   1135:        public void
                   1136: so_exit()
                   1137: {
                   1138:        tputs(sc_s_out, 1, putchr);
                   1139: }
                   1140:
                   1141: /*
                   1142:  * Begin "underline" (hopefully real underlining,
                   1143:  * otherwise whatever the terminal provides).
                   1144:  */
                   1145:        public void
                   1146: ul_enter()
                   1147: {
                   1148:        tputs(sc_u_in, 1, putchr);
                   1149: }
                   1150:
                   1151: /*
                   1152:  * End "underline".
                   1153:  */
                   1154:        public void
                   1155: ul_exit()
                   1156: {
                   1157:        tputs(sc_u_out, 1, putchr);
                   1158: }
                   1159:
                   1160: /*
                   1161:  * Begin "bold"
                   1162:  */
                   1163:        public void
                   1164: bo_enter()
                   1165: {
                   1166:        tputs(sc_b_in, 1, putchr);
                   1167: }
                   1168:
                   1169: /*
                   1170:  * End "bold".
                   1171:  */
                   1172:        public void
                   1173: bo_exit()
                   1174: {
                   1175:        tputs(sc_b_out, 1, putchr);
                   1176: }
                   1177:
                   1178: /*
                   1179:  * Begin "blink"
                   1180:  */
                   1181:        public void
                   1182: bl_enter()
                   1183: {
                   1184:        tputs(sc_bl_in, 1, putchr);
                   1185: }
                   1186:
                   1187: /*
                   1188:  * End "blink".
                   1189:  */
                   1190:        public void
                   1191: bl_exit()
                   1192: {
                   1193:        tputs(sc_bl_out, 1, putchr);
                   1194: }
                   1195:
                   1196: /*
                   1197:  * Erase the character to the left of the cursor
                   1198:  * and move the cursor left.
                   1199:  */
                   1200:        public void
                   1201: backspace()
                   1202: {
                   1203:        /*
                   1204:         * Try to erase the previous character by overstriking with a space.
                   1205:         */
                   1206:        tputs(sc_backspace, 1, putchr);
                   1207:        putchr(' ');
                   1208:        tputs(sc_backspace, 1, putchr);
                   1209: }
                   1210:
                   1211: /*
                   1212:  * Output a plain backspace, without erasing the previous char.
                   1213:  */
                   1214:        public void
                   1215: putbs()
                   1216: {
                   1217:        tputs(sc_backspace, 1, putchr);
                   1218: }