Annotation of 43BSDReno/contrib/mh/miscellany/less/screen.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Routines which deal with the characteristics of the terminal.
                      3:  * Uses termcap to be as terminal-independent as possible.
                      4:  *
                      5:  * {{ Someday this should be rewritten to use curses. }}
                      6:  */
                      7: 
                      8: #include "less.h"
                      9: #if XENIX
                     10: #include <sys/types.h>
                     11: #include <sys/ioctl.h>
                     12: #endif
                     13: 
                     14: #if TERMIO
                     15: #include <termio.h>
                     16: #else
                     17: #include <sgtty.h>
                     18: #endif
                     19: 
                     20: /*
                     21:  * Strings passed to tputs() to do various terminal functions.
                     22:  */
                     23: static char
                     24:        *sc_pad,                /* Pad string */
                     25:        *sc_home,               /* Cursor home */
                     26:        *sc_addline,            /* Add line, scroll down following lines */
                     27:        *sc_lower_left,         /* Cursor to last line, first column */
                     28:        *sc_move,               /* General cursor positioning */
                     29:        *sc_clear,              /* Clear screen */
                     30:        *sc_eol_clear,          /* Clear to end of line */
                     31:        *sc_s_in,               /* Enter standout (highlighted) mode */
                     32:        *sc_s_out,              /* Exit standout mode */
                     33:        *sc_u_in,               /* Enter underline mode */
                     34:        *sc_u_out,              /* Exit underline mode */
                     35:        *sc_visual_bell,        /* Visual bell (flash screen) sequence */
                     36:        *sc_backspace,          /* Backspace cursor */
                     37:        *sc_init,               /* Startup terminal initialization */
                     38:        *sc_deinit;             /* Exit terminal de-intialization */
                     39: static int dumb;
                     40: static int hard;
                     41: 
                     42: public int auto_wrap;          /* Terminal does \r\n when write past margin */
                     43: public int ignaw;              /* Terminal ignores \n immediately after wrap */
                     44: public int erase_char, kill_char; /* The user's erase and line-kill chars */
                     45: public int sc_width, sc_height;        /* Height & width of screen */
                     46: public int ul_width, ue_width; /* Printing width of underline sequences */
                     47: public int so_width, se_width; /* Printing width of standout sequences */
                     48: 
                     49: /*
                     50:  * These two variables are sometimes defined in,
                     51:  * and needed by, the termcap library.
                     52:  * It may be necessary on some systems to declare them extern here.
                     53:  */
                     54: /*extern*/ short ospeed;       /* Terminal output baud rate */
                     55: /*extern*/ char PC;            /* Pad character */
                     56: 
                     57: extern int quiet;              /* If VERY_QUIET, use visual bell for bell */
                     58: extern int know_dumb;          /* Don't complain about a dumb terminal */
                     59: extern int back_scroll;
                     60: char *tgetstr();
                     61: char *tgoto();
                     62: 
                     63: /*
                     64:  * Change terminal to "raw mode", or restore to "normal" mode.
                     65:  * "Raw mode" means 
                     66:  *     1. An outstanding read will complete on receipt of a single keystroke.
                     67:  *     2. Input is not echoed.  
                     68:  *     3. On output, \n is mapped to \r\n.
                     69:  *     4. \t is NOT be expanded into spaces.
                     70:  *     5. Signal-causing characters such as ctrl-C (interrupt),
                     71:  *        etc. are NOT disabled.
                     72:  * It doesn't matter whether an input \n is mapped to \r, or vice versa.
                     73:  */
                     74:        public void
                     75: raw_mode(on)
                     76:        int on;
                     77: {
                     78: #if TERMIO
                     79:        struct termio s;
                     80:        static struct termio save_term;
                     81: 
                     82:        if (on)
                     83:        {
                     84:                /*
                     85:                 * Get terminal modes.
                     86:                 */
                     87:                ioctl(2, TCGETA, &s);
                     88: 
                     89:                /*
                     90:                 * Save modes and set certain variables dependent on modes.
                     91:                 */
                     92:                save_term = s;
                     93:                ospeed = s.c_cflag & CBAUD;
                     94:                erase_char = s.c_cc[VERASE];
                     95:                kill_char = s.c_cc[VKILL];
                     96: 
                     97:                /*
                     98:                 * Set the modes to the way we want them.
                     99:                 */
                    100:                s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
                    101:                s.c_oflag |=  (OPOST|ONLCR|TAB3);
                    102:                s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
                    103:                s.c_cc[VMIN] = 1;
                    104:                s.c_cc[VTIME] = 0;
                    105:        } else
                    106:        {
                    107:                /*
                    108:                 * Restore saved modes.
                    109:                 */
                    110:                s = save_term;
                    111:        }
                    112:        ioctl(2, TCSETAW, &s);
                    113: #else
                    114:        struct sgttyb s;
                    115:        static struct sgttyb save_term;
                    116: 
                    117:        if (on)
                    118:        {
                    119:                /*
                    120:                 * Get terminal modes.
                    121:                 */
                    122:                ioctl(2, TIOCGETP, &s);
                    123: 
                    124:                /*
                    125:                 * Save modes and set certain variables dependent on modes.
                    126:                 */
                    127:                save_term = s;
                    128:                ospeed = s.sg_ospeed;
                    129:                erase_char = s.sg_erase;
                    130:                kill_char = s.sg_kill;
                    131: 
                    132:                /*
                    133:                 * Set the modes to the way we want them.
                    134:                 */
                    135:                s.sg_flags |= CBREAK;
                    136:                s.sg_flags &= ~(ECHO|XTABS);
                    137:        } else
                    138:        {
                    139:                /*
                    140:                 * Restore saved modes.
                    141:                 */
                    142:                s = save_term;
                    143:        }
                    144:        ioctl(2, TIOCSETN, &s);
                    145: #endif
                    146: }
                    147: 
                    148: static int couldnt = 0;
                    149: 
                    150:        static void
                    151: cannot(s)
                    152:        char *s;
                    153: {
                    154:        if (know_dumb)
                    155:                /* 
                    156:                 * He knows he has a dumb terminal, so don't tell him. 
                    157:                 */
                    158:                return;
                    159: 
                    160:        printf("WARNING: terminal cannot \"%s\"\n", s);
                    161:        couldnt = 1;
                    162: }
                    163: 
                    164: /*
                    165:  * Get terminal capabilities via termcap.
                    166:  */
                    167:        public void
                    168: get_term()
                    169: {
                    170:        char termbuf[1024];
                    171:        char *sp;
                    172:        static char sbuf[150];
                    173: 
                    174:        char *getenv();
                    175: 
                    176:        /*
                    177:         * Find out what kind of terminal this is.
                    178:         */
                    179:        if (tgetent(termbuf, getenv("TERM")) <= 0)
                    180:                dumb = 1;
                    181: 
                    182:        /*
                    183:         * Get size of the screen.
                    184:         */
                    185:        if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc"))
                    186:        {
                    187:                /* Oh no, this is a hardcopy terminal. */
                    188:                hard = 1;
                    189:                sc_height = 24;
                    190:        }
                    191:        if (dumb || (sc_width = tgetnum("co")) < 0)
                    192:                sc_width = 80;
                    193: 
                    194:        auto_wrap = tgetflag("am");
                    195:        ignaw = tgetflag("xn");
                    196: 
                    197:        /*
                    198:         * Assumes termcap variable "sg" is the printing width of
                    199:         * the standout sequence, the end standout sequence,
                    200:         * the underline sequence, and the end underline sequence.
                    201:         */
                    202:        if ((ul_width = tgetnum("sg")) < 0)
                    203:                ul_width = 0;
                    204:        so_width = se_width = ue_width = ul_width;
                    205: 
                    206:        /*
                    207:         * Get various string-valued capabilities.
                    208:         */
                    209:        sp = sbuf;
                    210: 
                    211:        sc_pad = (dumb) ? NULL : tgetstr("pc", &sp);
                    212:        if (sc_pad != NULL)
                    213:                PC = *sc_pad;
                    214: 
                    215:        sc_init = (dumb) ? NULL : tgetstr("ti", &sp);
                    216:        if (sc_init == NULL)
                    217:                sc_init = "";
                    218: 
                    219:        sc_deinit= (dumb) ? NULL : tgetstr("te", &sp);
                    220:        if (sc_deinit == NULL)
                    221:                sc_deinit = "";
                    222: 
                    223:        sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp);
                    224:        if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0')
                    225:        {
                    226:                cannot("clear to end of line");
                    227:                sc_eol_clear = "";
                    228:        }
                    229: 
                    230:        sc_clear = (dumb) ? NULL : tgetstr("cl", &sp);
                    231:        if (hard || sc_clear == NULL || *sc_clear == '\0')
                    232:        {
                    233:                cannot("clear screen");
                    234:                sc_clear = "\n\n";
                    235:        }
                    236: 
                    237:        sc_move = (dumb) ? NULL : tgetstr("cm", &sp);
                    238:        if (hard || sc_move == NULL || *sc_move == '\0')
                    239:        {
                    240:                /*
                    241:                 * This is not an error here, because we don't 
                    242:                 * always need sc_move.
                    243:                 * We need it only if we don't have home or lower-left.
                    244:                 */
                    245:                sc_move = "";
                    246:        }
                    247: 
                    248:        sc_s_in = (dumb) ? NULL : tgetstr("so", &sp);
                    249:        if (hard || sc_s_in == NULL)
                    250:                sc_s_in = "";
                    251: 
                    252:        sc_s_out = (dumb) ? NULL : tgetstr("se", &sp);
                    253:        if (hard || sc_s_out == NULL)
                    254:                sc_s_out = "";
                    255: 
                    256:        sc_u_in = (dumb) ? NULL : tgetstr("us", &sp);
                    257:        if (hard || sc_u_in == NULL)
                    258:                sc_u_in = sc_s_in;
                    259: 
                    260:        sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp);
                    261:        if (hard || sc_u_out == NULL)
                    262:                sc_u_out = sc_s_out;
                    263: 
                    264:        sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp);
                    265:        if (hard || sc_visual_bell == NULL)
                    266:                sc_visual_bell = "";
                    267: 
                    268:        sc_home = (dumb) ? NULL : tgetstr("ho", &sp);
                    269:        if (hard || sc_home == NULL || *sc_home == '\0')
                    270:        {
                    271:                if (*sc_move == '\0')
                    272:                {
                    273:                        cannot("home cursor");
                    274:                        /*
                    275:                         * This last resort for sc_home is supposed to
                    276:                         * be an up-arrow suggesting moving to the 
                    277:                         * top of the "virtual screen". (The one in
                    278:                         * your imagination as you try to use this on
                    279:                         * a hard copy terminal.)
                    280:                         */
                    281:                        sc_home = "|\b^";               
                    282:                } else
                    283:                {
                    284:                        /* 
                    285:                         * No "home" string,
                    286:                         * but we can use "move(0,0)".
                    287:                         */
                    288:                        strcpy(sp, tgoto(sc_move, 0, 0));
                    289:                        sc_home = sp;
                    290:                        sp += strlen(sp) + 1;
                    291:                }
                    292:        }
                    293: 
                    294:        sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp);
                    295:        if (hard || sc_lower_left == NULL || *sc_lower_left == '\0')
                    296:        {
                    297:                if (*sc_move == '\0')
                    298:                {
                    299:                        cannot("move cursor to lower left of screen");
                    300:                        sc_lower_left = "\r";
                    301:                } else
                    302:                {
                    303:                        /*
                    304:                         * No "lower-left" string, 
                    305:                         * but we can use "move(0,last-line)".
                    306:                         */
                    307:                        strcpy(sp, tgoto(sc_move, 0, sc_height-1));
                    308:                        sc_lower_left = sp;
                    309:                        sp += strlen(sp) + 1;
                    310:                }
                    311:        }
                    312: 
                    313:        /*
                    314:         * To add a line at top of screen and scroll the display down,
                    315:         * we use "al" (add line) or "sr" (scroll reverse).
                    316:         */
                    317:        if (dumb)
                    318:                sc_addline = NULL;
                    319:        else if ((sc_addline = tgetstr("al", &sp)) == NULL || 
                    320:                 *sc_addline == '\0')
                    321:                sc_addline = tgetstr("sr", &sp);
                    322: 
                    323:        if (hard || sc_addline == NULL || *sc_addline == '\0')
                    324:        {
                    325:                cannot("scroll backwards");
                    326:                sc_addline = "";
                    327:                /* Force repaint on any backward movement */
                    328:                back_scroll = 0;
                    329:        }
                    330: 
                    331:        if (dumb || tgetflag("bs"))
                    332:                sc_backspace = "\b";
                    333:        else
                    334:        {
                    335:                sc_backspace = tgetstr("bc", &sp);
                    336:                if (sc_backspace == NULL || *sc_backspace == '\0')
                    337:                        sc_backspace = "\b";
                    338:        }
                    339: 
                    340:        if (couldnt)
                    341:                /* Give him time to read all the "cannot" messages. */
                    342:                error("");
                    343: }
                    344: 
                    345: 
                    346: /*
                    347:  * Below are the functions which perform all the 
                    348:  * terminal-specific screen manipulation.
                    349:  */
                    350: 
                    351: 
                    352: /*
                    353:  * Initialize terminal
                    354:  */
                    355:        public void
                    356: init()
                    357: {
                    358:        tputs(sc_init, sc_height, putc);
                    359: }
                    360: 
                    361: /*
                    362:  * Deinitialize terminal
                    363:  */
                    364:        public void
                    365: deinit()
                    366: {
                    367:        tputs(sc_deinit, sc_height, putc);
                    368: }
                    369: 
                    370: /*
                    371:  * Home cursor (move to upper left corner of screen).
                    372:  */
                    373:        public void
                    374: home()
                    375: {
                    376:        tputs(sc_home, 1, putc);
                    377: }
                    378: 
                    379: /*
                    380:  * Add a blank line (called with cursor at home).
                    381:  * Should scroll the display down.
                    382:  */
                    383:        public void
                    384: add_line()
                    385: {
                    386:        tputs(sc_addline, sc_height, putc);
                    387: }
                    388: 
                    389: /*
                    390:  * Move cursor to lower left corner of screen.
                    391:  */
                    392:        public void
                    393: lower_left()
                    394: {
                    395:        tputs(sc_lower_left, 1, putc);
                    396: }
                    397: 
                    398: /*
                    399:  * Ring the terminal bell.
                    400:  */
                    401:        public void
                    402: bell()
                    403: {
                    404:        if (quiet == VERY_QUIET)
                    405:                vbell();
                    406:        else
                    407:                putc('\7');
                    408: }
                    409: 
                    410: /*
                    411:  * Output the "visual bell", if there is one.
                    412:  */
                    413:        public void
                    414: vbell()
                    415: {
                    416:        if (*sc_visual_bell == '\0')
                    417:                return;
                    418:        tputs(sc_visual_bell, sc_height, putc);
                    419: }
                    420: 
                    421: /*
                    422:  * Clear the screen.
                    423:  */
                    424:        public void
                    425: clear()
                    426: {
                    427:        tputs(sc_clear, sc_height, putc);
                    428: }
                    429: 
                    430: /*
                    431:  * Clear from the cursor to the end of the cursor's line.
                    432:  * {{ This must not move the cursor. }}
                    433:  */
                    434:        public void
                    435: clear_eol()
                    436: {
                    437:        tputs(sc_eol_clear, 1, putc);
                    438: }
                    439: 
                    440: /*
                    441:  * Begin "standout" (bold, underline, or whatever).
                    442:  */
                    443:        public void
                    444: so_enter()
                    445: {
                    446:        tputs(sc_s_in, 1, putc);
                    447: }
                    448: 
                    449: /*
                    450:  * End "standout".
                    451:  */
                    452:        public void
                    453: so_exit()
                    454: {
                    455:        tputs(sc_s_out, 1, putc);
                    456: }
                    457: 
                    458: /*
                    459:  * Begin "underline" (hopefully real underlining, 
                    460:  * otherwise whatever the terminal provides).
                    461:  */
                    462:        public void
                    463: ul_enter()
                    464: {
                    465:        tputs(sc_u_in, 1, putc);
                    466: }
                    467: 
                    468: /*
                    469:  * End "underline".
                    470:  */
                    471:        public void
                    472: ul_exit()
                    473: {
                    474:        tputs(sc_u_out, 1, putc);
                    475: }
                    476: 
                    477: /*
                    478:  * Erase the character to the left of the cursor 
                    479:  * and move the cursor left.
                    480:  */
                    481:        public void
                    482: backspace()
                    483: {
                    484:        /* 
                    485:         * Try to erase the previous character by overstriking with a space.
                    486:         */
                    487:        tputs(sc_backspace, 1, putc);
                    488:        putc(' ');
                    489:        tputs(sc_backspace, 1, putc);
                    490: }
                    491: 
                    492: /*
                    493:  * Output a plain backspace, without erasing the previous char.
                    494:  */
                    495:        public void
                    496: putbs()
                    497: {
                    498:        tputs(sc_backspace, 1, putc);
                    499: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.