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

1.7     ! niklas      1: /*     $OpenBSD$       */
        !             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: {
                    456:        register char *s;
                    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;
                    676:        register char *t1, *t2;
                    677:        register int hard;
                    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:                {
                    693:                        termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char));
                    694:                        sprintf(termcap, "TERMCAP=%s", sp);
                    695:                        free(sp);
                    696:                        putenv(termcap);
                    697:                }
                    698:        }
                    699: #endif
                    700:        /*
                    701:         * Find out what kind of terminal this is.
                    702:         */
                    703:        if ((term = getenv("TERM")) == NULL)
                    704:                term = DEFAULT_TERM;
                    705:        if (tgetent(termbuf, term) <= 0)
                    706:                strcpy(termbuf, "dumb:hc:");
                    707:
                    708:        hard = tgetflag("hc");
                    709:
                    710:        /*
                    711:         * Get size of the screen.
                    712:         */
                    713:        scrsize();
                    714:        pos_init();
                    715:
                    716: #if DEBUG
                    717:        if (strncmp(term,"LESSDEBUG",9) == 0)
                    718:        {
                    719:                get_debug_term();
                    720:                return;
                    721:        }
                    722: #endif /* DEBUG */
                    723:
                    724:        auto_wrap = tgetflag("am");
                    725:        ignaw = tgetflag("xn");
                    726:        above_mem = tgetflag("da");
                    727:        below_mem = tgetflag("db");
                    728:
                    729:        /*
                    730:         * Assumes termcap variable "sg" is the printing width of:
                    731:         * the standout sequence, the end standout sequence,
                    732:         * the underline sequence, the end underline sequence,
                    733:         * the boldface sequence, and the end boldface sequence.
                    734:         */
                    735:        if ((so_s_width = tgetnum("sg")) < 0)
                    736:                so_s_width = 0;
                    737:        so_e_width = so_s_width;
                    738:
                    739:        bo_s_width = bo_e_width = so_s_width;
                    740:        ul_s_width = ul_e_width = so_s_width;
                    741:        bl_s_width = bl_e_width = so_s_width;
                    742:
                    743: #if HILITE_SEARCH
                    744:        if (so_s_width > 0 || so_e_width > 0)
                    745:                /*
                    746:                 * Disable highlighting by default on magic cookie terminals.
                    747:                 * Turning on highlighting might change the displayed width
                    748:                 * of a line, causing the display to get messed up.
                    749:                 * The user can turn it back on with -g,
                    750:                 * but she won't like the results.
                    751:                 */
                    752:                hilite_search = 0;
                    753: #endif
                    754:
                    755:        /*
                    756:         * Get various string-valued capabilities.
                    757:         */
                    758:        sp = sbuf;
                    759:
                    760: #if HAVE_OSPEED
                    761:        sc_pad = tgetstr("pc", &sp);
                    762:        if (sc_pad != NULL)
                    763:                PC = *sc_pad;
                    764: #endif
                    765:
                    766:        sc_s_keypad = tgetstr("ks", &sp);
                    767:        if (sc_s_keypad == NULL)
                    768:                sc_s_keypad = "";
                    769:        sc_e_keypad = tgetstr("ke", &sp);
                    770:        if (sc_e_keypad == NULL)
                    771:                sc_e_keypad = "";
                    772:
1.2       etheisen  773:        /*
                    774:         * This loses for terminals with termcap entries with ti/te strings
                    775:         * that switch to/from an alternate screen, and we're in quit_at_eof
                    776:         * (eg, more(1)).
                    777:         */
1.6       deraadt   778:        if (!quit_at_eof && !more_mode) {
1.2       etheisen  779:                sc_init = tgetstr("ti", &sp);
                    780:                sc_deinit = tgetstr("te", &sp);
                    781:        }
