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

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