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

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