/* * 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 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; }