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

1.40    ! guenther    1: /*     $OpenBSD: tty.c,v 1.39 2021/03/20 09:00:49 lum Exp $    */
1.22      kjell       2:
                      3: /* This file is in the public domain. */
1.7       niklas      4:
1.1       deraadt     5: /*
1.2       millert     6:  * Terminfo display driver
1.1       deraadt     7:  *
1.2       millert     8:  * Terminfo is a terminal information database and routines to describe
                      9:  * terminals on most modern UNIX systems.  Many other systems have adopted
1.21      db         10:  * this as a reasonable way to allow for widely varying and ever changing
1.1       deraadt    11:  * varieties of terminal types.         This should be used where practical.
                     12:  */
1.5       millert    13: /*
                     14:  * Known problems: If you have a terminal with no clear to end of screen and
                     15:  * memory of lines below the ones visible on the screen, display will be
                     16:  * wrong in some cases.  I doubt that any such terminal was ever made, but I
                     17:  * thought everyone with delete line would have clear to end of screen too...
1.1       deraadt    18:  *
1.5       millert    19:  * Code for terminals without clear to end of screen and/or clear to end of line
1.21      db         20:  * has not been extensively tested.
1.1       deraadt    21:  *
1.5       millert    22:  * Cost calculations are very rough.  Costs of insert/delete line may be far
                     23:  * from the truth.  This is accentuated by display.c not knowing about
                     24:  * multi-line insert/delete.
1.1       deraadt    25:  *
1.5       millert    26:  * Using scrolling region vs insert/delete line should probably be based on cost
1.21      db         27:  * rather than the assumption that scrolling region operations look better.
1.1       deraadt    28:  */
                     29:
1.34      bcallah    30: #include <sys/ioctl.h>
                     31: #include <sys/queue.h>
1.10      art        32: #include <sys/types.h>
                     33: #include <sys/time.h>
1.34      bcallah    34: #include <signal.h>
                     35: #include <stdio.h>
                     36: #include <term.h>
1.39      lum        37: #include <unistd.h>
1.24      kjell      38:
1.34      bcallah    39: #include "def.h"
1.1       deraadt    40:
1.31      guenther   41: static int      charcost(const char *);
1.1       deraadt    42:
1.6       millert    43: static int      cci;
                     44: static int      insdel;        /* Do we have both insert & delete line? */
1.38      lum        45: static char    *scroll_fwd;    /* How to scroll forward. */
1.1       deraadt    46:
1.21      db         47: static void     winchhandler(int);
1.37      florian    48:
                     49: volatile sig_atomic_t   winch_flag;
                     50: int                     tceeol;
                     51: int                     tcinsl;
                     52: int                     tcdell;
1.10      art        53:
                     54: static void
                     55: winchhandler(int sig)
                     56: {
1.15      deraadt    57:        winch_flag = 1;
1.10      art        58: }
                     59:
1.1       deraadt    60: /*
                     61:  * Initialize the terminal when the editor
                     62:  * gets started up.
                     63:  */
