[BACK]Return to tty.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/tty.c, Revision 1.2

1.1       deraadt     1: /*
1.2     ! millert     2:  * Terminfo display driver
1.1       deraadt     3:  *
1.2     ! millert     4:  * Terminfo is a terminal information database and routines to describe
        !             5:  * terminals on most modern UNIX systems.  Many other systems have adopted
1.1       deraadt     6:  * this as a reasonable way to allow for widly varying and ever changing
                      7:  * varieties of terminal types.         This should be used where practical.
                      8:  */
                      9: /* Known problems:
                     10:  *     If you have a terminal with no clear to end of screen and
                     11:  *     memory of lines below the ones visible on the screen, display
                     12:  *     will be wrong in some cases.  I doubt that any such terminal
                     13:  *     was ever made, but I thought everyone with delete line would
                     14:  *     have clear to end of screen too...
                     15:  *
                     16:  *     Code for terminals without clear to end of screen and/or clear
                     17:  *     to end of line has not been extensivly tested.
                     18:  *
                     19:  *     Cost calculations are very rough.  Costs of insert/delete line
                     20:  *     may be far from the truth.  This is accentuated by display.c
                     21:  *     not knowing about multi-line insert/delete.
                     22:  *
                     23:  *     Using scrolling region vs insert/delete line should probably
                     24:  *     be based on cost rather than the assuption that scrolling
                     25:  *     region operations look better.
                     26:  */
                     27: #include       "def.h"
                     28:
1.2     ! millert    29: #include       <curses.h>
        !            30: #include       <term.h>
1.1       deraadt    31:
                     32: extern int     ttrow;
                     33: extern int     ttcol;
                     34: extern int     tttop;
                     35: extern int     ttbot;
                     36: extern int     tthue;
                     37:
1.2     ! millert    38: extern int     ttputc();
        !            39:
1.1       deraadt    40: int    tceeol;                 /* Costs are set later */
                     41: int    tcinsl;
                     42: int    tcdell;
                     43:
                     44: static int     insdel;         /* Do we have both insert & delete line? */
