diff options
author | 2000-02-25 19:08:45 +0000 | |
---|---|---|
committer | 2000-02-25 19:08:45 +0000 | |
commit | be803e14e26df9ab6a2a65eb17af6bc6477953fb (patch) | |
tree | 48a5beed232744945ae1115f13ec62a9ef9ef110 /usr.bin/mg/tty.c | |
parent | Include files for KerberosIV have moved. (diff) | |
download | wireguard-openbsd-be803e14e26df9ab6a2a65eb17af6bc6477953fb.tar.xz wireguard-openbsd-be803e14e26df9ab6a2a65eb17af6bc6477953fb.zip |
initial import of mg2a
Diffstat (limited to 'usr.bin/mg/tty.c')
-rw-r--r-- | usr.bin/mg/tty.c | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/usr.bin/mg/tty.c b/usr.bin/mg/tty.c new file mode 100644 index 00000000000..3ec5c434629 --- /dev/null +++ b/usr.bin/mg/tty.c @@ -0,0 +1,442 @@ +/* + * Termcap/terminfo display driver + * + * Termcap is a terminal information database and routines to describe + * terminals on most UNIX systems. Many other systems have adopted + * this as a reasonable way to allow for widly varying and ever changing + * varieties of terminal types. This should be used where practical. + */ +/* Known problems: + * If you have a terminal with no clear to end of screen and + * memory of lines below the ones visible on the screen, display + * will be wrong in some cases. I doubt that any such terminal + * was ever made, but I thought everyone with delete line would + * have clear to end of screen too... + * + * Code for terminals without clear to end of screen and/or clear + * to end of line has not been extensivly tested. + * + * Cost calculations are very rough. Costs of insert/delete line + * may be far from the truth. This is accentuated by display.c + * not knowing about multi-line insert/delete. + * + * Using scrolling region vs insert/delete line should probably + * be based on cost rather than the assuption that scrolling + * region operations look better. + */ +#include "def.h" + +#define BEL 0x07 /* BEL character. */ + +extern int ttrow; +extern int ttcol; +extern int tttop; +extern int ttbot; +extern int tthue; + +int tceeol; /* Costs are set later */ +int tcinsl; +int tcdell; + +static int insdel; /* Do we have both insert & delete line? */ + +#ifdef NO_RESIZE +static setttysize(); +#endif + +char *tgetstr(); +char *tgoto(); +int ttputc(); + +#define TCAPSLEN 1024 + +char tcapbuf[TCAPSLEN]; + +/* PC, UP, and BC are used by termlib, so must be extern and have these + * names unless you have a non-standard termlib. + */ + +int LI; /* standard # lines */ +char PC, + *CM, + *CE, + *UP, + *BC, + *IM, /* insert mode */ + *IC, /* insert a single space */ + *EI, /* end insert mode */ + *DC, + *AL, /* add line */ + *DL, /* del line */ + *pAL, /* parameterized add line */ + *pDL, /* parameterized delete line */ + *TI, /* term init -- start using cursor motion */ + *TE, /* term end --- end using cursor motion */ + *SO, + *SE, + *CD, + *CS, /* set scroll region */ + *SF, /* forw index (used with scroll region) */ + *SR; /* back index (used with scroll region) */ +#ifdef XKEYS +char *KS, *KE; /* enter keypad mode, exit keypad mode */ +#endif +int SG; /* number of glitches, 0 for invisible, -1 for none */ + /* (yes virginia, there are terminals with invisible glitches) */ + +/* + * Initialize the terminal when the editor + * gets started up. + */ +static char tcbuf[1024]; + +ttinit() { + char *tv_stype; + char *t, *p, *tgetstr(); +#ifndef gettermtype /* (avoid declaration if #define) */ + char *gettermtype(); /* system dependent function to determin terminal type */ +#endif + + if((tv_stype = gettermtype()) == NULL) + panic("Could not determine terminal type"); + if((tgetent(tcbuf, tv_stype)) != 1) { + (VOID) strcpy(tcbuf, "Unknown terminal type "); + (VOID) strcat(tcbuf, tv_stype); + panic(tcbuf); + } + + p = tcapbuf; + t = tgetstr("pc", &p); + if(t) PC = *t; + + LI = tgetnum("li"); + CD = tgetstr("cd", &p); + CM = tgetstr("cm", &p); + CE = tgetstr("ce", &p); + UP = tgetstr("up", &p); + BC = tgetstr("bc", &p); + IM = tgetstr("im", &p); + IC = tgetstr("ic", &p); + EI = tgetstr("ei", &p); + DC = tgetstr("dc", &p); + AL = tgetstr("al", &p); + DL = tgetstr("dl", &p); + pAL= tgetstr("AL", &p); /* parameterized insert and del. line */ + pDL= tgetstr("DL", &p); + TI = tgetstr("ti", &p); + TE = tgetstr("te", &p); + SO = tgetstr("so", &p); + SE = tgetstr("se", &p); + CS = tgetstr("cs", &p); /* set scrolling region */ + SF = tgetstr("sf", &p); + if(!SF || !*SF) { /* this is what GNU Emacs does */ + SF = tgetstr("do", &p); + if(!SF || !*SF) { + SF = tgetstr("nl", &p); + if(!SF || !*SF) SF = "\n"; + } + } + SR = tgetstr("sr", &p); + SG = tgetnum("sg"); /* standout glitch */ +#ifdef XKEYS + KS = tgetstr("ks", &p); /* keypad start, keypad end */ + KE = tgetstr("ke", &p); +#endif + + if(CM == NULL || UP == NULL) + panic("This terminal is to stupid to run MicroGnuEmacs\n"); + ttresize(); /* set nrow & ncol */ + + /* watch out for empty capabilities (sure to be wrong) */ + if (CE && !*CE) CE = NULL; + if (CS && !*CS) CS = NULL; + if (SR && !*SR) SR = NULL; + if (AL && !*AL) AL = NULL; + if (DL && !*DL) DL = NULL; + if (pAL && !*pAL) pAL = NULL; + if (pDL && !*pDL) pDL = NULL; + if (CD && !*CD) CD = NULL; + + if(!CE) tceeol = ncol; + else tceeol = charcost(CE); + + /* Estimate cost of inserting a line */ + if (CS && SR) tcinsl = charcost(CS)*2 + charcost(SR); + else if (pAL) tcinsl = charcost(pAL); + else if (AL) tcinsl = charcost(AL); + else tcinsl = NROW * NCOL; /* make this cost high enough */ + + /* Estimate cost of deleting a line */ + if (CS) tcdell = charcost(CS)*2 + charcost(SF); + else if (pDL) tcdell = charcost(pDL); + else if (DL) tcdell = charcost(DL); + else tcdell = NROW * NCOL; /* make this cost high enough */ + + /* Flag to indicate that we can both insert and delete lines */ + insdel = (AL || pAL) && (DL || pDL); + + if (p >= &tcapbuf[TCAPSLEN]) + panic("Terminal description too big!\n"); + if (TI && *TI) putpad(TI, 1); /* init the term */ +} + +/* + * Clean up the terminal, in anticipation of + * a return to the command interpreter. This is a no-op + * on the ANSI display. On the SCALD display, it sets the + * window back to half screen scrolling. Perhaps it should + * query the display for the increment, and put it + * back to what it was. + */ +tttidy() { + if (TE && *TE) putpad(TE, 1); /* set the term back to normal mode */ +#ifdef XKEYS + ttykeymaptidy(); +#endif +} + +/* + * Move the cursor to the specified + * origin 0 row and column position. Try to + * optimize out extra moves; redisplay may + * have left the cursor in the right + * location last time! + */ +ttmove(row, col) { + char *tgoto(); + + if (ttrow!=row || ttcol!=col) { + putpad(tgoto(CM, col, row), 1); + ttrow = row; + ttcol = col; + } +} + +/* + * Erase to end of line. + */ +tteeol() { + if(CE) putpad(CE, 1); + else { + register int i=ncol-ttcol; + while(i--) ttputc(' '); + ttrow = ttcol = HUGE; + } +} + +/* + * Erase to end of page. + */ +tteeop() { + if(CD) putpad(CD, nrow - ttrow); + else { + putpad(CE, 1); + if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1); + else { /* do it by hand */ + register int line; + for (line = ttrow + 1; line <= LI; ++line) { + ttmove(line, 0); + tteeol(); + } + } + ttrow = ttcol = HUGE; + } +} + +/* + * Make a noise. + */ +ttbeep() { + ttputc(BEL); + ttflush(); +} + +/* + * Insert nchunk blank line(s) onto the + * screen, scrolling the last line on the + * screen off the bottom. Use the scrolling + * region if possible for a smoother display. + * If no scrolling region, use a set + * of insert and delete line sequences + */ +ttinsl(row, bot, nchunk) { + register int i, nl; + + if (row == bot) { /* Case of one line insert is */ + ttmove(row, 0); /* special */ + tteeol(); + return; + } + if (CS && SR) { /* Use scroll region and back index */ + nl = bot - row; + ttwindow(row,bot); + ttmove(row, 0); + while (nchunk--) putpad(SR, nl); + ttnowindow(); + return; + } else if (insdel) { + ttmove(1+bot-nchunk, 0); + nl = nrow - ttrow; + if (pDL) putpad(tgoto(pDL, 0, nchunk), nl); + else for (i=0; i<nchunk; i++) /* For all lines in the chunk */ + putpad(DL, nl); + ttmove(row, 0); + nl = nrow - ttrow; /* ttmove() changes ttrow */ + if (pAL) putpad(tgoto(pAL, 0, nchunk), nl); + else for (i=0; i<nchunk; i++) /* For all lines in the chunk */ + putpad(AL, nl); + ttrow = HUGE; + ttcol = HUGE; + } else panic("ttinsl: Can't insert/delete line"); +} + +/* + * Delete nchunk line(s) from "row", replacing the + * bottom line on the screen with a blank line. + * Unless we're using the scrolling region, this is + * done with a crafty sequences of insert and delete + * lines. The presence of the echo area makes a + * boundry condition go away. + */ +ttdell(row, bot, nchunk) +{ + register int i, nl; + + if (row == bot) { /* One line special case */ + ttmove(row, 0); + tteeol(); + return; + } + if (CS) { /* scrolling region */ + nl = bot - row; + ttwindow(row, bot); + ttmove(bot, 0); + while (nchunk--) putpad(SF, nl); + ttnowindow(); + } + else if(insdel) { + ttmove(row, 0); /* Else use insert/delete line */ + nl = nrow - ttrow; + if (pDL) putpad(tgoto(pDL, 0, nchunk), nl); + else for (i=0; i<nchunk; i++) /* For all lines in the chunk */ + putpad(DL, nl); + ttmove(1+bot-nchunk,0); + nl = nrow - ttrow; /* ttmove() changes ttrow */ + if (pAL) putpad(tgoto(pAL, 0, nchunk), nl); + else for (i=0; i<nchunk; i++) /* For all lines in the chunk */ + putpad(AL, nl); + ttrow = HUGE; + ttcol = HUGE; + } else panic("ttdell: Can't insert/delete line"); +} + +/* + * This routine sets the scrolling window + * on the display to go from line "top" to line + * "bot" (origin 0, inclusive). The caller checks + * for the pathalogical 1 line scroll window that + * doesn't work right, and avoids it. The "ttrow" + * and "ttcol" variables are set to a crazy value + * to ensure that the next call to "ttmove" does + * not turn into a no-op (the window adjustment + * moves the cursor). + * + */ +ttwindow(top, bot) +{ + if (CS && (tttop!=top || ttbot!=bot)) { + putpad(tgoto(CS, bot, top), nrow - ttrow); + ttrow = HUGE; /* Unknown. */ + ttcol = HUGE; + tttop = top; /* Remember region. */ + ttbot = bot; + } +} + +/* + * Switch to full screen scroll. This is + * used by "spawn.c" just before is suspends the + * editor, and by "display.c" when it is getting ready + * to exit. This function gets to full screen scroll + * by telling the terminal to set a scrolling regin + * that is LI or nrow rows high, whichever is larger. + * This behavior seems to work right on systems + * where you can set your terminal size. + */ +ttnowindow() +{ + if (CS) { + putpad(tgoto(CS, (nrow > LI ? nrow : LI) - 1, 0), nrow - ttrow); + ttrow = HUGE; /* Unknown. */ + ttcol = HUGE; + tttop = HUGE; /* No scroll region. */ + ttbot = HUGE; + } +} + +/* + * Set the current writing color to the + * specified color. Watch for color changes that are + * not going to do anything (the color is already right) + * and don't send anything to the display. + * The rainbow version does this in putline.s on a + * line by line basis, so don't bother sending + * out the color shift. + */ +ttcolor(color) register int color; { + if (color != tthue) { + if (color == CTEXT) { /* Normal video. */ + putpad(SE, 1); + } else if (color == CMODE) { /* Reverse video. */ + putpad(SO, 1); + } + tthue = color; /* Save the color. */ + } +} + +/* + * This routine is called by the + * "refresh the screen" command to try and resize + * the display. The new size, which must be deadstopped + * to not exceed the NROW and NCOL limits, it stored + * back into "nrow" and "ncol". Display can always deal + * with a screen NROW by NCOL. Look in "window.c" to + * see how the caller deals with a change. + */ +ttresize() { + setttysize(); /* found in "ttyio.c", */ + /* ask OS for tty size */ + if (nrow < 1) /* Check limits. */ + nrow = 1; + else if (nrow > NROW) + nrow = NROW; + if (ncol < 1) + ncol = 1; + else if (ncol > NCOL) + ncol = NCOL; +} + +#ifdef NO_RESIZE +static setttysize() { + nrow = tgetnum("li"); + ncol = tgetnum("co"); +} +#endif + +static int cci; + +/*ARGSUSED*/ +static int /* fake char output for charcost() */ +fakec(c) +char c; +{ + cci++; +} + +/* calculate the cost of doing string s */ +charcost (s) char *s; { + cci = 0; + + tputs(s, nrow, fakec); + return cci; +} |