home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / micrognu / part04 / tty / termcap / tty.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-01-26  |  11.7 KB  |  469 lines

  1. /*
  2.  * Termcap/terminfo display driver
  3.  *
  4.  * Termcap is a terminal information database and routines to describe 
  5.  * terminals on most UNIX systems.  Many other systems have adopted
  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.  *    tputs is always called with the number of lines affected set to
  11.  *    one.  Therefore, padding may be insufficient on some sequences
  12.  *    dispite termcap being set up correctly.
  13.  *
  14.  *    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
  16.  *    will be wrong in some cases.  I doubt that any such terminal
  17.  *    was ever made, but I thought everyone with delete line would
  18.  *    have clear to end of screen too...
  19.  *
  20.  *    Code for terminals without clear to end of screen and/or clear
  21.  *    to end of line has not been extensivly tested.
  22.  *
  23.  *    Cost calculations are very rough.  Costs of insert/delete line
  24.  *    may be far from the truth.  This is accentuated by display.c
  25.  *    not knowing about multi-line insert/delete.
  26.  *
  27.  *    Using scrolling region vs insert/delete line should probably
  28.  *    be based on cost rather than the assuption that scrolling
  29.  *    region operations look better.
  30.  */
  31. #include    "def.h"
  32.  
  33. #define    BEL    0x07            /* BEL character.        */
  34. #define    LF    0x0A            /* Line feed.            */
  35.  
  36. extern    int    ttrow;
  37. extern    int    ttcol;
  38. extern    int    tttop;
  39. extern    int    ttbot;
  40. extern    int    tthue;
  41.  
  42. int    tceeol;            /* Costs are set later */
  43. int    tcinsl;
  44. int    tcdell;
  45.  
  46. static    int    insdel;        /* Do we have both insert & delete line? */
  47.  
  48. char    *tgetstr();
  49. char    *tgoto();
  50. int    ttputc();
  51.  
  52. #define TCAPSLEN 1024
  53.  
  54. char tcapbuf[TCAPSLEN];
  55.  
  56. /* PC, UP, and BC are used by termlib, so must be extern and have these
  57.  * names unless you have a non-standard termlib.
  58.  */
  59.  
  60. int    LI;            /* standard # lines */
  61. char    PC,
  62.         *CM,
  63.         *CE,
  64.         *UP,
  65.     *BC,
  66.     *IM,            /* insert mode */
  67.     *IC,            /* insert a single space */
  68.     *EI,            /* end insert mode */
  69.     *DC,
  70.     *AL,            /* add line */
  71.     *DL,            /* del line */
  72.     *pAL,            /* parameterized add line */
  73.     *pDL,            /* parameterized delete line */
  74.     *TI,            /* term init -- start using cursor motion */
  75.     *TE,            /* term end --- end using cursor motion */
  76.     *SO,
  77.     *SE,
  78.         *CD,
  79.     *CS,            /* set scroll region            */
  80.     *SR;            /* back index (used with scroll region    */
  81. #ifdef    XKEYS
  82. char    *K[NFKEYS],        /* other function key codes        */
  83.     *L[NFKEYS],        /* labels for other functions keys    */
  84.     *KS, *KE,        /* enter keypad mode, exit keypad mode    */
  85.     *KH, *KU, *KD, *KL, *KR; /* home, arrow keys            */
  86. #endif
  87. int    SG;    /* number of glitches, 0 for invisable, -1 for none    */
  88.     /* (yes virginia, there are terminals with invisible glitches)    */
  89.  
  90. /*
  91.  * Initialize the terminal when the editor
  92.  * gets started up.
  93.  */
  94. static char tcbuf[1024];
  95.  
  96. ttinit() {
  97.         char *getenv();
  98.         char *t, *p, *tgetstr();
  99.         char *tv_stype;
  100. #ifdef    XKEYS
  101.     char kname[3], lname[3];
  102.     int i;
  103. #endif
  104.  
  105. #ifdef    VAXC
  106.         if ((tv_stype = trnlnm("TERM")) == NULL)
  107. #else
  108.         if ((tv_stype = getenv("TERM")) == NULL)/* Don't want VAX C getenv() */
  109. #endif
  110.                 panic("Environment variable TERM not defined!");
  111.  
  112.         if((tgetent(tcbuf, tv_stype)) != 1)
  113.     {
  114.         (VOID) strcpy(tcbuf, "Unknown terminal type ");
  115.         (VOID) strcat(tcbuf, tv_stype);
  116.                 panic(tcbuf);
  117.         }
  118.  
  119.         p = tcapbuf;
  120.         t = tgetstr("pc", &p);
  121.         if(t) PC = *t;
  122.  
  123.     LI = tgetnum("li");
  124.         CD = tgetstr("cd", &p);
  125.         CM = tgetstr("cm", &p);
  126.         CE = tgetstr("ce", &p);
  127.         UP = tgetstr("up", &p);
  128.     BC = tgetstr("bc", &p);
  129.     IM = tgetstr("im", &p);
  130.     IC = tgetstr("ic", &p);
  131.     EI = tgetstr("ei", &p);
  132.     DC = tgetstr("dc", &p);
  133.     AL = tgetstr("al", &p);
  134.     DL = tgetstr("dl", &p);
  135.     pAL= tgetstr("AL", &p);    /* parameterized insert and del. line */
  136.     pDL= tgetstr("DL", &p);
  137.     TI = tgetstr("ti", &p);
  138.     TE = tgetstr("te", &p);
  139.     SO = tgetstr("so", &p);
  140.     SE = tgetstr("se", &p);
  141.     CS = tgetstr("cs", &p); /* set scrolling region */
  142.     SR = tgetstr("sr", &p);
  143.     SG = tgetnum("sg");    /* standout glitch     */
  144. #ifdef    XKEYS
  145.     /* get the 10 standard termcap keys */
  146.     strcpy(kname,"kx");
  147.     strcpy(lname,"lx");
  148.     for (i = 0; i < 10; i++) {
  149.         kname[1] = i + '0';
  150.         K[i] = tgetstr(kname, &p);
  151.         lname[1] = i + '0';
  152.         L[i] = tgetstr(lname, &p);
  153.     }
  154.     /* Hack to get another bunch */
  155.     strcpy(kname,"Kx");
  156.     strcpy(lname,"Lx");
  157.     for (i = 0; i < 10; i++) {
  158.         kname[1] = i + '0';
  159.         K[10 + i] = tgetstr(kname, &p);
  160.         lname[1] = i + '0';
  161.         L[10 + i] = tgetstr(lname, &p);
  162.     }
  163.  
  164.     /* Get the rest of the sequences */
  165.     KS = tgetstr("ks", &p);
  166.     KE = tgetstr("ke", &p);
  167.     KH = tgetstr("kh", &p);
  168.     KU = tgetstr("ku", &p);
  169.     KD = tgetstr("kd", &p);
  170.     KL = tgetstr("kl", &p);
  171.     KR = tgetstr("kr", &p);
  172. #endif
  173.  
  174.         if(CM == NULL || UP == NULL)
  175.             panic("This terminal is to stupid to run MicroGnuEmacs\n");
  176.     ttresize();            /* set nrow & ncol    */
  177.  
  178.     /* watch out for empty capabilities (sure to be wrong)    */
  179.     if (CE && !*CE) CE = NULL;
  180.     if (CS && !*CS) CS = NULL;
  181.     if (SR && !*SR) SR = NULL;
  182.     if (AL && !*AL) AL = NULL;
  183.     if (DL && !*DL) DL = NULL;
  184.     if (pAL && !*pAL) pAL = NULL;
  185.     if (pDL && !*pDL) pDL = NULL;
  186.     if (CD && !*CD) CD = NULL;
  187.  
  188.     if(!CE)    tceeol = ncol;
  189.     else     tceeol = charcost(CE);
  190.  
  191.     /* Estimate cost of inserting a line */
  192.     if (CS && SR)    tcinsl = charcost(CS)*2 + charcost(SR);
  193.     else if (pAL)   tcinsl = charcost(pAL);
  194.     else if (AL)    tcinsl = charcost(AL);
  195.     else        tcinsl = NROW * NCOL;    /* make this cost high enough */
  196.  
  197.     /* Estimate cost of deleting a line */
  198.     if (CS)        tcdell = charcost(CS)*2 + 1;
  199.     else if (pDL)   tcdell = charcost(pDL);
  200.     else if (DL)    tcdell = charcost(DL);
  201.     else        tcdell = NROW * NCOL;    /* make this cost high enough */
  202.  
  203.     /* Flag to indicate that we can both insert and delete lines */
  204.     insdel = (AL || pAL) && (DL || pDL);
  205.  
  206.         if (p >= &tcapbuf[TCAPSLEN])
  207.         panic("Terminal description too big!\n");
  208.     if (TI && *TI) putpad (TI);    /* init the term */
  209. }
  210.  
  211. /*
  212.  * Clean up the terminal, in anticipation of
  213.  * a return to the command interpreter. This is a no-op
  214.  * on the ANSI display. On the SCALD display, it sets the
  215.  * window back to half screen scrolling. Perhaps it should
  216.  * query the display for the increment, and put it
  217.  * back to what it was.
  218.  */
  219. tttidy() {
  220.     if (TE && *TE) putpad (TE);    /* set the term back to normal mode */
  221. #ifdef    XKEYS
  222.     ttykeymaptidy();
  223. #endif
  224. }
  225.  
  226. /*
  227.  * Move the cursor to the specified
  228.  * origin 0 row and column position. Try to
  229.  * optimize out extra moves; redisplay may
  230.  * have left the cursor in the right
  231.  * location last time!
  232.  */
  233. ttmove(row, col) {
  234.     char        *tgoto();
  235.  
  236.     if (ttrow!=row || ttcol!=col) {
  237.     putpad(tgoto(CM, col, row));
  238.     ttrow = row;
  239.     ttcol = col;
  240.     }
  241. }
  242.  
  243. /*
  244.  * Erase to end of line.
  245.  */
  246. tteeol() {
  247.     if(CE) putpad(CE);
  248.     else {
  249.     register int i=ncol-ttcol;
  250.     while(i--) ttputc(" ");
  251.     ttrow = ttcol = HUGE;
  252.     }
  253. }
  254.  
  255. /*
  256.  * Erase to end of page.
  257.  */
  258. tteeop() {
  259.     if(CD) putpad(CD);
  260.     else {
  261.         putpad(CE);
  262.     if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1);
  263.     else {        /* do it by hand */
  264.         register int line;
  265.         for (line = ttrow + 1; line <= LI; ++line) {
  266.             ttmove(line, 0);
  267.         tteeol();
  268.         }
  269.     }
  270.     ttrow = ttcol = HUGE;
  271.     }
  272. }
  273.  
  274. /*
  275.  * Make a noise.
  276.  */
  277. ttbeep() {
  278.     ttputc(BEL);
  279.     ttflush();
  280. }
  281.  
  282. /*
  283.  * Insert nchunk blank line(s) onto the
  284.  * screen, scrolling the last line on the
  285.  * screen off the bottom.  Use the scrolling
  286.  * region if possible for a smoother display.
  287.  * If no scrolling region, use a set
  288.  * of insert and delete line sequences
  289.  */
  290. ttinsl(row, bot, nchunk) {
  291.     register int    i;
  292.     
  293.     if (row == bot) {        /* Case of one line insert is     */
  294.     ttmove(row, 0);        /*    special            */
  295.     tteeol();
  296.     return;
  297.     }
  298.     if (CS && SR) {        /* Use scroll region and back index    */
  299.     ttwindow(row,bot);
  300.     ttmove(row, 0);
  301.     while (nchunk--) putpad(SR);
  302.     ttnowindow();
  303.     return;
  304.     } else if (insdel) {
  305.     ttmove(1+bot-nchunk, 0);
  306.     if (pDL) putpad (tgoto(pDL, 0, nchunk));
  307.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  308.         putpad(DL);
  309.     ttmove(row, 0);
  310.     if (pAL) putpad (tgoto(pAL, 0, nchunk));
  311.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  312.         putpad(AL);
  313.     ttrow = HUGE;
  314.     ttcol = HUGE;
  315.     } else panic("ttinsl: Can't insert/delete line");
  316. }
  317.  
  318. /*
  319.  * Delete nchunk line(s) from "row", replacing the
  320.  * bottom line on the screen with a blank line. 
  321.  * Unless we're using the scrolling region, this is 
  322.  * done with a crafty sequences of insert and delete 
  323.  * lines.  The presence of the echo area makes a
  324.  * boundry condition go away.
  325.  */
  326. ttdell(row, bot, nchunk)
  327. {
  328.     register int    i;
  329.     
  330.     if (row == bot) {        /* One line special case    */
  331.     ttmove(row, 0);
  332.     tteeol();
  333.     return;
  334.     }
  335.     if (CS) {            /* scrolling region    */
  336.     ttwindow(row, bot);
  337.     ttmove(bot, 0);
  338.     while (nchunk--) ttputc(LF);
  339.     ttnowindow();
  340.     }
  341.     else if(insdel) {
  342.     ttmove(row, 0);            /* Else use insert/delete line    */
  343.     if (pDL) putpad (tgoto(pDL, 0, nchunk));
  344.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  345.         putpad(DL);
  346.     ttmove(1+bot-nchunk,0);
  347.     if (pAL) putpad (tgoto(pAL, 0, nchunk));
  348.     else for (i=0; i<nchunk; i++)    /* For all lines in the chunk    */
  349.         putpad(AL);
  350.     ttrow = HUGE;
  351.     ttcol = HUGE;
  352.     } else panic("ttdell: Can't insert/delete line");
  353. }
  354.  
  355. /*
  356.  * This routine sets the scrolling window
  357.  * on the display to go from line "top" to line
  358.  * "bot" (origin 0, inclusive). The caller checks
  359.  * for the pathalogical 1 line scroll window that
  360.  * doesn't work right, and avoids it. The "ttrow"
  361.  * and "ttcol" variables are set to a crazy value
  362.  * to ensure that the next call to "ttmove" does
  363.  * not turn into a no-op (the window adjustment
  364.  * moves the cursor).
  365.  * 
  366.  */
  367. ttwindow(top, bot)
  368. {
  369.     if (CS && (tttop!=top || ttbot!=bot)) {
  370.         putpad(tgoto(CS, bot, top));
  371.         ttrow = HUGE;            /* Unknown.        */
  372.         ttcol = HUGE;
  373.         tttop = top;            /* Remember region.    */
  374.         ttbot = bot;
  375.     }
  376. }
  377.  
  378. /*
  379.  * Switch to full screen scroll. This is
  380.  * used by "spawn.c" just before is suspends the
  381.  * editor, and by "display.c" when it is getting ready
  382.  * to exit.  This function gets to full screen scroll 
  383.  * by telling the terminal to set a scrolling regin
  384.  * that is LI or nrow rows high, whichever is larger.
  385.  * This behavior seems to work right on systems
  386.  * where you can set your terminal size.
  387.  */
  388. ttnowindow()
  389. {
  390.     if (CS) {
  391.     putpad(tgoto(CS, (nrow > LI ? nrow : LI) - 1, 0));
  392.     ttrow = HUGE;            /* Unknown.        */
  393.     ttcol = HUGE;
  394.     tttop = HUGE;            /* No scroll region.    */
  395.     ttbot = HUGE;
  396.     }
  397. }
  398.  
  399. /*
  400.  * Set the current writing color to the
  401.  * specified color. Watch for color changes that are
  402.  * not going to do anything (the color is already right)
  403.  * and don't send anything to the display.
  404.  * The rainbow version does this in putline.s on a
  405.  * line by line basis, so don't bother sending
  406.  * out the color shift.
  407.  */
  408. ttcolor(color) register int color; {
  409.     if (color != tthue) {
  410.     if (color == CTEXT) {        /* Normal video.    */
  411.         putpad(SE);
  412.     } else if (color == CMODE) {    /* Reverse video.    */
  413.         putpad(SO);
  414.     }
  415.     tthue = color;            /* Save the color.    */
  416.     }
  417. }
  418.  
  419. /*
  420.  * This routine is called by the
  421.  * "refresh the screen" command to try and resize
  422.  * the display. The new size, which must be deadstopped
  423.  * to not exceed the NROW and NCOL limits, it stored
  424.  * back into "nrow" and "ncol". Display can always deal
  425.  * with a screen NROW by NCOL. Look in "window.c" to
  426.  * see how the caller deals with a change.
  427.  */
  428. ttresize() {
  429.     setttysize();            /* found in "ttyio.c",    */
  430.                     /* ask OS for tty size    */
  431.     if (nrow < 1)            /* Check limits.    */
  432.         nrow = 1;
  433.     else if (nrow > NROW)
  434.         nrow = NROW;
  435.     if (ncol < 1)
  436.         ncol = 1;
  437.     else if (ncol > NCOL)
  438.         ncol = NCOL;
  439. }
  440.  
  441. #ifdef NO_RESIZE
  442. static setttysize() {
  443.     nrow = tgetnum("li");
  444.     ncol = tgetnum("co");
  445. }
  446. #endif
  447.  
  448. static int cci;
  449.  
  450. static            /* fake char output for charcost() */
  451. fakec(c) char c; {
  452. #ifdef    lint
  453.     c++;
  454. #endif
  455.     cci++;
  456. }
  457.  
  458. /* calculate the cost of doing string s */
  459. charcost (s) char *s; {
  460.     cci = 0;
  461.  
  462.     tputs(s, nrow, fakec);
  463.     return cci;
  464. }
  465.  
  466. putpad(str) char *str; {
  467.         tputs(str, 1, ttputc);
  468. }
  469.