1.2     ! millert    45: static char *  scroll_fwd;     /* How to scroll forward. */
1.1       deraadt    46:
                     47: #ifdef NO_RESIZE
                     48: static setttysize();
                     49: #endif
                     50:
                     51: /*
                     52:  * Initialize the terminal when the editor
                     53:  * gets started up.
                     54:  */
                     55: ttinit() {
                     56:        char *tv_stype;
1.2     ! millert    57:        char *t, *p;
1.1       deraadt    58: #ifndef gettermtype            /* (avoid declaration if #define) */
                     59:        char *gettermtype();    /* system dependent function to determin terminal type */
                     60: #endif
                     61:
1.2     ! millert    62:        if ((tv_stype = gettermtype()) == NULL)
1.1       deraadt    63:                panic("Could not determine terminal type");
1.2     ! millert    64:        if (setupterm(tv_stype, 1, NULL) == ERR) {
        !            65:                (void) asprintf(&p, "Unknown terminal type: %s", tv_stype);
        !            66:                panic(p);
1.1       deraadt    67:        }
                     68:
1.2     ! millert    69:        scroll_fwd = scroll_forward;
        !            70:        if (!scroll_fwd || !*scroll_fwd) {
        !            71:                /* this is what GNU Emacs does */
        !            72:                scroll_fwd = parm_down_cursor;
        !            73:                if (!scroll_fwd || !*scroll_fwd)
        !            74:                        scroll_fwd = "\n";
1.1       deraadt    75:        }
                     76:
1.2     ! millert    77:        if (!cursor_address || !cursor_up)
        !            78:                panic("This terminal is to stupid to run mg");
1.1       deraadt    79:        ttresize();                     /* set nrow & ncol      */
                     80:
1.2     ! millert    81:        if (!clr_eol)
        !            82:                tceeol = ncol;
        !            83:        else
        !            84:                tceeol = charcost(clr_eol);
1.1       deraadt    85:
                     86:        /* Estimate cost of inserting a line */
1.2     ! millert    87:        if (change_scroll_region && scroll_reverse)
        !            88:                tcinsl = charcost(change_scroll_region)*2 +
        !            89:                                  charcost(scroll_reverse);
        !            90:        else if (parm_insert_line)
        !            91:                tcinsl = charcost(parm_insert_line);
        !            92:        else if (insert_line)
        !            93:                tcinsl = charcost(insert_line);
        !            94:        else
        !            95:                tcinsl = NROW * NCOL;   /* make this cost high enough */
1.1       deraadt    96:
                     97:        /* Estimate cost of deleting a line */
1.2     ! millert    98:        if (change_scroll_region)
        !            99:                tcdell = charcost(change_scroll_region)*2 +
        !           100:                                  charcost(scroll_fwd);
        !           101:        else if (parm_delete_line)
        !           102:                tcdell = charcost(parm_delete_line);
        !           103:        else if (delete_line)
        !           104:                tcdell = charcost(delete_line);
        !           105:        else
        !           106:                tcdell = NROW * NCOL;   /* make this cost high enough */
1.1       deraadt   107:
                    108:        /* Flag to indicate that we can both insert and delete lines */
1.2     ! millert   109:        insdel = (insert_line || parm_insert_line) && (delete_line || parm_delete_line);
1.1       deraadt   110:
1.2     ! millert   111:        if (enter_ca_mode)
        !           112:                putpad(enter_ca_mode, 1);       /* init the term */
1.1       deraadt   113: }
                    114:
                    115: /*
                    116:  * Clean up the terminal, in anticipation of
                    117:  * a return to the command interpreter. This is a no-op
                    118:  * on the ANSI display. On the SCALD display, it sets the
                    119:  * window back to half screen scrolling. Perhaps it should
                    120:  * query the display for the increment, and put it
                    121:  * back to what it was.
                    122:  */
                    123: tttidy() {
1.2     ! millert   124:
        !           125:        /* set the term back to normal mode */
        !           126:        if (exit_ca_mode)
        !           127:                putpad(exit_ca_mode, 1);
1.1       deraadt   128: #ifdef XKEYS
                    129:        ttykeymaptidy();
                    130: #endif
                    131: }
                    132:
                    133: /*
                    134:  * Move the cursor to the specified
                    135:  * origin 0 row and column position. Try to
                    136:  * optimize out extra moves; redisplay may
                    137:  * have left the cursor in the right
                    138:  * location last time!
                    139:  */
                    140: ttmove(row, col) {
                    141:     char       *tgoto();
                    142:
1.2     ! millert   143:     if (ttrow != row || ttcol !=col) {
        !           144:            putpad(tgoto(cursor_address, col, row), 1);
        !           145:            ttrow = row;
        !           146:            ttcol = col;
1.1       deraadt   147:     }
                    148: }
                    149:
                    150: /*
                    151:  * Erase to end of line.
                    152:  */
                    153: tteeol() {
1.2     ! millert   154:
        !           155:        if (clr_eol)
        !           156:                putpad(clr_eol, 1);
        !           157:        else {
        !           158:                int i = ncol - ttcol;
        !           159:                while (i--)
        !           160:                        ttputc(' ');
        !           161:                ttrow = ttcol = HUGE;
        !           162:        }
1.1       deraadt   163: }
                    164:
                    165: /*
                    166:  * Erase to end of page.
                    167:  */
                    168: tteeop() {
1.2     ! millert   169:        int line;
        !           170:
        !           171:        if (clr_eos)
        !           172:                putpad(clr_eos, nrow - ttrow);
        !           173:        else {
        !           174:                putpad(clr_eol, 1);
        !           175:                if (insdel)
        !           176:                        ttdell(ttrow + 1, lines, lines - ttrow - 1);
        !           177:                else {          /* do it by hand */
        !           178:                        for (line = ttrow + 1; line <= lines; ++line) {
        !           179:                                ttmove(line, 0);
        !           180:                                tteeol();
        !           181:                        }
        !           182:                }
        !           183:                ttrow = ttcol = HUGE;
1.1       deraadt   184:        }
                    185: }
                    186:
                    187: /*
                    188:  * Make a noise.
                    189:  */
                    190: ttbeep() {
1.2     ! millert   191:        putpad(bell, 1);
1.1       deraadt   192:        ttflush();
                    193: }
                    194:
                    195: /*
                    196:  * Insert nchunk blank line(s) onto the
                    197:  * screen, scrolling the last line on the
                    198:  * screen off the bottom.  Use the scrolling
                    199:  * region if possible for a smoother display.
                    200:  * If no scrolling region, use a set
                    201:  * of insert and delete line sequences
                    202:  */
                    203: ttinsl(row, bot, nchunk) {
1.2     ! millert   204:        int     i, nl;
1.1       deraadt   205:
1.2     ! millert   206:        if (row == bot) {               /* Case of one line insert is   */
        !           207:                ttmove(row, 0);         /*      special                 */
        !           208:                tteeol();
        !           209:                return;
        !           210:        }
        !           211:        if (change_scroll_region && scroll_reverse) {
        !           212:                /* Use scroll region and back index     */
        !           213:                nl = bot - row;
        !           214:                ttwindow(row,bot);
        !           215:                ttmove(row, 0);
        !           216:                while (nchunk--)
        !           217:                        putpad(scroll_reverse, nl);
        !           218:                ttnowindow();
        !           219:                return;
        !           220:        } else if (insdel) {
        !           221:                ttmove(1+bot-nchunk, 0);
        !           222:                nl = nrow - ttrow;
        !           223:                if (parm_delete_line)
        !           224:                        putpad(tgoto(parm_delete_line, 0, nchunk), nl);
        !           225:                else
        !           226:                        /* For all lines in the chunk   */
        !           227:                        for (i=0; i<nchunk; i++)
        !           228:                                putpad(delete_line, nl);
        !           229:                ttmove(row, 0);
        !           230:                nl = nrow - ttrow;      /* ttmove() changes ttrow */
        !           231:                if (parm_insert_line)
        !           232:                        putpad(tgoto(parm_insert_line, 0, nchunk), nl);
        !           233:                else
        !           234:                        /* For all lines in the chunk */
        !           235:                        for (i=0; i<nchunk; i++)
        !           236:                                putpad(insert_line, nl);
        !           237:                ttrow = HUGE;
        !           238:                ttcol = HUGE;
        !           239:        } else
        !           240:                panic("ttinsl: Can't insert/delete line");
1.1       deraadt   241: }
                    242:
                    243: /*
                    244:  * Delete nchunk line(s) from "row", replacing the
                    245:  * bottom line on the screen with a blank line.
                    246:  * Unless we're using the scrolling region, this is
                    247:  * done with a crafty sequences of insert and delete
                    248:  * lines.  The presence of the echo area makes a
                    249:  * boundry condition go away.
                    250:  */
                    251: ttdell(row, bot, nchunk)
                    252: {
1.2     ! millert   253:        int     i, nl;
1.1       deraadt   254:
1.2     ! millert   255:        if (row == bot) {               /* One line special case        */
        !           256:                ttmove(row, 0);
        !           257:                tteeol();
        !           258:                return;
        !           259:        }
        !           260:        if (change_scroll_region) {     /* scrolling region             */
        !           261:                nl = bot - row;
        !           262:                ttwindow(row, bot);
        !           263:                ttmove(bot, 0);
        !           264:                while (nchunk--)
        !           265:                        putpad(scroll_fwd, nl);
        !           266:                ttnowindow();
        !           267:        }
        !           268:        else if (insdel) {
        !           269:                ttmove(row, 0);         /* Else use insert/delete line  */
        !           270:                nl = nrow - ttrow;
        !           271:                if (parm_delete_line)
        !           272:                        putpad(tgoto(parm_delete_line, 0, nchunk), nl);
        !           273:                else
        !           274:                        /* For all lines in the chunk   */
        !           275:                        for (i=0; i<nchunk; i++)
        !           276:                                putpad(delete_line, nl);
        !           277:                ttmove(1+bot-nchunk,0);
        !           278:                nl = nrow - ttrow;      /* ttmove() changes ttrow */
        !           279:                if (parm_insert_line)
        !           280:                        putpad(tgoto(parm_insert_line, 0, nchunk), nl);
        !           281:                else
        !           282:                        /* For all lines in the chunk */
        !           283:                        for (i=0; i<nchunk; i++)
        !           284:                                putpad(insert_line, nl);
        !           285:                ttrow = HUGE;
        !           286:                ttcol = HUGE;
        !           287:        } else
        !           288:                panic("ttdell: Can't insert/delete line");
1.1       deraadt   289: }
                    290:
                    291: /*
                    292:  * This routine sets the scrolling window
                    293:  * on the display to go from line "top" to line
                    294:  * "bot" (origin 0, inclusive). The caller checks
                    295:  * for the pathalogical 1 line scroll window that
                    296:  * doesn't work right, and avoids it. The "ttrow"
                    297:  * and "ttcol" variables are set to a crazy value
                    298:  * to ensure that the next call to "ttmove" does
                    299:  * not turn into a no-op (the window adjustment
                    300:  * moves the cursor).
                    301:  *
                    302:  */
                    303: ttwindow(top, bot)
                    304: {
1.2     ! millert   305:        if (change_scroll_region && (tttop != top || ttbot != bot)) {
        !           306:                putpad(tgoto(change_scroll_region, bot, top), nrow - ttrow);
1.1       deraadt   307:                ttrow = HUGE;                   /* Unknown.             */
                    308:                ttcol = HUGE;
                    309:                tttop = top;                    /* Remember region.     */
                    310:                ttbot = bot;
                    311:        }
                    312: }
                    313:
                    314: /*
                    315:  * Switch to full screen scroll. This is
                    316:  * used by "spawn.c" just before is suspends the
                    317:  * editor, and by "display.c" when it is getting ready
                    318:  * to exit.  This function gets to full screen scroll
                    319:  * by telling the terminal to set a scrolling regin
1.2     ! millert   320:  * that is lines or nrow rows high, whichever is larger.
1.1       deraadt   321:  * This behavior seems to work right on systems
                    322:  * where you can set your terminal size.
                    323:  */
                    324: ttnowindow()
                    325: {
1.2     ! millert   326:        if (change_scroll_region) {
        !           327:                putpad(tgoto(change_scroll_region,
        !           328:                    (nrow > lines ? nrow : lines) - 1, 0), nrow - ttrow);
        !           329:                ttrow = HUGE;                   /* Unknown.             */
        !           330:                ttcol = HUGE;
        !           331:                tttop = HUGE;                   /* No scroll region.    */
        !           332:                ttbot = HUGE;
        !           333:        }
1.1       deraadt   334: }
                    335:
                    336: /*
                    337:  * Set the current writing color to the
                    338:  * specified color. Watch for color changes that are
                    339:  * not going to do anything (the color is already right)
                    340:  * and don't send anything to the display.
                    341:  * The rainbow version does this in putline.s on a
                    342:  * line by line basis, so don't bother sending
                    343:  * out the color shift.
                    344:  */