1.1       etheisen  782:        if (sc_init == NULL)
                    783:                sc_init = "";
                    784:        if (sc_deinit == NULL)
                    785:                sc_deinit = "";
                    786:
                    787:        sc_eol_clear = tgetstr("ce", &sp);
                    788:        if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
                    789:        {
                    790:                cannot("clear to end of line");
                    791:                sc_eol_clear = "";
                    792:        }
                    793:
                    794:        sc_eos_clear = tgetstr("cd", &sp);
                    795:        if (below_mem &&
                    796:                (hard || sc_eos_clear == NULL || *sc_eos_clear == '\0'))
                    797:        {
                    798:                cannot("clear to end of screen");
                    799:                sc_eol_clear = "";
                    800:        }
                    801:
                    802:        sc_clear = tgetstr("cl", &sp);
                    803:        if (hard || sc_clear == NULL || *sc_clear == '\0')
                    804:        {
                    805:                cannot("clear screen");
                    806:                sc_clear = "\n\n";
                    807:        }
                    808:
                    809:        sc_move = tgetstr("cm", &sp);
                    810:        if (hard || sc_move == NULL || *sc_move == '\0')
                    811:        {
                    812:                /*
                    813:                 * This is not an error here, because we don't
                    814:                 * always need sc_move.
                    815:                 * We need it only if we don't have home or lower-left.
                    816:                 */
                    817:                sc_move = "";
                    818:                can_goto_line = 0;
                    819:        } else
                    820:                can_goto_line = 1;
                    821:
                    822:        sc_s_in = tgetstr("so", &sp);
                    823:        if (hard || sc_s_in == NULL)
                    824:                sc_s_in = "";
                    825:
                    826:        sc_s_out = tgetstr("se", &sp);
                    827:        if (hard || sc_s_out == NULL)
                    828:                sc_s_out = "";
                    829:
                    830:        sc_u_in = tgetstr("us", &sp);
                    831:        if (hard || sc_u_in == NULL)
                    832:                sc_u_in = sc_s_in;
                    833:
                    834:        sc_u_out = tgetstr("ue", &sp);
                    835:        if (hard || sc_u_out == NULL)
                    836:                sc_u_out = sc_s_out;
                    837:
                    838:        sc_b_in = tgetstr("md", &sp);
                    839:        if (hard || sc_b_in == NULL)
                    840:        {
                    841:                sc_b_in = sc_s_in;
                    842:                sc_b_out = sc_s_out;
                    843:        } else
                    844:        {
                    845:                sc_b_out = tgetstr("me", &sp);
                    846:                if (hard || sc_b_out == NULL)
                    847:                        sc_b_out = "";
                    848:        }
                    849:
                    850:        sc_bl_in = tgetstr("mb", &sp);
                    851:        if (hard || sc_bl_in == NULL)
                    852:        {
                    853:                sc_bl_in = sc_s_in;
                    854:                sc_bl_out = sc_s_out;
                    855:        } else
                    856:        {
                    857:                sc_bl_out = tgetstr("me", &sp);
                    858:                if (hard || sc_bl_out == NULL)
                    859:                        sc_bl_out = "";
                    860:        }
                    861:
                    862:        sc_visual_bell = tgetstr("vb", &sp);
                    863:        if (hard || sc_visual_bell == NULL)
                    864:                sc_visual_bell = "";
                    865:
                    866:        if (tgetflag("bs"))
                    867:                sc_backspace = "\b";
                    868:        else
                    869:        {
                    870:                sc_backspace = tgetstr("bc", &sp);
                    871:                if (sc_backspace == NULL || *sc_backspace == '\0')
                    872:                        sc_backspace = "\b";
                    873:        }
                    874:
                    875:        /*
                    876:         * Choose between using "ho" and "cm" ("home" and "cursor move")
                    877:         * to move the cursor to the upper left corner of the screen.
                    878:         */
                    879:        t1 = tgetstr("ho", &sp);
                    880:        if (hard || t1 == NULL)
                    881:                t1 = "";
                    882:        if (*sc_move == '\0')
                    883:                t2 = "";
                    884:        else
                    885:        {
                    886:                strcpy(sp, tgoto(sc_move, 0, 0));
                    887:                t2 = sp;
                    888:                sp += strlen(sp) + 1;
                    889:        }
                    890:        sc_home = cheaper(t1, t2, "home cursor", "|\b^");
                    891:
                    892:        /*
                    893:         * Choose between using "ll" and "cm"  ("lower left" and "cursor move")
                    894:         * to move the cursor to the lower left corner of the screen.
                    895:         */
                    896:        t1 = tgetstr("ll", &sp);
                    897:        if (hard || t1 == NULL)
                    898:                t1 = "";
                    899:        if (*sc_move == '\0')
                    900:                t2 = "";
                    901:        else
                    902:        {
                    903:                strcpy(sp, tgoto(sc_move, 0, sc_height-1));
                    904:                t2 = sp;
                    905:                sp += strlen(sp) + 1;
                    906:        }
                    907:        sc_lower_left = cheaper(t1, t2,
                    908:                "move cursor to lower left of screen", "\r");
                    909:
                    910:        /*
                    911:         * Choose between using "al" or "sr" ("add line" or "scroll reverse")
                    912:         * to add a line at the top of the screen.
                    913:         */
                    914:        t1 = tgetstr("al", &sp);
                    915:        if (hard || t1 == NULL)
                    916:                t1 = "";
                    917:        t2 = tgetstr("sr", &sp);
                    918:        if (hard || t2 == NULL)
                    919:                t2 = "";
                    920: #if OS2
                    921:        if (*t1 == '\0' && *t2 == '\0')
                    922:                sc_addline = "";
                    923:        else
                    924: #endif
                    925:        if (above_mem)
                    926:                sc_addline = t1;
                    927:        else
                    928:                sc_addline = cheaper(t1, t2, "scroll backwards", "");
                    929:        if (*sc_addline == '\0')
                    930:        {
                    931:                /*
                    932:                 * Force repaint on any backward movement.
                    933:                 */
                    934:                back_scroll = 0;
                    935:        }
                    936: }
                    937:
                    938: /*
                    939:  * Return the cost of displaying a termcap string.
                    940:  * We use the trick of calling tputs, but as a char printing function
                    941:  * we give it inc_costcount, which just increments "costcount".
                    942:  * This tells us how many chars would be printed by using this string.
                    943:  * {{ Couldn't we just use strlen? }}
                    944:  */
                    945: static int costcount;
                    946:
                    947: /*ARGSUSED*/
                    948:        static int
                    949: inc_costcount(c)
                    950:        int c;
                    951: {
                    952:        costcount++;
                    953:        return (c);
                    954: }
                    955:
                    956:        static int
                    957: cost(t)
                    958:        char *t;
                    959: {
                    960:        costcount = 0;
                    961:        tputs(t, sc_height, inc_costcount);
                    962:        return (costcount);
                    963: }
                    964:
                    965: /*
                    966:  * Return the "best" of the two given termcap strings.
                    967:  * The best, if both exist, is the one with the lower
                    968:  * cost (see cost() function).
                    969:  */
                    970:        static char *
                    971: cheaper(t1, t2, doit, def)
                    972:        char *t1, *t2;
                    973:        char *doit;
                    974:        char *def;
                    975: {
                    976:        if (*t1 == '\0' && *t2 == '\0')
                    977:        {
                    978:                cannot(doit);
                    979:                return (def);
                    980:        }
                    981:        if (*t1 == '\0')
                    982:                return (t2);
                    983:        if (*t2 == '\0')
                    984:                return (t1);
                    985:        if (cost(t1) < cost(t2))
                    986:                return (t1);
                    987:        return (t2);
                    988: }
                    989:
                    990:
                    991: /*
                    992:  * Below are the functions which perform all the
                    993:  * terminal-specific screen manipulation.
                    994:  */
                    995:
                    996:
                    997: /*
                    998:  * Initialize terminal
                    999:  */
                   1000:        public void
                   1001: init()
                   1002: {
                   1003:        if (no_init)
                   1004:                return;
                   1005:        tputs(sc_init, sc_height, putchr);
                   1006:        tputs(sc_s_keypad, sc_height, putchr);
                   1007:        init_done = 1;
                   1008: }
                   1009:
                   1010: /*
                   1011:  * Deinitialize terminal
                   1012:  */
                   1013:        public void
                   1014: deinit()
                   1015: {
                   1016:        if (no_init)
                   1017:                return;
                   1018:        if (!init_done)
                   1019:                return;
                   1020:        tputs(sc_e_keypad, sc_height, putchr);
                   1021:        tputs(sc_deinit, sc_height, putchr);
                   1022:        init_done = 0;
                   1023: }
                   1024:
                   1025: /*
                   1026:  * Home cursor (move to upper left corner of screen).
                   1027:  */
                   1028:        public void
                   1029: home()
                   1030: {
                   1031:        tputs(sc_home, 1, putchr);
                   1032: }
                   1033:
                   1034: /*
                   1035:  * Add a blank line (called with cursor at home).
                   1036:  * Should scroll the display down.
                   1037:  */
                   1038:        public void
                   1039: add_line()
                   1040: {
                   1041:        tputs(sc_addline, sc_height, putchr);
                   1042: }
                   1043:
                   1044: /*
                   1045:  * Move cursor to lower left corner of screen.
                   1046:  */
                   1047:        public void
                   1048: lower_left()
                   1049: {
                   1050:        tputs(sc_lower_left, 1, putchr);
                   1051: }
                   1052:
                   1053: /*
                   1054:  * Goto a specific line on the screen.
                   1055:  */
                   1056:        public void
                   1057: goto_line(slinenum)
                   1058:        int slinenum;
                   1059: {
                   1060:        char *sc_goto;
                   1061:
                   1062:        sc_goto = tgoto(sc_move, 0, slinenum);
                   1063:        tputs(sc_goto, 1, putchr);
                   1064: }
                   1065:
                   1066: /*
                   1067:  * Ring the terminal bell.
                   1068:  */
                   1069:        public void
                   1070: bell()
                   1071: {
                   1072:        if (quiet == VERY_QUIET)
                   1073:                vbell();
                   1074:        else
                   1075:                putchr('\7');
                   1076: }
                   1077:
                   1078: /*
                   1079:  * Output the "visual bell", if there is one.
                   1080:  */
                   1081:        public void
                   1082: vbell()
                   1083: {
                   1084:        if (*sc_visual_bell == '\0')
                   1085:                return;
                   1086:        tputs(sc_visual_bell, sc_height, putchr);
                   1087: }
                   1088:
                   1089: /*
                   1090:  * Clear the screen.
                   1091:  */
                   1092:        public void
                   1093: clear()
                   1094: {
                   1095:        tputs(sc_clear, sc_height, putchr);
                   1096: }
                   1097:
                   1098: /*
                   1099:  * Clear from the cursor to the end of the cursor's line.
                   1100:  * {{ This must not move the cursor. }}
                   1101:  */
                   1102:        public void
                   1103: clear_eol()
                   1104: {
                   1105:        tputs(sc_eol_clear, 1, putchr);
                   1106: }
                   1107:
                   1108: /*
                   1109:  * Clear the bottom line of the display.
                   1110:  * Leave the cursor at the beginning of the bottom line.
                   1111:  */
                   1112:        public void
                   1113: clear_bot()
                   1114: {
                   1115:        lower_left();
                   1116:        if (below_mem)
                   1117:                tputs(sc_eos_clear, 1, putchr);
                   1118:        else
                   1119:                tputs(sc_eol_clear, 1, putchr);
                   1120: }
                   1121:
                   1122: /*
                   1123:  * Begin "standout" (bold, underline, or whatever).
                   1124:  */
                   1125:        public void
                   1126: so_enter()
                   1127: {
                   1128:        tputs(sc_s_in, 1, putchr);
                   1129: }
                   1130:
                   1131: /*
                   1132:  * End "standout".
                   1133:  */
                   1134:        public void
                   1135: so_exit()
                   1136: {
                   1137:        tputs(sc_s_out, 1, putchr);
                   1138: }
                   1139:
                   1140: /*
                   1141:  * Begin "underline" (hopefully real underlining,
                   1142:  * otherwise whatever the terminal provides).
                   1143:  */
                   1144:        public void
                   1145: ul_enter()
                   1146: {
                   1147:        tputs(sc_u_in, 1, putchr);
                   1148: }
                   1149:
                   1150: /*
                   1151:  * End "underline".
                   1152:  */
                   1153:        public void
                   1154: ul_exit()
                   1155: {
                   1156:        tputs(sc_u_out, 1, putchr);
                   1157: }
                   1158:
                   1159: /*
                   1160:  * Begin "bold"
                   1161:  */
                   1162:        public void
                   1163: bo_enter()
                   1164: {
                   1165:        tputs(sc_b_in, 1, putchr);
                   1166: }
                   1167:
                   1168: /*
                   1169:  * End "bold".
                   1170:  */
                   1171:        public void
                   1172: bo_exit()
                   1173: {
                   1174:        tputs(sc_b_out, 1, putchr);
                   1175: }
                   1176:
                   1177: /*
                   1178:  * Begin "blink"
                   1179:  */
                   1180:        public void
                   1181: bl_enter()
                   1182: {
                   1183:        tputs(sc_bl_in, 1, putchr);
                   1184: }
                   1185:
                   1186: /*
                   1187:  * End "blink".
                   1188:  */
                   1189:        public void
                   1190: bl_exit()
                   1191: {
                   1192:        tputs(sc_bl_out, 1, putchr);
                   1193: }
                   1194:
                   1195: /*
                   1196:  * Erase the character to the left of the cursor
                   1197:  * and move the cursor left.
                   1198:  */
                   1199:        public void
                   1200: backspace()
                   1201: {
                   1202:        /*
                   1203:         * Try to erase the previous character by overstriking with a space.
                   1204:         */
                   1205:        tputs(sc_backspace, 1, putchr);
                   1206:        putchr(' ');
                   1207:        tputs(sc_backspace, 1, putchr);
                   1208: }
                   1209:
                   1210: /*
                   1211:  * Output a plain backspace, without erasing the previous char.
                   1212:  */
                   1213:        public void
                   1214: putbs()
                   1215: {
                   1216:        tputs(sc_backspace, 1, putchr);
                   1217: }