1.8       art        64: void
1.18      vincent    65: ttinit(void)
1.5       millert    66: {
1.39      lum        67:        char *tty;
1.29      tobias     68:        int errret;
1.6       millert    69:
1.39      lum        70:        if (batch == 1)
                     71:                tty = "pty";
                     72:        else
                     73:                tty = NULL;
                     74:
                     75:        if (setupterm(tty, STDOUT_FILENO, &errret))
1.29      tobias     76:                panic("Terminal setup failed");
1.6       millert    77:
1.10      art        78:        signal(SIGWINCH, winchhandler);
1.26      otto       79:        signal(SIGCONT, winchhandler);
1.15      deraadt    80:        siginterrupt(SIGWINCH, 1);
                     81:
1.2       millert    82:        scroll_fwd = scroll_forward;
1.6       millert    83:        if (scroll_fwd == NULL || *scroll_fwd == '\0') {
1.2       millert    84:                /* this is what GNU Emacs does */
                     85:                scroll_fwd = parm_down_cursor;
1.6       millert    86:                if (scroll_fwd == NULL || *scroll_fwd == '\0')
1.38      lum        87:                        scroll_fwd = curbp->b_nlchr;
1.1       deraadt    88:        }
1.6       millert    89:
                     90:        if (cursor_address == NULL || cursor_up == NULL)
                     91:                panic("This terminal is too stupid to run mg");
                     92:
                     93:        /* set nrow & ncol */
                     94:        ttresize();
1.1       deraadt    95:
1.2       millert    96:        if (!clr_eol)
                     97:                tceeol = ncol;
                     98:        else
                     99:                tceeol = charcost(clr_eol);
1.1       deraadt   100:
                    101:        /* Estimate cost of inserting a line */
1.2       millert   102:        if (change_scroll_region && scroll_reverse)
1.5       millert   103:                tcinsl = charcost(change_scroll_region) * 2 +
1.6       millert   104:                    charcost(scroll_reverse);
1.2       millert   105:        else if (parm_insert_line)
                    106:                tcinsl = charcost(parm_insert_line);
                    107:        else if (insert_line)
                    108:                tcinsl = charcost(insert_line);
                    109:        else
1.6       millert   110:                /* make this cost high enough */
1.11      art       111:                tcinsl = nrow * ncol;
1.1       deraadt   112:
                    113:        /* Estimate cost of deleting a line */
1.2       millert   114:        if (change_scroll_region)
1.5       millert   115:                tcdell = charcost(change_scroll_region) * 2 +
1.6       millert   116:                    charcost(scroll_fwd);
1.2       millert   117:        else if (parm_delete_line)
                    118:                tcdell = charcost(parm_delete_line);
                    119:        else if (delete_line)
                    120:                tcdell = charcost(delete_line);
1.5       millert   121:        else
1.6       millert   122:                /* make this cost high enough */
1.11      art       123:                tcdell = nrow * ncol;
1.1       deraadt   124:
                    125:        /* Flag to indicate that we can both insert and delete lines */
1.9       mickey    126:        insdel = (insert_line || parm_insert_line) &&
1.6       millert   127:            (delete_line || parm_delete_line);
1.1       deraadt   128:
1.2       millert   129:        if (enter_ca_mode)
1.6       millert   130:                /* enter application mode */
                    131:                putpad(enter_ca_mode, 1);
1.3       millert   132:
1.10      art       133:        ttresize();
1.1       deraadt   134: }
                    135:
                    136: /*
1.4       millert   137:  * Re-initialize the terminal when the editor is resumed.
                    138:  * The keypad_xmit doesn't really belong here but...
                    139:  */
1.8       art       140: void
1.18      vincent   141: ttreinit(void)
1.5       millert   142: {
1.30      kjell     143:        /* check if file was modified while we were gone */
                    144:        if (fchecktime(curbp) != TRUE) {
                    145:                curbp->b_flag |= BFDIRTY;
                    146:        }
                    147:
1.21      db        148:        if (enter_ca_mode)
1.6       millert   149:                /* enter application mode */
                    150:                putpad(enter_ca_mode, 1);
1.21      db        151:
                    152:        if (keypad_xmit)
1.6       millert   153:                /* turn on keypad */
                    154:                putpad(keypad_xmit, 1);
1.4       millert   155:
1.10      art       156:        ttresize();
1.4       millert   157: }
                    158:
                    159: /*
1.9       mickey    160:  * Clean up the terminal, in anticipation of a return to the command
                    161:  * interpreter. This is a no-op on the ANSI display. On the SCALD display,
1.6       millert   162:  * it sets the window back to half screen scrolling. Perhaps it should
                    163:  * query the display for the increment, and put it back to what it was.
1.1       deraadt   164:  */
1.8       art       165: void
1.18      vincent   166: tttidy(void)
1.5       millert   167: {
                    168:        ttykeymaptidy();
1.6       millert   169:
1.2       millert   170:        /* set the term back to normal mode */
                    171:        if (exit_ca_mode)
                    172:                putpad(exit_ca_mode, 1);
1.1       deraadt   173: }
                    174:
                    175: /*
1.6       millert   176:  * Move the cursor to the specified origin 0 row and column position. Try to
                    177:  * optimize out extra moves; redisplay may have left the cursor in the right
1.1       deraadt   178:  * location last time!
                    179:  */
