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

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