1.2     ! millert   345: ttcolor(color)
        !           346:        int color;
        !           347: {
        !           348:
        !           349:        if (color != tthue) {
        !           350:            if (color == CTEXT)                 /* Normal video.        */
        !           351:                    putpad(exit_standout_mode, 1);
        !           352:            else if (color == CMODE)            /* Reverse video.       */
        !           353:                    putpad(enter_standout_mode, 1);
        !           354:            tthue = color;                      /* Save the color.      */
1.1       deraadt   355:        }
                    356: }
                    357:
                    358: /*
                    359:  * This routine is called by the
                    360:  * "refresh the screen" command to try and resize
                    361:  * the display. The new size, which must be deadstopped
                    362:  * to not exceed the NROW and NCOL limits, it stored
                    363:  * back into "nrow" and "ncol". Display can always deal
                    364:  * with a screen NROW by NCOL. Look in "window.c" to
                    365:  * see how the caller deals with a change.
                    366:  */
                    367: ttresize() {
1.2     ! millert   368:
1.1       deraadt   369:        setttysize();                   /* found in "ttyio.c",  */
                    370:                                        /* ask OS for tty size  */
                    371:        if (nrow < 1)                   /* Check limits.        */
                    372:                nrow = 1;
                    373:        else if (nrow > NROW)
                    374:                nrow = NROW;
                    375:        if (ncol < 1)
                    376:                ncol = 1;
                    377:        else if (ncol > NCOL)
                    378:                ncol = NCOL;
                    379: }
                    380:
                    381: #ifdef NO_RESIZE
                    382: static setttysize() {
                    383:        nrow = tgetnum("li");
                    384:        ncol = tgetnum("co");
                    385: }
                    386: #endif
                    387:
                    388: static int cci;
                    389:
                    390: /*ARGSUSED*/
                    391: static int             /* fake char output for charcost() */
                    392: fakec(c)
                    393: char c;
                    394: {
                    395:        cci++;
                    396: }
                    397:
                    398: /* calculate the cost of doing string s */
                    399: charcost (s) char *s; {
1.2     ! millert   400:        cci = 0;
1.1       deraadt   401:
1.2     ! millert   402:        tputs(s, nrow, fakec);
        !           403:        return (cci);
1.1       deraadt   404: }