1.8       art       180: void
1.18      vincent   181: ttmove(int row, int col)
1.5       millert   182: {
                    183:        if (ttrow != row || ttcol != col) {
                    184:                putpad(tgoto(cursor_address, col, row), 1);
                    185:                ttrow = row;
                    186:                ttcol = col;
                    187:        }
1.1       deraadt   188: }
                    189:
                    190: /*
                    191:  * Erase to end of line.
                    192:  */
1.8       art       193: void
1.18      vincent   194: tteeol(void)
1.5       millert   195: {
1.6       millert   196:        int     i;
1.2       millert   197:
                    198:        if (clr_eol)
                    199:                putpad(clr_eol, 1);
                    200:        else {
1.6       millert   201:                i = ncol - ttcol;
1.2       millert   202:                while (i--)
                    203:                        ttputc(' ');
                    204:                ttrow = ttcol = HUGE;
                    205:        }
1.1       deraadt   206: }
                    207:
                    208: /*
                    209:  * Erase to end of page.
                    210:  */
1.8       art       211: void
1.18      vincent   212: tteeop(void)
1.5       millert   213: {
1.6       millert   214:        int     line;
1.2       millert   215:
                    216:        if (clr_eos)
                    217:                putpad(clr_eos, nrow - ttrow);
                    218:        else {
                    219:                putpad(clr_eol, 1);
                    220:                if (insdel)
                    221:                        ttdell(ttrow + 1, lines, lines - ttrow - 1);
1.6       millert   222:                else {
                    223:                        /* do it by hand */
1.2       millert   224:                        for (line = ttrow + 1; line <= lines; ++line) {
                    225:                                ttmove(line, 0);
                    226:                                tteeol();
                    227:                        }
                    228:                }
                    229:                ttrow = ttcol = HUGE;
1.1       deraadt   230:        }
                    231: }
                    232:
                    233: /*
                    234:  * Make a noise.
                    235:  */
