home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume2 / window / part3 / vterm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  11.2 KB  |  452 lines

  1. /*
  2.  *************
  3.  * DISTRIBUTION NOTICE  July 30 1985
  4.  * A Revised Edition of WM, by Matt Lennon and Tom Truscott,
  5.  *        Research Triangle Institute, (919) 541-7005.
  6.  * Based on the original by Robert Jacob (decvax!nrl-css!jacob),
  7.  *        Naval Research Laboratory, (202) 767-3365.
  8.  * No claims or warranties of any sort are made for this distribution.
  9.  * General permission is granted to copy, but not for profit,
  10.  * any of this distribution, provided that this notice
  11.  * is always included in the copies.
  12.  *************
  13.  */
  14. /*
  15.  * This file contains routines for low-level virtual
  16.  * terminal emulation.
  17.  */
  18.  
  19. #include "wm.h"
  20.  
  21. #define FULLWIDTH(wp)    (wcols(wp)==COLS)
  22. #define FULLSCREEN(wp)    (FULLWIDTH(wp) && wlines(wp)==LINES-1)
  23.  
  24. /* Termcap entry for virtual terminals.
  25.  */
  26. static char TERMCAP[]="wm|wmvirt|wm virtual terminal:am:bs:ce=\\EK:ho=\\EH:cd=\\EB:cl=\\ES:nd=\\EC:up=\\EA:cm=\\EY%+ %+ :";
  27. #define TBUFLEN    (sizeof(TERMCAP)+300)    /* max length of termcap string */
  28.  
  29. extern char *tgoto(), *tparm();
  30.  
  31. /*
  32.  * Add 'n' characters of 'p' to window 'w' at its current (y, x) coordinate.
  33.  */
  34. WMaddbuf(w, p, n)
  35. int w;
  36. register char *p;
  37. register int n;
  38. {
  39.     register WINDOW *wp;
  40.     register int y, x;
  41.     register int c;
  42.  
  43.     /*
  44.      * Are we in the midst of an escape sequence?
  45.      */
  46.     while (win[w].pend[0] && --n >= 0)
  47.     WMescape(w, toascii(*p++));
  48.  
  49.     wp = win[w].wptr;
  50.     getyx(wp, y, x);
  51.  
  52.  
  53.     while (--n >= 0) switch (c = toascii(*p++))
  54.     {
  55.     case '\t':
  56.     x = (x+8) & ~07;
  57.     while (x >= wcols(wp)) {
  58.         WMaddbuf(w, "\n", 1);
  59.         x -= wcols(wp);
  60.     }
  61.     wmove(wp, y = wcury(wp), x);
  62.     break;
  63.     case '\n':
  64.     if (++y >= wlines(wp)) {
  65.         --y;
  66.         wmove(wp, 0, x); WMdeleteln(w);
  67.     }
  68.     wmove(wp, y, x);
  69.     break;
  70.     case '\r':
  71.     wmove(wp, y, x = 0);
  72.     break;
  73.     case '\b':
  74.     if (x>0) wmove(wp, y, --x);
  75.     break;
  76.     case '\007':
  77.     beep();
  78.     break;
  79.     case '\0':
  80.     break;
  81.     case ESC:
  82.     win[w].pend[0] = ESC;
  83.     win[w].pend[1] = '\0';
  84.     while (win[w].pend[0] && --n >= 0)
  85.         WMescape(w, toascii(*p++));
  86.     getyx(wp, y, x);
  87.     break;
  88.     /* Dummy cases to fool pcc into generating a fast switch table */
  89.     case 01: case 02: case 03: case 04: case 05: case 06:
  90.     default:
  91.     if (isprint(c))
  92.     {
  93.         waddch(wp, c);
  94.         if (++x >= wcols(wp)) {
  95.         if (++y >= wlines(wp)) {
  96.             --y;
  97.             wmove(wp, 0, 0); WMdeleteln(w);
  98.         }
  99.         wmove(wp, y, x = 0);
  100.         }
  101.     }
  102.     else
  103.     {
  104.         char *s = mkprint(c);
  105.         WMaddbuf(w, s, strlen(s));
  106.         getyx(wp, y, x);
  107.     }
  108.     break;
  109.     }
  110. }
  111.  
  112. /*
  113.  * Construct virtual terminal escape sequence
  114.  * one character at a time.
  115.  * When escape sequence is complete, perform
  116.  * the indicated action in window 'w'.
  117.  */
  118. WMescape(w, c)
  119. int w;
  120. int c;
  121. {
  122.     register WINDOW *wp;
  123.     register int y, x;
  124.     register char *pend;
  125.     int oldx, oldy;
  126.  
  127.  
  128.     pend = win[w].pend;
  129.     wp = win[w].wptr;
  130.     getyx(wp, y, x);
  131.  
  132.      /* ESC-Y is a multi-character escape sequence
  133.       * so we need to make sure we have all the
  134.       * characters before we start processing it.
  135.       */
  136.     if (c == 'Y' && pend[1] == '\0') { pend[1]=c; pend[2]='\0'; return; }
  137.  
  138.     else if (pend[1] == 'Y')
  139.     {
  140.     if (pend[2]=='\0') { pend[2]=c; return; }
  141.     else               { pend[3]=c; c='Y'; }
  142.     }
  143.  
  144.      /* Process escape sequence.
  145.       */
  146.     pend[0] = '\0';    /* escape no longer pending */
  147.     switch (c)
  148.     {
  149.     case 'Y':                /* cursor motion */
  150.     y = oldy = pend[2]-' '; x = oldx = pend[3]-' ';
  151.     if (x < 0) x = 0;
  152.     if (y < 0) y = 0;
  153.     if (x >= wcols(wp)) x = wcols(wp)-1;
  154.     if (y >= wlines(wp)) y = wlines(wp)-1;
  155.     if (y != oldy || x != oldx)
  156.         showmsg("Bad cursor motion to (%d,%d).", oldy, oldx);
  157.     wmove(wp, y, x);
  158.     break;
  159.     case 'K':                /* clear to end of line */
  160.     wclrtoeol(wp);
  161.     break;
  162.     case 'B':                /* clear to bottom of window */
  163.     wclrtobot(wp);
  164.     break;
  165.     case 'H':                /* home cursor */
  166.     wmove(wp, 0, 0);
  167.     break;
  168.     case 'R':                /* visual bell */
  169.     flash();
  170.     break;
  171.     case 'D':                /* delete line */
  172.     WMdeleteln(w);
  173.     break;
  174.     case 'L':                /* insert line */
  175.     WMinsertln(w);
  176.     break;
  177.     case 'P':                /* insert character */
  178. #ifdef CURSEASSIST
  179. #ifndef TERMINFO
  180.     if (FULLWIDTH(wp) && insert_character && !insert_null_glitch) {
  181.         (void) movecursor(wbegy(wp)+y, wbegx(wp)+x);
  182.         putp(insert_character);    winsch(curscr, ' ');
  183.     }
  184. #endif
  185. #endif
  186.     winsch(wp, ' ');
  187.     break;
  188.     case 'Q':                /* delete character */
  189. #ifdef CURSEASSIST
  190. #ifndef TERMINFO
  191.     if (FULLWIDTH(wp) && delete_character) {
  192.         (void) movecursor(wbegy(wp)+y, wbegx(wp)+x);
  193.         putp(delete_character);    wdelch(curscr);
  194.     }
  195. #endif
  196. #endif
  197.     wdelch(wp);
  198.     break;
  199.     case 'S':                /* erase window */
  200.     werase(wp);
  201. #ifdef    CURSEASSIST
  202.     if (FULLSCREEN(wp) && !msgbirth)
  203.         clearok(curscr, TRUE);
  204. #endif
  205.     break;
  206.     case 'C':                /* non-destructive blank */
  207.     if (++x >= wcols(wp)) {
  208.         WMaddbuf(w, "\n", 1);
  209.         x = 0;
  210.     }
  211.     wmove(wp, wcury(wp), x);
  212.     break;
  213.     case 'A':                /* cursor up */
  214.     if (--y>=0) wmove(wp, y, x);
  215.     break;
  216.     case 'O':                /* enter standout mode */
  217.     wstandout(wp);
  218.     break;
  219.     case 'E':                /* leave standout mode */
  220.     wstandend(wp);
  221.     break;
  222.     default:
  223.     {
  224.         char *s;
  225.         s = mkprint(ESC);
  226.         WMaddbuf(w, s, strlen(s));
  227.         s = mkprint(c);
  228.         WMaddbuf(w, s, strlen(s));
  229.     }
  230.     break;
  231.     }
  232. }
  233.  
  234. /*
  235.  * Insert a line just above the current line of window wp.
  236.  * The cursor location in wp is not changed.
  237.  */
  238. WMinsertln(w)
  239. int w;
  240. {
  241.     register WINDOW *wp;
  242.     register int curline, curcol;
  243.  
  244.     wp = win[w].wptr;
  245.     wrefresh(wp);    /* smooths scrolling.  Crucial for untouchwin. */
  246.     winsertln(wp);
  247.  
  248. #ifdef CURSEASSIST
  249.      /* If this terminal has scrolling regions, use them */
  250.     if (has_scroll_region && FULLWIDTH(wp)) {
  251.     /* First, get curscr management out of the way. */
  252.     curline = cursrow(); curcol = curscol();
  253.     Cmove(wbegy(wp)+wlines(wp)-1, 0);
  254.     Cdeleteln();
  255.     Cmove(wbegy(wp)+wcury(wp), 0);
  256.     Cinsertln();
  257.     Cmove(curline, curcol);
  258.     /* now update the screen itself */
  259.     (void) movecursor(wbegy(wp)+wcury(wp), wbegx(wp)+wcurx(wp));
  260.     putp(save_cursor);    /* Save since CS garbles cursor */
  261.     putp(tgoto(change_scroll_region,
  262.         wbegy(wp)+wlines(wp)-1, wbegy(wp)+wcury(wp)));
  263.     putp(restore_cursor);    /* CS garbles cursor */
  264.     putp(scroll_reverse);
  265.     putp(tgoto(change_scroll_region, LINES-1, 0));
  266.     putp(restore_cursor);    /* Once again put it back */
  267.     Untouchwin(wp);
  268.     }
  269.  
  270.     /* Else if this terminal has scrolling rectangles, use them now. */
  271. #ifdef SET_WINDOW
  272.     else if (has_scroll_window) {
  273.     overwrite(wp, curscr);    /* slow but easy */
  274.     putp(tparm(set_window,
  275.         wbegy(wp)+wcury(wp), wbegy(wp)+wlines(wp)-1,
  276.         wbegx(wp), wbegx(wp)+wcols(wp)-1));
  277.     putp(scroll_reverse);
  278.     putp(tparm(set_window, 0, LINES-1, 0, COLS-1));
  279.     /* get back to where curses thinks we are */
  280.     putp(tgoto(cursor_address, curscol(), cursrow()));
  281.     Untouchwin(wp);
  282.     }
  283. #endif
  284.  
  285.     /* Else if this terminal has ins/del line, now is the time */
  286.     else if (has_insdel_line && FULLWIDTH(wp)) {
  287.     /* Open a line above current line in window wp,
  288.      * then delete wp's bottom line.
  289.      * Perform identical operations on curscr
  290.      * as we do on the terminal itself.
  291.      */
  292.     (void) movecursor(wbegy(wp)+wcury(wp), 0);
  293.     putp(insert_line);         Cinsertln();
  294.     (void) movecursor(wbegy(wp)+wlines(wp), 0);
  295.     putp(delete_line);         Cdeleteln();
  296.     RestoreMsg();
  297.     Untouchwin(wp);
  298.     }
  299. #endif
  300. }
  301.  
  302. /*
  303.  * This routine deletes the current line in window wp.
  304.  * The cursor location in wp is not changed.
  305.  */
  306. WMdeleteln(w)
  307. int w;
  308. {
  309.     register WINDOW *wp;
  310.     register int curline, curcol;
  311.  
  312.     wp = win[w].wptr;
  313.  
  314.      /*
  315.       * See what we can do about windows that scroll slowly
  316.       */
  317.      if (!(win[w].flags&FAST)) {
  318.     static int lines_since_refresh = 0;
  319.     if ((lines_since_refresh += 7) >= wlines(wp)) {
  320.         wrefresh(wp);
  321.         lines_since_refresh = 0;
  322.     }
  323.     wdeleteln(wp);
  324. #ifdef BUGGYTERMINFO
  325.     touchwin(wp);
  326. #endif
  327.     return;
  328.     }
  329.  
  330.     wrefresh(wp);    /* smooths scrolling.  Crucial for untouchwin. */
  331.     wdeleteln(wp);
  332. #ifdef BUGGYTERMINFO
  333.     /* wdeleteln neglects first/bottom info for the last line */
  334.     touchwin(wp);
  335. #endif
  336.  
  337. #ifdef CURSEASSIST
  338.      /* If we're deleting top line of a full screen window,
  339.       * this is the same as scrolling.
  340.       * (We do not this if we have scrolling region support
  341.       *  and there is a wm message, but what a bother.)
  342.       */
  343.     if (FULLSCREEN(wp) && wcury(wp)==0 && !(has_scroll_region && msgbirth))
  344.     {
  345.     ZapMsgLine();    /* so it doesn't scroll up into our window */
  346.     curline = cursrow(); curcol = curscol();
  347.     Cmove(0, 0); Cdeleteln();
  348.     Cmove(curline, curcol);
  349.  
  350.     /* Cause screen to scroll.
  351.      * Since wm almost always 'wants' the cursor on LINES-2,
  352.      * there is a cheap heuristic thrown in.
  353.      */
  354.     (void) movecursor(LINES, curcol);
  355. #ifndef TERMINFO
  356.     if (cursor_up) {
  357.         putp(cursor_up);
  358.         Cmove(LINES-2, curcol);
  359.     }
  360. #endif
  361.     RestoreMsg();
  362.     Untouchwin(wp);
  363.     }
  364.  
  365.      /* Else if this terminal has scrolling regions, use them. */
  366.     else if (has_scroll_region && FULLWIDTH(wp)) {
  367.     curline = cursrow(); curcol = curscol();
  368.     Cmove(wbegy(wp)+wcury(wp), 0);
  369.     Cdeleteln();    /* it is about to be deleted */
  370.     Cmove(wbegy(wp)+wlines(wp)-1, 0);
  371.     Cinsertln();    /* it is about to be cleared */
  372.     Cmove(curline, curcol);
  373.     (void) movecursor(wbegy(wp)+wlines(wp)-1, wbegx(wp)+wcurx(wp));
  374.     putp(save_cursor);    /* Save since CS garbles cursor */
  375.     putp(tgoto(change_scroll_region,
  376.         wbegy(wp)+wlines(wp)-1, wbegy(wp)+wcury(wp)));
  377.     putp(restore_cursor);    /* put cursor back */
  378.     putp(scroll_forward);
  379.     putp(tgoto(change_scroll_region, LINES-1, 0));
  380.     putp(restore_cursor);        /* put cursor back */
  381.     Untouchwin(wp);
  382.     }
  383.  
  384.      /* Else if this terminal has scrolling rectangles, use them. */
  385. #ifdef SET_WINDOW
  386.      else if (has_scroll_window) {
  387.     overwrite(wp, curscr);    /* slow but easy */
  388.     putp(tparm(set_window,
  389.         wbegy(wp)+wcury(wp), wbegy(wp)+wlines(wp)-1,
  390.         wbegx(wp), wbegx(wp)+wcols(wp)-1));
  391.     putp(tgoto(cursor_address, 0, wlines(wp)-1));
  392.     putp(scroll_forward);
  393.     putp(tparm(set_window, 0, LINES-1, 0, COLS-1));
  394.     putp(tgoto(cursor_address, curscol(), cursrow()));
  395.     Untouchwin(wp);
  396.     }
  397. #endif
  398.  
  399.     /* Else if this terminal has insdel line, use that. */
  400.     else if (has_insdel_line && FULLWIDTH(wp)) {
  401.     /* Open a line below the last line in window wp,
  402.      * then delete wp's current line.
  403.      */
  404.     (void) movecursor(wbegy(wp)+wlines(wp), 0);
  405.     putp(insert_line);    Cinsertln();
  406.     (void) movecursor(wbegy(wp)+wcury(wp), 0);
  407.     putp(delete_line);    Cdeleteln();
  408.     RestoreMsg();
  409.     Untouchwin(wp);
  410.     }
  411. #endif
  412. }
  413.  
  414. /*
  415.  * Construct termcap for wmvirt terminal in window w.
  416.  */
  417. char *
  418. termcap(w)
  419. int w;
  420. {
  421.     register WINDOW *wp;
  422.     static char tbuf[TBUFLEN];    /* termcap buffer */
  423.  
  424.     wp = win[w].wptr;
  425.     (void)sprintf(tbuf, "%sco#%d:li#%d:", TERMCAP, wcols(wp), wlines(wp));
  426.  
  427.      /* If terminal scrolls 'quickly', add insert/delete line to termcap. */
  428.     if ((win[w].flags&FAST)
  429.      && (has_insdel_line || has_scroll_region || has_scroll_window))
  430.     strcat(tbuf, "al=\\EL:dl=\\ED:");
  431.  
  432.      /* If terminal has insert/delete character options, add them  here */
  433.     if (insert_character || (enter_insert_mode && exit_insert_mode))
  434.     strcat(tbuf, "ic=\\EP:");
  435.     if (delete_character)
  436.     strcat(tbuf, "dc=\\EQ:");
  437.  
  438.      /* If terminal has standout capabilities, add that too. */
  439.     if (enter_standout_mode && exit_standout_mode)
  440.     strcat(tbuf, "so=\\EO:se=\\EE:");
  441.  
  442.     /* Include vb if terminal has a visual bell */
  443.     if (flash_screen)
  444.     strcat(tbuf, "vb=\\ER:");
  445.  
  446.     /* Include keypad capabilities if there is room left */
  447.     if (strlen(tbuf)+strlen(keycap) < TBUFLEN)
  448.     strcat(tbuf, keycap);
  449.  
  450.     return(tbuf);
  451. }
  452.