[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     ! 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: }