1.8       art       236: void
1.20      deraadt   237: ttbeep(void)
1.5       millert   238: {
1.2       millert   239:        putpad(bell, 1);
1.1       deraadt   240:        ttflush();
                    241: }
                    242:
                    243: /*
1.9       mickey    244:  * Insert nchunk blank line(s) onto the screen, scrolling the last line on
                    245:  * the screen off the bottom.  Use the scrolling region if possible for a
                    246:  * smoother display.  If there is no scrolling region, use a set of insert
1.6       millert   247:  * and delete line sequences.
1.1       deraadt   248:  */
1.8       art       249: void
1.18      vincent   250: ttinsl(int row, int bot, int nchunk)
1.5       millert   251: {
1.6       millert   252:        int     i, nl;
1.1       deraadt   253:
1.36      jasper    254:        /* One line special cases */
1.6       millert   255:        if (row == bot) {
                    256:                ttmove(row, 0);
1.2       millert   257:                tteeol();
                    258:                return;
                    259:        }
1.36      jasper    260:        /* Use scroll region and back index */
1.2       millert   261:        if (change_scroll_region && scroll_reverse) {
                    262:                nl = bot - row;
1.5       millert   263:                ttwindow(row, bot);
1.2       millert   264:                ttmove(row, 0);
                    265:                while (nchunk--)
                    266:                        putpad(scroll_reverse, nl);
                    267:                ttnowindow();
                    268:                return;
1.36      jasper    269:        /* else use insert/delete line */
1.2       millert   270:        } else if (insdel) {
1.5       millert   271:                ttmove(1 + bot - nchunk, 0);
1.2       millert   272:                nl = nrow - ttrow;
                    273:                if (parm_delete_line)
                    274:                        putpad(tgoto(parm_delete_line, 0, nchunk), nl);
                    275:                else
1.36      jasper    276:                        /* For all lines in the chunk */
1.5       millert   277:                        for (i = 0; i < nchunk; i++)
1.2       millert   278:                                putpad(delete_line, nl);
                    279:                ttmove(row, 0);
1.6       millert   280:
                    281:                /* ttmove() changes ttrow */
                    282:                nl = nrow - ttrow;
                    283:
1.2       millert   284:                if (parm_insert_line)
                    285:                        putpad(tgoto(parm_insert_line, 0, nchunk), nl);
                    286:                else
                    287:                        /* For all lines in the chunk */
1.5       millert   288:                        for (i = 0; i < nchunk; i++)
1.2       millert   289:                                putpad(insert_line, nl);
                    290:                ttrow = HUGE;
                    291:                ttcol = HUGE;
                    292:        } else
                    293:                panic("ttinsl: Can't insert/delete line");
1.1       deraadt   294: }
                    295:
                    296: /*
1.9       mickey    297:  * Delete nchunk line(s) from "row", replacing the bottom line on the
                    298:  * screen with a blank line.  Unless we're using the scrolling region,
                    299:  * this is done with crafty sequences of insert and delete lines.  The
1.21      db        300:  * presence of the echo area makes a boundary condition go away.
1.1       deraadt   301:  */
1.8       art       302: void
1.21      db        303: ttdell(int row, int bot, int nchunk)
1.1       deraadt   304: {
1.6       millert   305:        int     i, nl;
1.1       deraadt   306:
1.6       millert   307:        /* One line special cases */
                    308:        if (row == bot) {
1.2       millert   309:                ttmove(row, 0);
                    310:                tteeol();
                    311:                return;
                    312:        }
1.6       millert   313:        /* scrolling region */
                    314:        if (change_scroll_region) {
1.2       millert   315:                nl = bot - row;
                    316:                ttwindow(row, bot);
                    317:                ttmove(bot, 0);
                    318:                while (nchunk--)
                    319:                        putpad(scroll_fwd, nl);
                    320:                ttnowindow();
1.6       millert   321:        /* else use insert/delete line */
1.5       millert   322:        } else if (insdel) {
1.6       millert   323:                ttmove(row, 0);
1.2       millert   324:                nl = nrow - ttrow;
                    325:                if (parm_delete_line)
                    326:                        putpad(tgoto(parm_delete_line, 0, nchunk), nl);
                    327:                else
1.36      jasper    328:                        /* For all lines in the chunk */
1.5       millert   329:                        for (i = 0; i < nchunk; i++)
1.2       millert   330:                                putpad(delete_line, nl);
1.5       millert   331:                ttmove(1 + bot - nchunk, 0);
1.6       millert   332:
                    333:                /* ttmove() changes ttrow */
                    334:                nl = nrow - ttrow;
1.36      jasper    335:
1.2       millert   336:                if (parm_insert_line)
                    337:                        putpad(tgoto(parm_insert_line, 0, nchunk), nl);
                    338:                else
                    339:                        /* For all lines in the chunk */
1.5       millert   340:                        for (i = 0; i < nchunk; i++)
1.2       millert   341:                                putpad(insert_line, nl);
                    342:                ttrow = HUGE;
                    343:                ttcol = HUGE;
                    344:        } else
                    345:                panic("ttdell: Can't insert/delete line");
1.1       deraadt   346: }
                    347:
                    348: /*
1.9       mickey    349:  * This routine sets the scrolling window on the display to go from line
                    350:  * "top" to line "bot" (origin 0, inclusive).  The caller checks for the
                    351:  * pathological 1-line scroll window which doesn't work right and avoids
                    352:  * it.  The "ttrow" and "ttcol" variables are set to a crazy value to
                    353:  * ensure that the next call to "ttmove" does not turn into a no-op (the
1.6       millert   354:  * window adjustment moves the cursor).
1.1       deraadt   355:  */
1.8       art       356: void
1.21      db        357: ttwindow(int top, int bot)
1.1       deraadt   358: {
1.2       millert   359:        if (change_scroll_region && (tttop != top || ttbot != bot)) {
                    360:                putpad(tgoto(change_scroll_region, bot, top), nrow - ttrow);
1.5       millert   361:                ttrow = HUGE;   /* Unknown.              */
1.1       deraadt   362:                ttcol = HUGE;
1.5       millert   363:                tttop = top;    /* Remember region.      */
1.1       deraadt   364:                ttbot = bot;
                    365:        }
                    366: }
                    367:
                    368: /*
1.9       mickey    369:  * Switch to full screen scroll. This is used by "spawn.c" just before it
                    370:  * suspends the editor and by "display.c" when it is getting ready to
                    371:  * exit.  This function does a full screen scroll by telling the terminal
                    372:  * to set a scrolling region that is lines or nrow rows high, whichever is
                    373:  * larger.  This behavior seems to work right on systems where you can set
1.6       millert   374:  * your terminal size.
1.1       deraadt   375:  */
1.8       art       376: void
1.20      deraadt   377: ttnowindow(void)
1.1       deraadt   378: {
1.2       millert   379:        if (change_scroll_region) {
                    380:                putpad(tgoto(change_scroll_region,
1.13      deraadt   381:                    (nrow > lines ? nrow : lines) - 1, 0), nrow - ttrow);
1.5       millert   382:                ttrow = HUGE;   /* Unknown.              */
1.2       millert   383:                ttcol = HUGE;
1.5       millert   384:                tttop = HUGE;   /* No scroll region.     */
1.2       millert   385:                ttbot = HUGE;
                    386:        }
1.1       deraadt   387: }
                    388:
                    389: /*
1.9       mickey    390:  * Set the current writing color to the specified color. Watch for color
1.6       millert   391:  * changes that are not going to do anything (the color is already right)
1.9       mickey    392:  * and don't send anything to the display.  The rainbow version does this
                    393:  * in putline.s on a line by line basis, so don't bother sending out the
1.6       millert   394:  * color shift.
1.1       deraadt   395:  */
1.8       art       396: void
1.21      db        397: ttcolor(int color)
1.2       millert   398: {
                    399:        if (color != tthue) {
1.6       millert   400:                if (color == CTEXT)
                    401:                        /* normal video */
1.5       millert   402:                        putpad(exit_standout_mode, 1);
1.6       millert   403:                else if (color == CMODE)
                    404:                        /* reverse video */
1.5       millert   405:                        putpad(enter_standout_mode, 1);
1.6       millert   406:                /* save the color */
                    407:                tthue = color;
1.1       deraadt   408:        }
                    409: }
                    410:
                    411: /*
1.9       mickey    412:  * This routine is called by the "refresh the screen" command to try
1.11      art       413:  * to resize the display. Look in "window.c" to see how
1.6       millert   414:  * the caller deals with a change.
1.11      art       415:  *
                    416:  * We use `newrow' and `newcol' so vtresize() know the difference between the
                    417:  * new and old settings.
1.1       deraadt   418:  */
1.8       art       419: void
1.18      vincent   420: ttresize(void)
1.5       millert   421: {
1.11      art       422:        int newrow = 0, newcol = 0;
                    423:
1.10      art       424:        struct  winsize winsize;
                    425:
1.27      deraadt   426:        if (ioctl(0, TIOCGWINSZ, &winsize) == 0) {
1.11      art       427:                newrow = winsize.ws_row;
                    428:                newcol = winsize.ws_col;
                    429:        }
                    430:        if ((newrow <= 0 || newcol <= 0) &&
                    431:            ((newrow = lines) <= 0 || (newcol = columns) <= 0)) {
                    432:                newrow = 24;
                    433:                newcol = 80;
                    434:        }
1.17      vincent   435:        if (vtresize(1, newrow, newcol) != TRUE)
1.11      art       436:                panic("vtresize failed");
1.1       deraadt   437: }
                    438:
1.6       millert   439: /*
1.9       mickey    440:  * fake char output for charcost()
1.6       millert   441:  */
                    442: static int
1.19      art       443: fakec(int c)
1.1       deraadt   444: {
                    445:        cci++;
1.21      db        446:        return (0);
1.1       deraadt   447: }
                    448:
                    449: /* calculate the cost of doing string s */
1.6       millert   450: static int
1.31      guenther  451: charcost(const char *s)
1.5       millert   452: {
1.25      kjell     453:        cci = 0;
1.1       deraadt   454:
1.2       millert   455:        tputs(s, nrow, fakec);
                    456:        return (cci);
1.1       deraadt   457: }