home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / toswinsc.zoo / vt52.c < prev    next >
C/C++ Source or Header  |  1992-10-27  |  13KB  |  658 lines

  1. /*
  2.  * Copyright 1992 Eric R. Smith. All rights reserved.
  3.  * Redistribution is permitted only if the distribution
  4.  * is not for profit, and only if all documentation
  5.  * (including, in particular, the file "copying")
  6.  * is included in the distribution in unmodified form.
  7.  * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
  8.  * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
  9.  * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
  10.  * RISK.
  11.  */
  12. /*
  13.  * VT52 emulator for a GEM text window (with type TEXTWIN)
  14.  */
  15.  
  16. #include "xgem.h"
  17. #include <osbind.h>
  18. #include <stdlib.h>
  19. #include "twdefs.h"
  20. #include "twproto.h"
  21.  
  22. void vt52_putch();
  23.  
  24. /*
  25.  * paint(v, c): put character 'c' at the current (x, y) coordinates
  26.  * of window v. If insert mode is on, this involves moving all the
  27.  * other characters one space to the left, first.
  28.  */
  29.  
  30. static void
  31. paint(v, c)
  32.     TEXTWIN *v;
  33.     int c;
  34. {
  35.     int i;
  36.     int line = v->cy;
  37.  
  38.     if (v->term_flags & FINSERT) {
  39.         for (i = v->maxx-1; i > v->cx; --i) {
  40.             v->data[line][i] = v->data[line][i-1];
  41.             v->cflag[line][i] = v->cflag[line][i-1] | CDIRTY;
  42.         }
  43.     }
  44.     if (v->data[line][v->cx] != c) {
  45.         v->data[line][v->cx] = c;
  46.         v->cflag[line][v->cx] = CDIRTY | v->term_cattr;
  47.     }
  48.     else
  49.         v->cflag[line][v->cx] = (CTOUCHED | v->term_cattr);
  50.     v->dirty[line] |= SOMEDIRTY;
  51. }
  52.  
  53. /*
  54.  * gotoxy (v, x, y): move current cursor address of window v to (x, y)
  55.  * verifies that (x,y) is within range
  56.  */
  57.  
  58. static void
  59. gotoxy(v, x, y)
  60.     TEXTWIN *v;
  61.     int x, y;
  62. {
  63.     if (x < 0) x = 0;
  64.     else if (x >= v->maxx) x = v->maxx - 1;
  65.     if (y < v->miny) y = v->miny;
  66.     else if (y >= v->maxy) y = v->maxy - 1;
  67.  
  68.     v->cx = x;
  69.     v->cy = y;
  70. }
  71.  
  72. /*
  73.  * clrline(v, r): clear line r of window v
  74.  */
  75.  
  76. static void
  77. clrline(v, r)
  78.     TEXTWIN *v;
  79.     int r;
  80. {
  81.     int i;
  82.  
  83.     for (i = v->maxx-1; i >= 0; --i) {
  84.         v->data[r][i] = ' ';
  85.         v->cflag[r][i] = v->term_cattr & (CBGCOL|CFGCOL);
  86.     }
  87.     v->dirty[r] = ALLDIRTY;
  88. }
  89.     
  90. /*
  91.  * clear(v): clear the whole window v
  92.  */
  93.  
  94. static void
  95. clear(v)
  96.     TEXTWIN *v;
  97. {
  98.     int y;
  99.  
  100.     for (y = v->miny; y < v->maxy; y++)
  101.         clrline(v, y);
  102. }
  103.  
  104. /*
  105.  * clrchar(v, x, y): clear the (x,y) position on window v
  106.  */
  107.  
  108. static void
  109. clrchar(v, x, y)
  110.     TEXTWIN *v;
  111.     int x, y;
  112. {
  113.     if (v->data[y][x] != ' ') {
  114.         v->data[y][x] = ' ';
  115.         v->cflag[y][x] = CDIRTY | (v->term_cattr & (CBGCOL|CFGCOL));
  116.     } else {
  117.         v->cflag[y][x] = CTOUCHED |
  118.             (v->term_cattr & (CBGCOL|CFGCOL));
  119.     }
  120.     v->dirty[y] |= SOMEDIRTY;
  121. }
  122.  
  123. /*
  124.  * clrfrom(v, x1, y1, x2, y2): clear window v from position (x1,y1) to
  125.  * position (x2, y2) inclusive. It is assumed that y2 >= y1.
  126.  */
  127.  
  128. static void
  129. clrfrom(v, x1, y1, x2, y2)
  130.     TEXTWIN *v;
  131.     int x1,y1,x2,y2;
  132. {
  133.     int i;
  134.  
  135.     for (i = x1; i < v->maxx; i++)
  136.         clrchar(v, i, y1);
  137.     if (y2 > y1) {
  138.         for (i = 0; i <= x2; i++)
  139.             clrchar(v, i, y2);
  140.         for (i = y1+1; i < y2; i++)
  141.             clrline(v, i);
  142.     }
  143. }
  144.  
  145. /*
  146.  * delete_char(v, x, y): delete the character at position (x, y) on
  147.  * the screen; the rest of the line is scrolled left, and a blank is
  148.  * inserted at the end of the line.
  149.  */
  150.  
  151. static void
  152. delete_char(v, x, y)
  153.     TEXTWIN *v;
  154.     int x, y;
  155. {
  156.     int i;
  157.  
  158.     for (i = x; i < v->maxx-1; i++) {
  159.         v->data[y][i] = v->data[y][i+1];
  160.         v->cflag[y][i] = v->cflag[y][i+1] | CDIRTY;
  161.     }
  162.     v->data[y][v->maxx-1] = ' ';
  163.     v->cflag[y][v->maxx-1] = CDIRTY | (v->term_cattr & (CBGCOL|CFGCOL));
  164.     v->dirty[y] |= SOMEDIRTY;
  165. }
  166.  
  167. /*
  168.  * delete_line(v, r): delete line r of window v. The screen below this
  169.  * line is scrolled up, and the bottom line is cleared.
  170.  */
  171.  
  172. #define scroll(v) delete_line(v, 0)
  173.  
  174. static void
  175. delete_line(v, r)
  176.     TEXTWIN *v;
  177.     int r;
  178. {
  179.     int y;
  180.     int doscroll = (r == 0);
  181.     UCHAR *oldline;
  182.     short *oldflag;
  183.  
  184.     oldline = v->data[r];
  185.     oldflag = v->cflag[r];
  186.     for (y = r; y < v->maxy-1; y++) {
  187.         v->data[y] = v->data[y+1];
  188.         v->cflag[y] = v->cflag[y+1];
  189.         v->dirty[y] = doscroll ? v->dirty[y+1] : ALLDIRTY;
  190.     }
  191.  
  192.     v->data[y] = oldline;
  193.     v->cflag[y] = oldflag;
  194.  
  195. /* clear the last line */
  196.     clrline(v, v->maxy - 1);
  197.     if (doscroll) {
  198.         v->scrolled++;
  199.     }
  200. }
  201.  
  202. /*
  203.  * insert_line(v, r): scroll all of the window from line r down,
  204.  * and then clear line r.
  205.  */
  206.  
  207. static void
  208. insert_line(v, r)
  209.     TEXTWIN *v;
  210.     int r;
  211. {
  212.     int i, limit;
  213.     UCHAR *oldline;
  214.     short *oldflag;
  215.  
  216.     limit = v->maxy - 1;
  217.     oldline = v->data[limit];
  218.     oldflag = v->cflag[limit];
  219.  
  220.     for (i = limit-1; i >= r ; --i) {
  221.     /* move line i to line i+1 */
  222.         v->data[i+1] = v->data[i];
  223.         v->cflag[i+1] = v->cflag[i];
  224.         v->dirty[i+1] = ALLDIRTY;
  225.     }
  226.  
  227.     v->cflag[r] = oldflag;
  228.     v->data[r] = oldline;
  229. /* clear line r */
  230.     clrline(v, r);
  231. }
  232.  
  233. /*
  234.  * assorted callback functions
  235.  */
  236.  
  237. static void
  238. set_title(v)
  239.     TEXTWIN *v;
  240. {
  241.     WINDOW *w = v->win;
  242.  
  243.     title_window(w, v->captbuf);
  244. }
  245.  
  246. static void
  247. set_size(v)
  248.     TEXTWIN *v;
  249. {
  250.     int rows, cols;
  251.     char *s;
  252.     s = v->captbuf;
  253.     while (*s && *s != ',') s++;
  254.     if (*s) *s++ = 0;
  255.     cols = decval(v->captbuf);
  256.     rows = decval(s);
  257.     if (rows == 0) rows = v->maxy;
  258.     else if (rows < MINROWS) rows = MINROWS;
  259.     else if (rows > MAXROWS) rows = MAXROWS;
  260.     if (cols == 0) cols = v->maxx;
  261.     else if (rows < MINCOLS) rows = MINCOLS;
  262.     else if (cols > MAXCOLS) cols = MAXCOLS;
  263.     resize_textwin(v, cols, rows, v->miny);
  264. }
  265.  
  266. /* capture(v, c): put character c into the capture buffer
  267.  * if c is '\r', then we're finished and we call the callback
  268.  * function
  269.  */
  270.  
  271. static void
  272. capture(v, c)
  273.     TEXTWIN *v;
  274.     int c;
  275. {
  276.     int i = v->captsiz;
  277.  
  278.     if (c == '\r') c = 0;
  279.  
  280.     if (i < CAPTURESIZE || c == 0) {
  281.         v->captbuf[i++] = c;
  282.         v->captsiz = i;
  283.     }
  284.     if (c == 0) {
  285.         v->output = vt52_putch;
  286.         (*v->callback)(v);
  287.     }
  288. }
  289.  
  290. /*
  291.  * paint a character, even if it's a graphic character
  292.  */
  293.  
  294. static void
  295. quote_putch(v, c)
  296.     TEXTWIN *v;
  297.     int c;
  298. {
  299.     if (c == 0) c = ' ';
  300.     curs_off(v);
  301.     paint(v, c);
  302.     v->cx++;
  303.     if (v->cx == v->maxx) {
  304.         if (v->term_flags & FWRAP) {
  305.             v->cx = 0;
  306.             vt52_putch(v, '\n');
  307.         } else {
  308.             v->cx = v->maxx - 1;
  309.         }
  310.     }
  311.     curs_on(v);
  312.     v->output = vt52_putch;
  313. }
  314.  
  315. static void
  316. fgcol_putch(v, c)
  317.     TEXTWIN *v;
  318.     int c;
  319. {
  320.     v->term_cattr = (v->term_cattr & ~CFGCOL) | ((c & 0x000f) << 4);
  321.     v->output = vt52_putch;
  322. }
  323.  
  324. static void
  325. bgcol_putch(v, c)
  326.     TEXTWIN *v;
  327.     int c;
  328. {
  329.     v->term_cattr = (v->term_cattr & ~CBGCOL) | (c & 0x000f);
  330.     v->output = vt52_putch;
  331. }
  332.  
  333. /* set special effects */
  334. static void
  335. seffect_putch(v, c)
  336.     TEXTWIN *v;
  337.     int c;
  338. {
  339.     v->term_cattr |= ((c & 0x1f) << 8);
  340.     v->output = vt52_putch;
  341. }
  342.  
  343. /* clear special effects */
  344. static void
  345. ceffect_putch(v, c)
  346.     TEXTWIN *v;
  347.     int c;
  348. {
  349.     v->term_cattr &= ~((c & 0x1f) << 8);
  350.     v->output = vt52_putch;
  351. }
  352.  
  353. /* set cursor flash time */
  354. static void
  355. timer_putch(v, c)
  356.     TEXTWIN *v;
  357.     int c;
  358. {
  359.     c -= ' ';
  360.     if (c < 0) c = 0;
  361.     v->flashperiod = v->flashtimer = c;
  362.     v->output = vt52_putch;
  363. }
  364.  
  365. /*
  366.  * putesc(v, c): handle the control sequence ESC c
  367.  */
  368.  
  369. static void
  370. putesc(v, c)
  371.     TEXTWIN *v;
  372.     int c;
  373. {
  374.     int cx, cy;
  375.     static void escy_putch();
  376.  
  377.     curs_off(v);
  378.  
  379.     cx = v->cx; cy = v->cy;
  380.  
  381.     switch (c) {
  382.     case 'A':        /* cursor up */
  383.         gotoxy(v, cx, cy-1);
  384.         break;
  385.     case 'B':        /* cursor down */
  386.         gotoxy(v, cx, cy+1);
  387.         break;
  388.     case 'C':        /* cursor right */
  389.         gotoxy(v, cx+1, cy);
  390.         break;
  391.     case 'D':        /* cursor left */
  392.         gotoxy(v, cx-1, cy);
  393.         break;
  394.     case 'E':        /* clear home */
  395.         clear(v);
  396.         /* fall through... */
  397.     case 'H':        /* cursor home */
  398.         gotoxy(v, 0, v->miny);
  399.         break;
  400.     case 'I':        /* cursor up, insert line */
  401.         if (cy == v->miny)
  402.             insert_line(v, v->miny);
  403.         else
  404.             gotoxy(v, cx, cy-1);
  405.         break;
  406.     case 'J':        /* clear below cursor */
  407.         clrfrom(v, cx, cy, v->maxx-1, v->maxy-1);
  408.         break;
  409.     case 'K':        /* clear remainder of line */
  410.         clrfrom(v, cx, cy, v->maxx-1, cy);
  411.         break;
  412.     case 'L':        /* insert a line */
  413.         insert_line(v, cy);
  414.         gotoxy(v, 0, cy);
  415.         break;
  416.     case 'M':        /* delete line */
  417.         delete_line(v, cy);
  418.         gotoxy(v, 0, cy);
  419.         break;
  420.     case 'Q':        /* MW extension: quote next character */
  421.         v->output = quote_putch;
  422.         curs_on(v);
  423.         return;
  424.     case 'R':        /* TW extension: set window size */
  425.         v->captsiz = 0;
  426.         v->output = capture;
  427.         v->callback = set_size;
  428.         curs_on(v);
  429.         return;
  430.     case 'S':        /* MW extension: set title bar */
  431.         v->captsiz = 0;
  432.         v->output = capture;
  433.         v->callback = set_title;
  434.         curs_on(v);
  435.         return;
  436.     case 'T':        /* TW extension: send termcap string */
  437.         output_termcap(v);
  438.         break;
  439.     case 'Y':
  440.         v->output = escy_putch;
  441.         curs_on(v);
  442.         return;
  443.     case 'a':        /* MW extension: delete character */
  444.         delete_char(v, cx, cy);
  445.         break;
  446.     case 'b':        /* set foreground color */
  447.         v->output = fgcol_putch;
  448.         curs_on(v);
  449.         return;        /* `return' to avoid resetting v->output */
  450.     case 'c':        /* set background color */
  451.         v->output = bgcol_putch;
  452.         curs_on(v);
  453.         return;
  454.     case 'd':        /* clear to cursor position */
  455.         clrfrom(v, 0, v->miny, cx, cy);
  456.         break;
  457.     case 'e':        /* enable cursor */
  458.         v->term_flags |= FCURS;
  459.         break;
  460.     case 'f':        /* cursor off */
  461.         v->term_flags &= ~FCURS;
  462.         break;
  463.     case 'h':        /* MW extension: enter insert mode */
  464.         v->term_flags |= FINSERT;
  465.         break;
  466.     case 'i':        /* MW extension: leave insert mode */
  467.         v->term_flags &= ~FINSERT;
  468.         break;
  469.     case 'j':        /* save cursor position */
  470.         v->savex = v->cx;
  471.         v->savey = v->cy;
  472.         break;
  473.     case 'k':        /* restore saved position */
  474.         gotoxy(v, v->savex, v->savey);
  475.         break;
  476.     case 'l':        /* clear line */
  477.         clrline(v, cy);
  478.         gotoxy(v, 0, cy);
  479.         break;
  480.     case 'o':        /* clear from start of line to cursor */
  481.         clrfrom(v, 0, cy, cx, cy);
  482.         break;
  483.     case 'p':        /* reverse video on */
  484.         v->term_cattr |= CINVERSE;
  485.         break;
  486.     case 'q':        /* reverse video off */
  487.         v->term_cattr &= ~CINVERSE;
  488.         break;
  489.     case 't':        /* TW extension: set cursor timer */
  490.         v->flashtimer = v->flashperiod = 0;
  491.         v->output = timer_putch;
  492.         curs_on(v);
  493.         return;
  494.     case 'u':        /* TW extension: cursor flashing OFF */
  495.         v->flashtimer = v->flashperiod = 0;
  496.         break;
  497.     case 'v':        /* wrap on */
  498.         v->term_flags |= FWRAP;
  499.         break;
  500.     case 'w':
  501.         v->term_flags &= ~FWRAP;
  502.         break;
  503.     case 'y':        /* TW extension: set special effects */
  504.         v->output = seffect_putch;
  505.         curs_on(v);
  506.         return;
  507.     case 'z':        /* TW extension: clear special effects */
  508.         v->output = ceffect_putch;
  509.         curs_on(v);
  510.         return;
  511.     }
  512.     v->output = vt52_putch;
  513.     curs_on(v);
  514. }
  515.  
  516. /*
  517.  * escy1_putch(v, c): for when an ESC Y + char has been seen
  518.  */
  519.  
  520. static void
  521. escy1_putch(v, c)
  522.     TEXTWIN *v;
  523.     int c;
  524. {
  525.     static void vt52_putch();
  526.  
  527.     curs_off(v);
  528.     gotoxy(v, c - ' ', v->miny + v->escy1 - ' ');
  529.     v->output = vt52_putch;
  530.     curs_on(v);
  531. }
  532.  
  533. /*
  534.  * escy_putch(v, c): for when an ESC Y has been seen
  535.  */
  536. static void
  537. escy_putch(v, c)
  538.     TEXTWIN *v;
  539.     int c;
  540. {
  541.     curs_off(v);
  542.     v->escy1 = c;
  543.     v->output = escy1_putch;
  544.     curs_on(v);
  545. }
  546.  
  547. /*
  548.  * vt52_putch(v, c): put character 'c' on screen 'v'. This is the default
  549.  * for when no escape, etc. is active
  550.  */
  551.  
  552. void
  553. vt52_putch(v, c)
  554.     TEXTWIN *v;
  555.     int c;
  556. {
  557.     int cx, cy;
  558.  
  559.     cx = v->cx; cy = v->cy;
  560.     curs_off(v);
  561.  
  562.     c &= 0x00ff;
  563.  
  564. /* control characters */
  565.     if (c < ' ') {
  566.         switch (c) {
  567.         case '\r':
  568.             gotoxy(v, 0, cy);
  569.             curs_on(v);
  570.             return;
  571.         case '\n':
  572.             if (cy == v->maxy - 1) {
  573.                 curs_off(v);
  574.                 scroll(v);
  575.             }
  576.             else
  577.                 gotoxy(v, cx, cy+1);
  578.             curs_on(v);
  579.             return;
  580.         case '\b':
  581.             gotoxy(v, cx-1, cy);
  582.             curs_on(v);
  583.             return;
  584.         case '\007':        /* BELL */
  585.             (void)Bconout(2, 7);
  586.             curs_on(v);
  587.             return;
  588.         case '\033':        /* ESC */
  589.             v->output = putesc;
  590.             curs_on(v);
  591.             return;
  592.         case '\t':
  593.             gotoxy(v, (v->cx +8) & ~7, v->cy); 
  594.             /* fall through */
  595.         default:
  596.             curs_on(v);
  597.             return;
  598.         }
  599.     }
  600.  
  601.     paint(v, c);
  602.     v->cx++;
  603.     if (v->cx == v->maxx) {
  604.         if (v->term_flags & FWRAP) {
  605.             v->cx = 0;
  606.             vt52_putch(v, '\n');
  607.         } else {
  608.             v->cx = v->maxx - 1;
  609.         }
  610.     }
  611.     curs_on(v);
  612. }
  613.  
  614. /* routines for setting the cursor state in window v */
  615.  
  616. void
  617. set_curs(v, on)
  618.     TEXTWIN *v;
  619.     int on;
  620. {
  621.     if (on && (v->term_flags & FCURS) && !(v->term_flags & FFLASH)) {
  622.         if (focuswin && v == focuswin->extra)
  623.             v->cflag[v->cy][v->cx] ^= CINVERSE;
  624.         else
  625.             v->cflag[v->cy][v->cx] ^= CE_UNDERLINE;
  626.         v->cflag[v->cy][v->cx] |= CTOUCHED;
  627.         v->dirty[v->cy] |= SOMEDIRTY;
  628.         v->term_flags |= FFLASH;
  629.     } else if ( (!on) && (v->term_flags & FFLASH)) {
  630.         if (focuswin && v == focuswin->extra)
  631.             v->cflag[v->cy][v->cx] ^= CINVERSE;
  632.         else
  633.             v->cflag[v->cy][v->cx] ^= CE_UNDERLINE;
  634.         v->cflag[v->cy][v->cx] |= CTOUCHED;
  635.         v->dirty[v->cy] |= SOMEDIRTY;
  636.         v->term_flags &= ~FFLASH;
  637.     }
  638.     v->flashtimer = v->flashperiod;
  639. }
  640.  
  641. /* flash the cursor in the indicated window */
  642.  
  643. void
  644. curs_flash(v)
  645.     TEXTWIN *v;
  646. {
  647.     if (v->term_flags & FCURS) {
  648.         if (focuswin && v == focuswin->extra)
  649.             v->cflag[v->cy][v->cx] ^= CINVERSE;
  650.         else
  651.             v->cflag[v->cy][v->cx] ^= CE_UNDERLINE;
  652.         v->dirty[v->cy] |= SOMEDIRTY;
  653.         v->cflag[v->cy][v->cx] |= CTOUCHED;
  654.         v->term_flags ^= FFLASH;
  655.     }
  656.     v->flashtimer = v->flashperiod;
  657. }
  658.