home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR10 / MINCOM15.ZIP / WINDOW.C < prev    next >
C/C++ Source or Header  |  1993-10-14  |  35KB  |  1,777 lines

  1. /*
  2.  * window.c    Very portable window routines.
  3.  *        Currently this code is used in _both_ the BBS
  4.  *        system and minicom.
  5.  *
  6.  * Author:    Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
  7.  * 
  8.  */
  9.  
  10. #include <sys/types.h>
  11. #if defined(_MINIX) || defined(linux)
  12. #  include <termcap.h>
  13. #else
  14. char *tgetstr(), *tgoto();
  15. int tgetent(), tputs(), tgetnum(), tgetflag();
  16. #endif
  17. #include <string.h>
  18. #if defined (_POSIX_SOURCE) || defined(_BSD43)
  19. #  include <stdlib.h>
  20. #  include <unistd.h>
  21. #else
  22.   char *getenv();
  23. #endif
  24. #include "charmap.h"
  25.  
  26. /* Don't want to include all header stuff for three prototypes from sysdep.c */
  27. #if __STDC__
  28.   int setcbreak(int);
  29.   int getch(void);
  30.   void getrowcols(int *rows, int *cols);
  31. #else
  32.   int setcbreak();
  33.   int getch();
  34.   void getrowcols();
  35. #endif
  36.  
  37. #if 0 /* Should use it in wprintf */
  38. #ifdef _MINIX
  39. #  include <stdarg.h>
  40. #else
  41. #  include <varargs.h>
  42. #endif
  43. #endif
  44.  
  45. #include <stdio.h>
  46. #include <signal.h>
  47. #include "window.h"
  48. #ifndef BBS
  49. #include "config.h"
  50. #endif
  51.  
  52. #define BUFFERSIZE 2048
  53.  
  54. #define swap(x, y) { int d = (x); (x) = (y); (y) = d; }
  55.  
  56. /* Terminal capabilities */
  57. static char *CM, *IS, *RS;
  58. static char *ME, *SE, *UE, *AE;
  59. static char *AS, *MB, *MD, *MR, *SO, *US;
  60. static char *CE, *Al, *Dl, *AL, *DL;
  61. static char *CS, *SF, *SR, *VB;
  62. static char *VE, *VI, *KS, *KE;
  63. static char *CD, *CL, *IC, *DC;
  64. static char *BC, *CR, *NL;
  65.  
  66. /* Special characters */
  67. static char D_UL;
  68. static char D_HOR;
  69. static char D_UR;
  70. static char D_LL;
  71. static char D_VER;
  72. static char D_LR;
  73.  
  74. static char S_UL;
  75. static char S_HOR;
  76. static char S_UR;
  77. static char S_LL;
  78. static char S_VER;
  79. static char S_LR;
  80.  
  81. static char _bufstart[BUFFERSIZE];
  82. static char *_bufpos = _bufstart;
  83. static char *_buffend;
  84. static ELM *gmap;
  85.  
  86. static char curattr = -1;
  87. static char curcolor = -1;
  88. static int curx = -1;
  89. static int cury = -1;
  90. static int _intern = 0;
  91. static int _curstype = CNORMAL;
  92. static int _has_am = 0;
  93. static int _mv_standout = 0;
  94. static ELM oldc;
  95. static int sflag = 0;
  96.  
  97. /*
  98.  * Smooth is only defined for slow machines running Minicom.
  99.  * With this defined, Minicom will buffer only per-line
  100.  * and the output will look much less 'jerky'. (I hope :-)
  101.  */
  102. #ifdef SMOOTH
  103. static WIN *curwin = NIL_WIN;
  104. extern WIN *us;
  105. #endif
  106.  
  107. int useattr = 1;
  108. int dirflush = 1;
  109. int LINES, COLS;
  110. int usecolor = 0;
  111. WIN *stdwin;
  112. char *_tptr = CNULL;
  113. int literal = 0;
  114. int w_init = 0;
  115.  
  116. #if DEBUG
  117.  
  118. /*
  119.  * Debug to stdout
  120.  */
  121. int debug(s, a1, a2, a3, a4)
  122. char *s;
  123. int a1, a2, a3, a4;
  124. {
  125.   char lala[80];
  126.  
  127.   sprintf(lala, s, a1, a2, a3, a4);
  128.   write(2, lala, strlen(lala));
  129.   return(0);
  130. }
  131. #endif
  132.  
  133. /* ===== Low level routines ===== */
  134.  
  135. /*
  136.  * Flush the screen buffer
  137.  */
  138. void wflush()
  139. {
  140.   register int todo, done;
  141.  
  142.   todo = _bufpos - _bufstart;
  143.   _bufpos = _bufstart;
  144.  
  145.   while(todo > 0) {
  146.       done = write(1, _bufpos, todo);
  147.       if (done > 0) {
  148.           todo -= done;
  149.           _bufpos += done;
  150.       }
  151.   }
  152.   _bufpos = _bufstart;
  153. }
  154.  
  155. /*
  156.  * Output a raw character to the screen
  157.  */
  158. static int outchar(c)
  159. int c;
  160. {
  161.   *_bufpos++ = c;
  162.   if (_bufpos >= _buffend) wflush();
  163. #if defined(SMOOTH)
  164.   if (curwin == us && (c == '\n' || c == '\r')) wflush();
  165. #endif
  166.   return(0);
  167. }
  168.  
  169. /*
  170.  * Output a raw string to the screen.
  171.  */
  172. static void outstr(s)
  173. char *s;
  174. {
  175. #ifdef _MINIX
  176.   while(*s) (void) outchar (*s++);
  177. #else
  178.   tputs(s, 1, outchar);
  179. #endif
  180. }
  181.  
  182.  
  183. /*
  184.  * Turn off all attributes
  185.  */
  186. static void _attroff()
  187. {
  188.   if (ME != CNULL)
  189.       outstr(ME);
  190.   else {
  191.       if (SE != CNULL) outstr(SE);
  192.       if (UE != CNULL) outstr(UE);
  193.   }
  194.   if (AE != CNULL) outstr(AE);
  195. }
  196.  
  197. /*
  198.  * Turn some attributes on
  199.  */
  200. static void _attron(attr)
  201. char attr;
  202. {
  203.   if (!usecolor || (attr & A_REVERSE) == 0) {
  204.     /* Reverse standout does not look too good.. */
  205.     if (attr & A_BOLD    && MD != CNULL)  outstr(MD);
  206.       if (attr & A_STANDOUT   && SO != CNULL)  outstr(SO);
  207.     if (attr & A_UNDERLINE  && US != CNULL)  outstr(US);
  208.   }
  209.   if (attr & A_REVERSE      && MR != CNULL)  outstr(MR);
  210.   if (attr & A_ALTCHARSET && AS != CNULL)  outstr(AS);
  211.   if (attr & A_BLINK      && MB != CNULL)  outstr(MB);
  212. }
  213.  
  214. /*
  215.  * Set the colors
  216.  */
  217. static void _colson(color)
  218. char color;
  219. {
  220.   char buf[12];
  221.   sprintf(buf, "\033[%d;%dm", COLFG(color) + 30, COLBG(color) + 40);
  222.   outstr(buf);
  223. }
  224.   
  225. /*
  226.  * Set global attributes, if different.
  227.  */
  228. static void _setattr(attr, color)
  229. char attr, color;
  230. {
  231.   if (!useattr) return;
  232.  
  233.   if (!usecolor) {
  234.       curcolor = color;
  235.       if (attr == curattr) return;
  236.       curattr = attr;
  237.       _attroff();
  238.       _attron(attr);
  239.       return;
  240.   }
  241.   if (attr == curattr && color == curcolor) return;
  242.   _attroff();
  243.   _colson(color);
  244.   _attron(attr);
  245.   curattr = attr;
  246.   curcolor = color;
  247. }
  248.  
  249. /*
  250.  * Goto (x, y) in stdwin
  251.  */
  252. static void _gotoxy(x, y)
  253. int x, y;
  254. {
  255.   register oldattr = -1;
  256.  
  257.   if (x < COLS && y < LINES && (x != curx || y != cury)) {
  258.       if (!_mv_standout && curattr != A_NORMAL) {
  259.           oldattr = curattr;
  260.           _setattr(A_NORMAL, curcolor);
  261.       }
  262.       if (CR != CNULL && y == cury && x == 0)
  263.           outstr(CR);
  264. #if 0 /* Hmm, sometimes NL only works in the first column */
  265.     else if (NL != CNULL && x == curx && y == cury + 1)
  266.         outstr(NL);
  267. #else
  268.     else if (NL != CNULL && x == 0 && x == curx && y == cury + 1)
  269.         outstr(NL);
  270. #endif
  271.       else if (BC != CNULL && y == cury && x == curx - 1)
  272.           outstr(BC);
  273.       else    
  274.           outstr(tgoto(CM, x, y));
  275.       curx = x;
  276.       cury = y;
  277.       if (oldattr != -1) _setattr(oldattr, curcolor);
  278.   } 
  279. }
  280.  
  281. /*
  282.  * Write a character in stdwin at x, y with attr & color
  283.  * 'doit' can be  -1: only write to screen, not to memory
  284.  *                 0: only write to memory, not to screen
  285.  *                 1: write to both screen and memory
  286.  */
  287. static void _write(c, doit, x, y,attr, color)
  288. int c, doit;
  289. int x, y;
  290. char attr, color;
  291. {
  292.   register ELM *e;
  293.  
  294.   /* If the terminal has automatic margins, we can't write to the
  295.    * last line, last character. After scrolling, this "invisible"
  296.    * character is automatically restored.
  297.    */
  298.   if (_has_am && y >= LINES - 1 && x >= COLS - 1) {
  299.       doit = 0;
  300.       sflag = 1;
  301.       oldc.value = c;
  302.       oldc.attr = attr;
  303.       oldc.color = color;
  304.   }
  305.   if (x < COLS && y < LINES) {
  306.      if (doit != 0) {
  307.       _gotoxy(x, y);
  308.       _setattr(attr, color);
  309. #ifdef _ACK
  310.     c &= 0xFF;
  311. #endif
  312.     (void) outchar(literal ? c : wcharmap[(unsigned char)c]);
  313.     curx++;
  314.      }
  315.      if (doit >= 0) {
  316.     e = &gmap[x + y * COLS];
  317.     e->value = c;
  318.     e->attr = attr;
  319.     e->color = color;
  320.      }
  321.   }
  322. }
  323.  
  324. /*
  325.  * Set cursor type.
  326.  */
  327. static void _cursor(type)
  328. int type;
  329. {
  330.   _curstype = type;
  331.  
  332.   if (type == CNORMAL && VE != CNULL) outstr(VE);
  333.   if (type == CNONE && VE != CNULL && VI != CNULL) outstr(VI);
  334. }
  335.  
  336.  
  337. /* ==== High level routines ==== */
  338.  
  339.  
  340. #if 0
  341. /* This code is functional, but not yet used.
  342.  * It might be one day....
  343.  */
  344. /*
  345.  * Resize a window
  346.  */
  347. void wresize(win, lines, cols)
  348. WIN *win;
  349. int lines, cols;
  350. {
  351.   int x, y;
  352.   ELM *oldmap, *newmap, *e, *n;
  353.  
  354.   if ((newmap = (ELM *)malloc(lines * cols * sizeof(ELM))) == (ELM *)NULL)
  355.     return;
  356.   if (win == stdwin)
  357.     oldmap = gmap;
  358.   else
  359.     oldmap = win->map;
  360.  
  361.   for(y = 0; y < lines; y++)
  362.     for(x = 0; x < cols; x++) {
  363.         n = &newmap[y + x * cols];
  364.         if (x < win->xs && y < win->ys) {
  365.             e = &oldmap[y + x * COLS];
  366.             n->value = e->value;
  367.             n->color = e->color;
  368.             n->attr = e->attr;
  369.         } else {
  370.             n->value = ' ';
  371.             n->color = win->color;
  372.             n->attr = win->attr;
  373.         }
  374.     }
  375.   if (win->sy2 == win->y2) win->sy2 = win->y1 + lines - 1;
  376.   win->y2 = win->y1 + lines - 1;
  377.   win->ys = lines;
  378.   win->xs = cols;
  379.   free(oldmap);
  380.   if (win == stdwin) {
  381.     gmap = newmap;
  382.     LINES = lines;
  383.     COLS = cols;
  384.   } else
  385.     win->map = newmap;
  386. }
  387. #endif
  388.  
  389. /*
  390.  * Create a new window.
  391.  */
  392. /*ARGSUSED*/
  393. WIN *wopen(x1, y1, x2, y2, border, attr, fg, bg, direct, histlines, rel)
  394. int x1, y1, x2, y2;
  395. int border;
  396. int attr, fg, bg, direct;
  397. int histlines;
  398. int rel;
  399. {
  400.   WIN *w;
  401.   ELM *e;
  402.   int bytes;
  403.   int x, y;
  404.   int color;
  405.   int offs;
  406.   int doclr = 1;        /* Could later be added as argument to func */
  407. #ifdef SMOOTH
  408.   curwin = NIL_WIN;
  409. #endif
  410.  
  411.   if ((w = (WIN *)malloc(sizeof(WIN))) == (WIN *)0) return(w);
  412.   
  413.   offs = (border != BNONE);
  414.  
  415.   if (x1 < offs) x1 = offs;
  416.   if (y1 < offs) y1 = offs;
  417. #if 0
  418.   if (x2 >= COLS - offs) x2 = COLS - offs - 1;
  419.   if (y2 >= LINES - offs) y2 = LINES - offs - 1;
  420. #endif
  421.   if (x1 > x2) swap(x1, x2);
  422.   if (y1 > y2) swap(y1, y2);
  423.  
  424.   w->xs = x2 - x1 + 1;
  425.   w->ys = y2 - y1 + 1;
  426.   w->x1 = x1;
  427.   w->x2 = x2;
  428.   w->y1 = w->sy1 = y1;
  429.   w->y2 = w->sy2 = y2;
  430.   w->doscroll = 1;
  431.   w->border = border;
  432.   w->cursor = CNORMAL;
  433.   w->attr = attr;
  434.   w->autocr = 1;
  435.   w->wrap = 1;
  436.   color = w->color = COLATTR(fg, bg);
  437.   w->curx = 0;
  438.   w->cury = 0;
  439.  
  440.   w->o_curx = curx;
  441.   w->o_cury = cury;
  442.   w->o_attr = curattr;
  443.   w->o_color = curcolor;
  444.   w->o_cursor = _curstype;
  445.   w->direct = direct;
  446.  
  447.   if (border != BNONE) {
  448.       x1--; x2++;
  449.       y1--; y2++;
  450.   }
  451.   /* Store whatever we are overlapping */
  452.   bytes = (y2 - y1 + 1) * (x2 - x1 + 1) * sizeof(ELM) + 100;
  453.   if ((e = (ELM *)malloc(bytes)) == (ELM *)0) {
  454.       free(w);
  455.       return((WIN *)0);
  456.   }
  457.   w->map = e;
  458.   /* How many bytes is one line */
  459.   bytes = (x2 - x1 + 1) * sizeof(ELM);
  460.   /* Loop */
  461.   for(y = y1; y <= y2; y++) {
  462.       memcpy(e, gmap + COLS * y + x1, bytes);
  463.       e += (x2 - x1 + 1);
  464.   }
  465.   
  466. #if HISTORY
  467.   /* Do we want history? */
  468.   w->histline = w->histlines = 0;
  469.   w->histbuf = (ELM *)0;
  470.   if (histlines) {
  471.     /* Reserve some memory. */
  472.     bytes = w->xs * histlines * sizeof(ELM);
  473.     if ((w->histbuf = (ELM *)malloc(bytes)) == NULL) {
  474.         free(w->map);
  475.         free(w);
  476.         return((WIN *)0);
  477.     }
  478.     w->histlines = histlines;
  479.  
  480.     /* Clear the history buf. */
  481.     e = w->histbuf;
  482.     for(y = 0; y < w->xs * histlines; y++) {
  483.         e->value = ' ';
  484.         e->attr = attr;
  485.         e->color = color;
  486.         e++;
  487.     }
  488.   }
  489. #endif
  490.  
  491.   /* And draw the window */
  492.   if (border) {
  493.     _write(border == BSINGLE ? S_UL : D_UL, w->direct, x1, y1,
  494.                     attr, color);
  495.     for(x = x1 + 1; x < x2; x++)
  496.         _write(border == BSINGLE ? S_HOR : D_HOR, w->direct, x, y1,
  497.                     attr, color);
  498.     _write(border == BSINGLE ? S_UR : D_UR, w->direct, x2, y1,
  499.                     attr, color);
  500.     for(y = y1 + 1; y < y2; y++) {
  501.         _write(border == BSINGLE ? S_VER : D_VER, w->direct, x1, y,
  502.                     attr, color);
  503.         for(x = x1 + 1; x < x2; x++)
  504.             _write(' ', w->direct, x, y, attr, color);
  505.         _write(border == BSINGLE ? S_VER : D_VER, w->direct, x2, y,
  506.                     attr, color);
  507.     }
  508.     _write(border == BSINGLE ? S_LL : D_LL, w->direct, x1, y2,
  509.                     attr, color);
  510.     for(x = x1 + 1; x < x2; x++)
  511.         _write(border == BSINGLE ? S_HOR : D_HOR, w->direct,
  512.                     x, y2, attr, color);
  513.     _write(border == BSINGLE ? S_LR : D_LR, w->direct, x2, y2,
  514.                     attr, color);
  515.     if (w->direct) _gotoxy(x1 + 1, y1 + 1);
  516.   } else
  517.       if (doclr) winclr(w);
  518.   wcursor(w, CNORMAL);    
  519.  
  520.   if (w->direct) wflush();
  521.   return(w);
  522. }
  523.  
  524. /*
  525.  * Close a window.
  526.  */
  527. void wclose(win, replace)
  528. WIN *win;
  529. int replace;
  530. {
  531.   register ELM *e;
  532.   register int x, y;
  533.  
  534. #ifdef SMOOTH
  535.   curwin = NIL_WIN;
  536. #endif
  537.  
  538.   if (win == stdwin) {
  539.       win_end();
  540.       return;
  541.   }
  542.   e = win->map;
  543.  
  544.   if (win->border) {
  545.       win->x1--; win->x2++;
  546.       win->y1--; win->y2++;
  547.   }
  548.   wcursor(win, win->o_cursor);
  549.   if (replace) {
  550.     for(y = win->y1; y <= win->y2; y++) {
  551.           for(x = win->x1; x <= win->x2; x++) {
  552.               _write(e->value, 1, x, y, e->attr, e->color);
  553.               e++;
  554.           }
  555.      }
  556.     _gotoxy(win->o_curx, win->o_cury);
  557.     _setattr(win->o_attr, win->o_color);
  558.   }
  559.   free(win->map);
  560.   free(win);
  561. #if HISTORY
  562.   if (win->histbuf) free(win->histbuf);
  563. #endif
  564.   wflush();
  565. }
  566.  
  567. static int oldx, oldy;
  568. static int ocursor;
  569.  
  570. /*
  571.  * Clear screen & restore keyboard modes
  572.  */
  573. void wleave()
  574. {
  575.   oldx = curx;
  576.   oldy = cury;
  577.   ocursor = _curstype;
  578.  
  579.   (void) setcbreak(0); /* Normal */
  580.   _gotoxy(0, LINES - 1);
  581.   _setattr(A_NORMAL, COLATTR(WHITE, BLACK));
  582.   _cursor(CNORMAL);
  583.   if (CL != CNULL)
  584.     outstr(CL);
  585.   else
  586.     outstr("\n");
  587.   if (KE != CNULL) outstr(KE);
  588.   if (RS != CNULL) outstr(RS);
  589.   wflush();
  590. }
  591.  
  592. void wreturn()
  593. {
  594.   int x, y;
  595.   ELM *e;
  596.  
  597. #ifdef SMOOTH
  598.   curwin = NIL_WIN;
  599. #endif
  600.  
  601.   curattr = -1;
  602.   curcolor = -1;
  603.  
  604.   (void) setcbreak(1); /* Cbreak, no echo */
  605.  
  606.   if (KS != CNULL) outstr(KS); /* Keypad mode */
  607.   if (IS != CNULL) outstr(IS); /* Initialization string */
  608.   
  609.   _gotoxy(0, 0);
  610.   _cursor(ocursor);
  611.  
  612.   e = gmap;
  613.   for(y = 0; y <LINES; y++) {
  614.       for(x = 0; x < COLS; x++) {
  615.           _write(e->value, -1, x, y, e->attr, e->color);
  616.           e++;
  617.       }
  618.   }
  619.   _gotoxy(oldx, oldy);
  620.   wflush();
  621. }
  622.  
  623. /*
  624.  * Redraw the whole window.
  625.  */
  626. void wredraw(w, newdirect)
  627. WIN *w;
  628. int newdirect;
  629. {
  630.   int minx, maxx, miny, maxy;
  631.   register ELM *e;
  632.   register int x, y;
  633.   int addcnt;
  634.  
  635.   minx = w->x1;
  636.   maxx = w->x2;
  637.   miny = w->y1;
  638.   maxy = w->y2;
  639.   addcnt = stdwin->xs - w->xs;
  640.  
  641.   if (w->border) {
  642.       minx--;
  643.       maxx++;
  644.       miny--;
  645.       maxy++;
  646.       addcnt -= 2;
  647.   }
  648.  
  649.   _cursor(CNONE);
  650.   e = gmap + (miny * stdwin->xs) + minx;
  651.  
  652.   for(y = miny; y <= maxy; y++) {
  653.       for(x = minx; x <= maxx; x++) {
  654.           _write(e->value, -1, x, y, e->attr, e->color);
  655.           e++;
  656.       }
  657.       e += addcnt;
  658.   }
  659.   _cursor(w->cursor);
  660.   _gotoxy(w->x1 + w->curx, w->y1 + w->cury);
  661.   wflush();
  662.   w->direct = newdirect;
  663. }
  664.  
  665. /*
  666.  * Clear to end of line, low level.
  667.  */
  668. static int _wclreol(w)
  669. WIN *w;
  670. {
  671.   register x;
  672.   register doit = 1;
  673.   register y;
  674.   
  675. #ifdef SMOOTH
  676.   curwin = w;
  677. #endif
  678.   y = w->cury + w->y1;
  679.  
  680.   if (w->direct && (w->x2 == COLS - 1) && CE) {
  681.       _gotoxy(w->curx + w->x1, y);
  682.       _setattr(w->attr, w->color);
  683.       outstr(CE);
  684.       doit = 0;
  685.   }
  686.   for(x = w->curx + w->x1; x <= w->x2; x++)
  687.       _write(' ', w->direct && doit, x, y, w->attr, w->color);
  688.   return(doit);    
  689. }
  690.  
  691. /*
  692.  * Scroll a window.
  693.  */
  694. void wscroll(win, dir)
  695. WIN *win;
  696. int dir;
  697. {
  698.   register ELM *e, *f;
  699.   register char *src, *dst;
  700.   register int x, y;
  701.   register int doit = 1;
  702.   int ocurx, fs = 0, len;
  703.   int phys_scr = 0;
  704.  
  705. #ifdef SMOOTH
  706.   curwin = win;
  707. #endif
  708.  
  709.   /*
  710.    * If the window *is* the physical screen, we can scroll very simple.
  711.    * This improves performance on slow screens (eg ATARI ST) dramatically.
  712.    */
  713.   if (win->direct && SF != CNULL &&
  714.       (dir == S_UP || SR != CNULL) && (LINES == win->sy2 - win->sy1 + 1)) {
  715.       doit = 0;
  716.       phys_scr = 1;
  717.       _setattr(win->attr, win->color);
  718.       if (dir == S_UP) {
  719.           _gotoxy(0, LINES - 1);
  720.           outstr(SF);
  721.       } else {
  722.           _gotoxy(0, 0);
  723.           outstr(SR);
  724.       }
  725.   }
  726.   /*
  727.    * If the window is as wide as the physical screen, we can
  728.    * scroll it with insert/delete line (or set scroll region - vt100!)
  729.    */
  730.   else if (win->direct && win->xs == COLS &&
  731.           ((CS != CNULL && SF != CNULL && SR != CNULL)
  732.           || (Dl != CNULL && Al != CNULL))) {
  733.       doit = 0;
  734.       phys_scr = 1;
  735.       _setattr(win->attr, win->color);
  736.       if (CS != CNULL && SF != CNULL && SR != CNULL) { /* Scrolling Region */
  737.         /* If the scroll region we want to initialize already is as
  738.          * big as the physical screen, we don't _have_ to
  739.          * initialize it.
  740.          */
  741.           if (win->sy2 == LINES - 1 && win->sy1 == 0) fs = 1;
  742.           if (!fs) {
  743.               outstr(tgoto(CS, win->sy2, win->sy1));
  744.               cury = 0;
  745.           }    
  746.           if (dir == S_UP) {
  747.                _gotoxy(0, win->sy2);
  748.                outstr(SF);
  749.           } else {
  750.                _gotoxy(0, win->sy1);
  751.                outstr(SR);
  752.           }
  753.           if (!fs) {
  754.               outstr(tgoto(CS, LINES - 1, 0));
  755.               cury = 0;
  756.           }    
  757.           _gotoxy(0, win->sy2);
  758.       } else { /* Use insert/delete line */
  759.           if (dir == S_UP) {
  760.               _gotoxy(0, win->sy1);
  761.               outstr(Dl);
  762.               _gotoxy(0, win->sy2);
  763.               outstr(Al);
  764.           } else {
  765.               _gotoxy(0, win->sy2);
  766.               outstr(Dl);
  767.               _gotoxy(0, win->sy1);
  768.               outstr(Al);
  769.           }
  770.       }
  771.   }
  772.  
  773.   /* If a terminal has automatic margins, we can't write
  774.    * to the lower right. After scrolling we have to restore
  775.    * the non-visible character that is now visible.
  776.    */
  777.   if (sflag && win->sy2 == (LINES - 1) && win->sy1 != win->sy2) {
  778.       if (dir == S_UP) {
  779.           _write(oldc.value, 1, COLS - 1, LINES - 2,
  780.               oldc.attr, oldc.color);
  781.       }
  782.       sflag = 0;
  783.   }
  784.  
  785.   ocurx = win->curx;
  786.  
  787. #if HISTORY
  788.   /* If this window has a history buf, see if we want to use it. */
  789.   if (win->histbuf && dir == S_UP &&
  790.     win->sy2 == win->y2 && win->sy1 == win->y1) {
  791.  
  792.     /* Calculate screen buffer */
  793.       e = gmap + win->y1 * COLS + win->x1;
  794.  
  795.     /* Calculate history buffer */
  796.     f = win->histbuf + (win->xs * win->histline);
  797.  
  798.     /* Copy line from screen to history buffer */
  799.     memcpy((char *)f, (char *)e, win->xs * sizeof(ELM));
  800.  
  801.     /* Postion the next line in the history buffer */
  802.     win->histline++;
  803.     if (win->histline >= win->histlines) win->histline = 0;
  804.   }
  805. #endif
  806.  
  807.   /* If the window is screen-wide and has no border, there
  808.    * is a much simpler & FASTER way of scrolling the memory image !!
  809.    */
  810.   if (phys_scr) {
  811.       len = (win->sy2 - win->sy1) * win->xs * sizeof(ELM);
  812.       if (dir == S_UP)  {
  813.           dst = (char *)&gmap[0];                /* First line */
  814.           src = (char *)&gmap[win->xs];            /* Second line */
  815.           win->cury = win->sy2 - win->y1;
  816.       } else {
  817.           src = (char *)&gmap[0];                /* First line */
  818.           dst = (char *)&gmap[win->xs];            /* Second line */
  819.           win->cury = win->sy1 - win->y1;
  820.       }
  821.       /* memmove copies len bytes from src to dst, even if the
  822.        * objects overlap.
  823.        */
  824.       fflush(stdout);
  825. #ifdef _SYSV
  826.       memcpy((char *)dst, (char *)src, len);
  827. #else
  828.       memmove((char *)dst, (char *)src, len);
  829. #endif
  830.   } else {
  831.     /* Now scroll the memory image. */
  832.       if (dir == S_UP) {
  833.           for(y = win->sy1 + 1; y <= win->sy2; y++) {
  834.               e = gmap + y * COLS + win->x1;
  835.               for(x = win->x1; x <= win->x2; x++) {
  836.                  _write(e->value, win->direct && doit,
  837.                          x, y - 1, e->attr, e->color);
  838.                  e++;
  839.               }
  840.           }
  841.           win->curx = 0;
  842.           win->cury = win->sy2 - win->y1;
  843.           if (doit) (void) _wclreol(win);
  844.       } else {
  845.           for(y = win->sy2 - 1; y >= win->sy1; y--) {
  846.               e = gmap + y * COLS + win->x1;
  847.               for(x = win->x1; x <= win->x2; x++) {
  848.                  _write(e->value, win->direct && doit,
  849.                          x, y + 1, e->attr, e->color);
  850.                  e++;
  851.               }
  852.           }
  853.           win->curx = 0;
  854.           win->cury = win->sy1 - win->y1;
  855.           if (doit) (void) _wclreol(win);
  856.       }
  857.   }
  858.  
  859.   win->curx = ocurx;
  860.  
  861.   if (!doit) for(x = win->x1; x <= win->x2; x++)
  862.         _write(' ', 0, x, win->y1 + win->cury, win->attr, win->color);
  863.   if (!_intern && win->direct)
  864.       _gotoxy(win->x1 + win->curx, win->y1 + win->cury);
  865.   if (dirflush && !_intern && win->direct) wflush();
  866. }
  867.  
  868. /*
  869.  * Locate the cursor in a window.
  870.  */
  871. void wlocate(win, x, y)
  872. WIN *win;
  873. int x, y;
  874. {
  875.   if (x < 0) x = 0;
  876.   if (y < 0) y = 0;
  877.   if (x >= win->xs) x = win->xs - 1;
  878.   if (y >= win->ys) y = win->ys - 1;
  879.  
  880.   win->curx = x;
  881.   win->cury = y;
  882.   if (win->direct) _gotoxy(win->x1 + x, win->y1 + y);
  883.  
  884.   if (dirflush) wflush();
  885. }
  886.  
  887. /*
  888.  * Print a character in a window.
  889.  */
  890. void wputc(win, c)
  891. WIN *win;
  892. int c;
  893. {
  894.   register mv = 0;
  895.  
  896. #ifdef SMOOTH
  897.   curwin = win;
  898. #endif
  899.  
  900.   switch(c) {
  901.       case '\r':
  902.           win->curx = 0;
  903.           mv++;
  904.           break;
  905.       case '\n':
  906.           win->cury++;
  907.           if (win->autocr) win->curx = 0;
  908.           mv++;
  909.           break;
  910.       case '\b':
  911.           if (win->curx == 0) break;
  912.           win->curx--;
  913.           mv++;
  914.           break;
  915.       case '\007':
  916.           wbell();
  917.           break;
  918.       case '\t':
  919.           do {
  920.               wputc(win, ' '); /* Recursion! */
  921.           } while(win->curx % 8);
  922.           break;
  923.       default:
  924.         _write(c, win->direct, win->curx + win->x1,
  925.             win->cury + win->y1, win->attr, win->color);
  926.           if (++win->curx >= win->xs) {
  927.               if (win->wrap) {
  928.                   win->curx = 0;
  929.                   win->cury++;
  930.               } else {
  931.                   win->curx--;    
  932.                   curx = 0; /* Force to move */
  933.               }
  934.               mv++;
  935.           }
  936.           break;
  937.   }
  938.   if (mv) {
  939.     if (win->cury == win->sy2 - win->y1 + 1) {
  940.           if (win->doscroll)
  941.               wscroll(win, S_UP);
  942.           else
  943.               win->cury = win->sy1 - win->y1;
  944.     }
  945.     if (win->cury >= win->ys) win->cury = win->ys - 1;
  946.       if (win->direct) _gotoxy(win->x1 + win->curx, win->y1 + win->cury);
  947.   }
  948.   if (win->direct && dirflush && !_intern) wflush();
  949. }
  950.  
  951. /* Draw one line in a window */
  952. void wdrawelm(w, y, e)
  953. WIN *w;
  954. int y;
  955. ELM *e;
  956. {
  957.   int x;
  958.  
  959.   for(x = w->x1; x < w->x2; x++) {
  960.     _write(e->value, w->direct, x,
  961.         y + w->y1, e->attr, e->color);
  962.     e++;
  963.   }
  964. }
  965.  
  966. /*
  967.  * Print a string in a window.
  968.  */
  969. void wputs(win, s)
  970. WIN *win;
  971. register char *s;
  972. {
  973.   _intern = 1;
  974.  
  975.   while(*s) wputc(win, *s++);
  976.   if (dirflush && win->direct) wflush();
  977.   _intern = 0;
  978. }
  979.  
  980. /*
  981.  * Print a formatted string in a window.
  982.  * Should return stringlength - but who cares.
  983.  */
  984. /*VARARGS1*/
  985. int wprintf(win, s, a1, a2, a3, a4, a5, a6, a7, a8)
  986. WIN *win;
  987. char *s, *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
  988. {
  989.   char buf[128];
  990.   char *t;
  991.  
  992.   t = buf;
  993.  
  994.   _intern = 1;
  995.   sprintf(buf, s, a1, a2, a3, a4, a5, a6, a7, a8);
  996.   while(*t) wputc(win, *t++);
  997.   _intern = 0;
  998.   if (dirflush && win->direct) wflush();
  999.  
  1000.   return(0);
  1001. }
  1002.  
  1003. /*
  1004.  * Sound a bell.
  1005.  */
  1006. void wbell()
  1007. {
  1008.   if (VB != CNULL)
  1009.       outstr(VB);
  1010.   else
  1011.       (void) outchar('\007');
  1012.   wflush();
  1013. }
  1014.  
  1015. /*
  1016.  * Set cursor type.
  1017.  */
  1018. void wcursor(win, type)
  1019. WIN *win;
  1020. int type;
  1021. {
  1022.   win->cursor = type;
  1023.   if (win->direct) {
  1024.       _cursor(type);
  1025.     if (dirflush) wflush();
  1026.   }
  1027. }
  1028.  
  1029. void wtitle(w, pos, s)
  1030. WIN *w;
  1031. int pos;
  1032. char *s;
  1033. {
  1034.   int x;
  1035.  
  1036. #ifdef SMOOTH
  1037.   curwin = NIL_WIN;
  1038. #endif
  1039.  
  1040.   if (w->border == BNONE) return;
  1041.   
  1042.   if (pos == TLEFT) x = w->x1;
  1043.   if (pos == TRIGHT) x = w->x2 - strlen(s) - 1;
  1044.   if (pos == TMID) x = w->x1 + (w->xs - strlen(s)) / 2 - 1;
  1045.   if (x < w->x1) x = w->x1;
  1046.  
  1047.   if (x < w->x2) _write('[', w->direct, x++, w->y1 - 1, w->attr, w->color);
  1048.   while(*s && x <= w->x2) _write(*s++, w->direct, x++, w->y1 - 1,
  1049.           w->attr, w->color);
  1050.   if (x <= w->x2) _write(']', w->direct, x++, w->y1 - 1, w->attr, w->color);
  1051.  
  1052.   if (w->direct) {
  1053.       _gotoxy(w->x1 + w->curx, w->y1 + w->cury);
  1054.     if (dirflush) wflush();
  1055.   }
  1056. }
  1057.  
  1058.  
  1059. /* ==== Menu Functions ==== */
  1060.  
  1061. /*
  1062.  * Change attributes of one line of a window.
  1063.  */
  1064. void wcurbar(w, y, attr)
  1065. WIN *w;
  1066. int y;
  1067. int attr;
  1068. {
  1069.   ELM *e;
  1070.   register x;
  1071.  
  1072. #ifdef SMOOTH
  1073.   curwin = w;
  1074. #endif
  1075.  
  1076.   y += w->y1;
  1077.  
  1078.   e = gmap + y * COLS + w->x1;
  1079.   
  1080.   /* If we can't do reverse, just put a '>' in front of
  1081.    * the line. We only support A_NORMAL & A_REVERSE.
  1082.    */
  1083.   if (!useattr || MR == CNULL) {
  1084.       if (attr & A_REVERSE)
  1085.           x = '>';
  1086.       else
  1087.           x = ' ';
  1088.       _write(x, w->direct, w->x1, y, attr, e->color);
  1089.   } else {
  1090.     for(x = w->x1; x <= w->x2; x++) {
  1091.           _write(e->value, w->direct, x, y, attr, e->color);
  1092.           e++;
  1093.     }
  1094.   }
  1095.   if ((VI == CNULL || _curstype == CNORMAL) && w->direct)
  1096.       _gotoxy(w->x1, y);
  1097.   if (w->direct) wflush();
  1098. }
  1099.  
  1100. /*
  1101.  * wselect - select one of many choices.
  1102.  */
  1103. int wselect(x, y, choices, funlist, title, attr, fg, bg)
  1104. int x, y;
  1105. char **choices;
  1106. void (**funlist)();
  1107. char *title;
  1108. int attr, fg, bg;
  1109. {
  1110.   char **a = choices;
  1111.   int len = 0;
  1112.   int count = 0;
  1113.   int cur = 0;
  1114.   int c;
  1115.   WIN *w;
  1116.   int high_on = A_REVERSE | attr;
  1117.   int high_off = attr;
  1118.   
  1119.   /* first count how many, and max. width. */
  1120.  
  1121.   while(*a != CNULL) {
  1122.       count++;
  1123.       if (strlen(*a) > len) len = strlen(*a);
  1124.       a++;
  1125.   }
  1126.   if (title != CNULL && strlen(title) + 2 > len) len = strlen(title) + 2;
  1127.   if (attr & A_REVERSE) {
  1128.       high_on = attr & ~A_REVERSE;
  1129.       high_off = attr;
  1130.   }
  1131.  
  1132.   if ((w = wopen(x, y, x + len + 2, y + count - 1, BDOUBLE,
  1133.     attr, fg, bg, 0, 0, 0)) == (WIN *)0) return(-1);
  1134.   wcursor(w, CNONE);
  1135.  
  1136.   if (title != CNULL) wtitle(w, TMID, title);
  1137.  
  1138.   for(c = 0; c < count; c++) {
  1139.       wprintf(w, " %s%s", choices[c], c == count - 1 ? "" : "\n");
  1140.   }
  1141.  
  1142.   wcurbar(w, cur, high_on);
  1143.   wredraw(w, 1);
  1144.  
  1145.   while (1) {
  1146.     while((c = getch()) != 27 && c != '\n' && c!= '\r' && c != ' ') {
  1147.         if (c == K_UP || c == K_DN || c == 'j' || c == 'k')
  1148.             wcurbar(w, cur, high_off);
  1149.         switch(c) {
  1150.             case K_UP:
  1151.             case 'k':
  1152.                 cur--;
  1153.                 if (cur < 0) cur = count - 1;
  1154.                 break;
  1155.             case K_DN:
  1156.             case 'j':
  1157.                 cur++;
  1158.                 if (cur >= count) cur = 0;
  1159.                 break;
  1160.         }
  1161.         if (c == K_UP || c == K_DN || c == 'j' || c == 'k')
  1162.             wcurbar(w, cur, high_on);
  1163.     }
  1164.     wcursor(w, CNORMAL);
  1165.     if (c == ' ' || c == 27) {
  1166.         wclose(w, 1);
  1167.         return(0);
  1168.     }
  1169.     if (funlist == NIL_FUNLIST || funlist[cur] == NIL_FUN) {
  1170.         wclose(w, 1);
  1171.         return(cur + 1);
  1172.     }
  1173.     (*funlist[cur])();
  1174.     wcursor(w, CNONE);
  1175.   }
  1176. }
  1177.  
  1178.  
  1179. /* ==== Clearing functions ==== */
  1180.  
  1181. /*
  1182.  * Clear entire line.
  1183.  */
  1184. void wclrel(w)
  1185. WIN *w;
  1186. {
  1187.   int ocurx = w->curx;
  1188.   
  1189.   w->curx = 0;
  1190.   (void) _wclreol(w);
  1191.   w->curx = ocurx;
  1192.   wlocate(w, ocurx, w->cury);
  1193. }
  1194.  
  1195. /*
  1196.  * Clear to end of line.
  1197.  */
  1198. void wclreol(w)
  1199. WIN *w;
  1200. {
  1201.   if (_wclreol(w) && w->direct) _gotoxy(w->x1 + w->curx, w->y1 + w->cury);
  1202.   if (dirflush) wflush();
  1203. }
  1204.  
  1205. /*
  1206.  * Clear to begin of line
  1207.  */
  1208. void wclrbol(w)
  1209. WIN *w;
  1210. {
  1211.   register x;
  1212.   int y;
  1213.   
  1214. #ifdef SMOOTH
  1215.   curwin = w;
  1216. #endif
  1217.  
  1218.   y = w->curx + w->y1;
  1219.  
  1220.   if (w->direct) _gotoxy(w->x1, y);
  1221.   
  1222.   for(x = w->x1; x <= w->x2; x++) _write(' ', w->direct, x, y,
  1223.           w->attr, w->color);
  1224.   if (w->direct) {
  1225.       _gotoxy(w->x1 + curx, y);
  1226.     if (dirflush) wflush();
  1227.   }
  1228. }
  1229.  
  1230. /*
  1231.  * Clear to end of screen
  1232.  */
  1233. void wclreos(w)
  1234. WIN *w;
  1235. {
  1236.   register y;
  1237.   int ocurx, ocury;
  1238.   
  1239.   ocurx = w->curx;
  1240.   ocury = w->cury;
  1241.   
  1242.   w->curx = 0;
  1243.  
  1244.   for(y = w->cury + 1; y <= w->y2 - w->y1; y++) {
  1245.       w->cury = y;
  1246.       (void) _wclreol(w);
  1247.   }
  1248.   w->curx = ocurx;
  1249.   w->cury = ocury;
  1250.   if (_wclreol(w) && w->direct) _gotoxy(w->x1 + w->curx, w->y1 + w->cury);
  1251.   if (dirflush && w->direct) wflush();
  1252. }
  1253.  
  1254. /*
  1255.  * Clear to begin of screen.
  1256.  */
  1257. void wclrbos(w)
  1258. WIN *w;
  1259. {
  1260.   int ocurx, ocury;
  1261.   register y;
  1262.   
  1263.   ocurx = w->curx;
  1264.   ocury = w->cury;
  1265.   
  1266.   w->curx = 0;
  1267.   
  1268.   for(y = 0; y < ocury; y++) {
  1269.       w->cury = y;
  1270.       (void) _wclreol(w);
  1271.   }
  1272.   w->curx = ocurx;
  1273.   w->cury = ocury;
  1274.   wclrbol(w);
  1275. }
  1276.  
  1277. /*
  1278.  * Clear a window.
  1279.  */
  1280. void winclr(w)
  1281. WIN *w;
  1282. {
  1283.   register y;
  1284.   int olddir = w->direct;
  1285.  
  1286.   _setattr(w->attr, w->color);
  1287.   w->curx = 0;
  1288.  
  1289.   if (CL && w->y1 == 0 && w->y2 == LINES-1 &&
  1290.             w->x1 == 0 && w->x2 == COLS-1) {
  1291.     w->direct = 0;
  1292.     curx = 0;
  1293.     cury = 0;
  1294.     outstr(CL);
  1295.   }
  1296.   for(y = w->ys - 1; y >= 0; y--) {
  1297.      w->cury = y;
  1298.      (void) _wclreol(w);
  1299.   }
  1300.   w->direct = olddir;
  1301.   _gotoxy(w->x1, w->y1);
  1302.   if (dirflush) wflush();
  1303. }
  1304.  
  1305. /* ==== Insert / Delete functions ==== */
  1306.  
  1307. void winsline(w)
  1308. WIN *w;
  1309. {
  1310.   int osy1, osy2;
  1311.   
  1312.   osy1 = w->sy1;
  1313.   osy2 = w->sy2;
  1314.   
  1315.   w->sy1 = w->y1 + w->cury;
  1316.   w->sy2 = w->y2;
  1317.   wscroll(w, S_DOWN);
  1318.   
  1319.   w->sy1 = osy1;
  1320.   w->sy2 = osy2;
  1321. }
  1322.  
  1323. void wdelline(w)
  1324. WIN *w;
  1325. {
  1326.   int osy1, osy2;
  1327.   int ocury;
  1328.   
  1329.   ocury = w->cury;
  1330.   osy1 = w->sy1;
  1331.   osy2 = w->sy2;
  1332.   
  1333.   w->sy1 = w->y1 + w->cury;
  1334.   w->sy2 = w->y2;
  1335.   
  1336.   _intern = 1;
  1337.   wscroll(w, S_UP);
  1338.   _intern = 0;
  1339.   wlocate(w, 0, ocury);
  1340.  
  1341.   w->sy1 = osy1;
  1342.   w->sy2 = osy2;
  1343. }
  1344.  
  1345. /*
  1346.  * Insert a space at cursor position.
  1347.  */
  1348. void winschar(w)
  1349. WIN *w;
  1350. {
  1351.   int y;
  1352.   register x;
  1353.   int doit = 1;
  1354.   ELM buf[128];
  1355.   ELM *e = buf;
  1356.  
  1357. #ifdef SMOOTH
  1358.   curwin = w;
  1359. #endif
  1360.  
  1361.   if (w->curx == w->xs - 1) {
  1362.       wputc(w, ' ');
  1363.       return;
  1364.   }
  1365.  
  1366.   if (w->xs == COLS && IC != CNULL) {
  1367.       doit = 0;
  1368.       if (w->direct) outstr(IC);
  1369.   }
  1370.   
  1371.   /* Get the rest of line into buffer */
  1372.   y = w->y1 + w->cury;
  1373.   x = w->x1 + w->curx;
  1374.   memcpy(buf, gmap + COLS * y + x, sizeof(ELM) * (w->xs - w->curx));
  1375.   
  1376.   _write(' ', doit && w->direct, x++, y, w->attr, w->color);
  1377.   /* Write buffer to screen */
  1378.   for(; x <= w->x2; x++) {
  1379.       _write(e->value, doit && w->direct, x, y, e->attr, e->color);
  1380.       e++;
  1381.   }
  1382.   wlocate(w, w->curx, w->cury);
  1383. }
  1384.  
  1385. /*
  1386.  * Delete character under the cursor.
  1387.  */
  1388. void wdelchar(w)
  1389. WIN *w;
  1390. {
  1391.   register x, y;
  1392.   int doit = 1;
  1393.   ELM *e;
  1394.  
  1395. #ifdef SMOOTH
  1396.   curwin = w;
  1397. #endif
  1398.  
  1399.   x = w->x1 + w->curx;
  1400.   y = w->y1 + w->cury;
  1401.   
  1402.   if (w->direct && w->xs == COLS && DC != CNULL) {
  1403.       /*_gotoxy(x - 1, y);*/
  1404.       _gotoxy(x, y);
  1405.       outstr(DC);
  1406.       doit = 0;
  1407.   }
  1408.   
  1409.   e = gmap + y * COLS + x + 1;
  1410.   
  1411.   for(; x < w->x2; x++) {
  1412.       _write(e->value, doit && w->direct, x, y, e->attr, e->color);
  1413.       e++;
  1414.   }
  1415.   _write(' ', doit && w->direct, x, y, w->attr, w->color);
  1416.   wlocate(w, w->curx, w->cury);
  1417. }
  1418.  
  1419. /* ============= Support: edit a line on the screen. ============ */
  1420.  
  1421. /* Redraw the line we are editting. */
  1422. static void lredraw(w, x, y, s, len)
  1423. WIN *w;
  1424. int x;
  1425. int y;
  1426. char *s;
  1427. int len;
  1428. {
  1429.   int i, f;
  1430.  
  1431.   i = 0;
  1432.   wlocate(w, x, y);
  1433.   for(f = 0; f < len; f++) {
  1434.     if (s[f] == 0) i++;
  1435.     wputc(w, i ? ' ' : s[f]);
  1436.   }
  1437. }
  1438.  
  1439. /* wgets - edit one line in a window. */
  1440. int wgets(w, s, linelen, maxlen)
  1441. WIN *w;
  1442. char *s;
  1443. int linelen;
  1444. int maxlen;
  1445. {
  1446.   int c;
  1447.   int idx;
  1448.   int offs = 0;
  1449.   int f, st, i;
  1450.   char buf[256];
  1451.   int quit = 0;
  1452.   int x, y, r;
  1453.   int direct = dirflush;
  1454.  
  1455.   x = w->curx;
  1456.   y = w->cury;
  1457.  
  1458.   i = w->xs - x;
  1459.   if (linelen >= i - 1) linelen = i - 1;
  1460.  
  1461.   /* We assume the line has already been drawn on the screen. */
  1462.   if ((idx = strlen(s)) > linelen)
  1463.     idx = linelen;
  1464.   strcpy(buf, s);
  1465.   wlocate(w, x + idx, y);
  1466.   dirflush = 0;
  1467.   wflush();
  1468.  
  1469.   while(!quit) {
  1470.     c = getch();
  1471.     switch(c) {
  1472.         case '\r':
  1473.         case '\n':
  1474.             st = 0;
  1475.             quit = 1;
  1476.             break;
  1477.         case K_ESC: /* Exit without changing. */
  1478.             wlocate(w, x, y);
  1479.             lredraw(w, x, y, s, linelen);
  1480.             wflush();
  1481.             st = -1;
  1482.             quit = 1;
  1483.             break;
  1484.         case K_HOME: /* Home */
  1485.             r = (offs > 0);
  1486.             offs = 0;
  1487.             idx = 0;
  1488.             if (r) lredraw(w, x, y, buf, linelen);
  1489.             wlocate(w, x, y);
  1490.             wflush();
  1491.             break;
  1492.         case K_END: /* End of line. */
  1493.             idx = strlen(buf);
  1494.             r = 0;
  1495.             while(idx - offs > linelen) {
  1496.                 r = 1;
  1497.                 offs += 4;
  1498.             }
  1499.             if (r) lredraw(w, x, y, buf + offs, linelen);
  1500.             wlocate(w, x + idx - offs, y);
  1501.             wflush();
  1502.             break;
  1503.         case K_LT: /* Cursor left. */
  1504.         case K_BS: /* Backspace is first left, then DEL. */
  1505.             if (idx == 0) break;
  1506.             idx--;
  1507.             if (idx < offs) {
  1508.                 offs -= 4;
  1509.                 /*if (c == K_LT) FIXME? */
  1510.                     lredraw(w, x, y, buf + offs, linelen);
  1511.             }
  1512.             if(c == K_LT) {
  1513.                 wlocate(w, x + idx - offs, y);
  1514.                 wflush();
  1515.                 break;
  1516.             }
  1517.             /*FALLTHRU*/
  1518.         case K_DEL: /* Delete character under cursor. */
  1519.             if (buf[idx] == 0) break;
  1520.             for(f = idx; buf[f]; f++)
  1521.                 buf[f] = buf[f+1];
  1522.             lredraw(w, x + idx - offs, y, buf + idx,
  1523.                 linelen - (idx - offs));
  1524.             wlocate(w, x + idx - offs, y);
  1525.             wflush();
  1526.             break;
  1527.         case K_RT:
  1528.             if (buf[idx] == 0) break;
  1529.             idx++;
  1530.             if (idx - offs > linelen) {
  1531.                 offs += 4;
  1532.                 lredraw(w, x, y, buf + offs, linelen);
  1533.             }
  1534.             wlocate(w, x + idx - offs, y);
  1535.             wflush();
  1536.             break;
  1537.         default:
  1538.             /* Insert character at cursor position. */
  1539.             if (c < 32 || c > 127) break;
  1540.             if (idx + 1 >= maxlen) break;
  1541.             for(f = strlen(buf) + 1; f > idx; f--)
  1542.                 buf[f] = buf[f-1];
  1543.             i = buf[idx];
  1544.             buf[idx] = c;
  1545.             if (i == 0) buf[idx+1] = i;
  1546.             if (idx - offs >= linelen) {
  1547.                 offs += 4;
  1548.                 lredraw(w, x, y, buf + offs, linelen);
  1549.             } else
  1550.                 lredraw(w, x + idx - offs, y, buf + idx,
  1551.                     linelen - (idx - offs));
  1552.             idx++;
  1553.             wlocate(w, x + idx - offs, y);
  1554.             wflush();
  1555.             break;
  1556.     }
  1557.   }
  1558.   if (st == 0) strcpy(s, buf);
  1559.   dirflush = direct;
  1560.   return(st);
  1561. }
  1562.  
  1563. /* ==== Initialization code ==== */
  1564.  
  1565. static char tbuf[1024];
  1566. static char cbuf[1024];
  1567.  
  1568. /*
  1569.  * Initialize the window system
  1570.  */
  1571. #ifdef BBS
  1572. /* Code for the BBS system.. */
  1573. int win_init(term, lines)
  1574. char *term;
  1575. int lines;
  1576. {
  1577.   int fg = WHITE;
  1578.   int bg = BLACK;
  1579.   int attr = A_NORMAL;
  1580. #else
  1581. /* Code for other applications (minicom!) */
  1582. int win_init(fg, bg, attr)
  1583. int fg;
  1584. int bg;
  1585. int attr;
  1586. {
  1587.   char *term;
  1588. #endif
  1589.   static WIN _stdwin;
  1590.   char *p;
  1591.   int f, olduseattr;
  1592.  
  1593.   if (w_init) return(0);
  1594.  
  1595. #ifndef BBS
  1596.   if ((term = getenv("TERM")) == CNULL) {
  1597.       fprintf(stderr, "Environment variable TERM not set\n");
  1598.     return(-1);
  1599.   }
  1600. #endif
  1601.   switch((f = tgetent(cbuf, term))) {
  1602.       case 0:
  1603.           fprintf(stderr, "No termcap entry for %s\n", term);
  1604.           return(-1);
  1605.       case -1:
  1606.           fprintf(stderr, "No /etc/termcap present!\n");
  1607.           return(-1);
  1608.       default:
  1609.           break;
  1610.   }
  1611.   _tptr = tbuf;
  1612.  
  1613.   if ((CM = tgetstr("cm", &_tptr)) == CNULL) {
  1614.       fprintf(stderr, "No cursor motion capability (cm)\n");
  1615.       return(-1);
  1616.   }
  1617.   getrowcols(&LINES, &COLS);
  1618. #ifdef BBS
  1619.   LINES = lines;
  1620. #endif
  1621.   if (LINES == 0 && (LINES = tgetnum("li")) <= 0) {
  1622.       fprintf(stderr, "Number of terminal lines unknown\n");
  1623.       return(-1);
  1624.   }
  1625.   if (COLS == 0 && (COLS = tgetnum("co")) <= 0) {
  1626.       fprintf(stderr, "Number of terminal columns unknown\n");
  1627.       return(-1);
  1628.   }
  1629.  
  1630.   /* Terminal Capabilities */
  1631.   ME = tgetstr("me", &_tptr);
  1632.   SE = tgetstr("se", &_tptr);
  1633.   UE = tgetstr("ue", &_tptr);
  1634.   AS = tgetstr("as", &_tptr);
  1635.   AE = tgetstr("ae", &_tptr);
  1636.   MB = tgetstr("mb", &_tptr);
  1637.   MD = tgetstr("md", &_tptr);
  1638.   MR = tgetstr("mr", &_tptr);
  1639.   SO = tgetstr("so", &_tptr);
  1640.   US = tgetstr("us", &_tptr);
  1641.   CE = tgetstr("ce", &_tptr);
  1642.   Al = tgetstr("al", &_tptr);
  1643.   Dl = tgetstr("dl", &_tptr);
  1644.   AL = tgetstr("AL", &_tptr);
  1645.   DL = tgetstr("DL", &_tptr);
  1646.   CS = tgetstr("cs", &_tptr);
  1647.   SF = tgetstr("sf", &_tptr);
  1648.   SR = tgetstr("sr", &_tptr);
  1649.   VB = tgetstr("vb", &_tptr);
  1650.   VE = tgetstr("ve", &_tptr);
  1651.   VI = tgetstr("vi", &_tptr);
  1652.   IS = tgetstr("is", &_tptr);
  1653.   RS = tgetstr("rs", &_tptr);
  1654.   KS = tgetstr("ks", &_tptr);
  1655.   KE = tgetstr("ke", &_tptr);
  1656.   CD = tgetstr("cd", &_tptr);
  1657.   CL = tgetstr("cl", &_tptr);
  1658.   IC = tgetstr("ic", &_tptr);
  1659.   DC = tgetstr("dc", &_tptr);
  1660.   BC = tgetstr("bc", &_tptr);
  1661.   CR = tgetstr("cr", &_tptr);
  1662.   NL = tgetstr("nl", &_tptr);
  1663.  
  1664.   if (MR == CNULL) MR = SO;  /* Try standout */
  1665.   if (MR == CNULL) MR = US;  /* Try underline */
  1666.   if (MR == CNULL) MR = MD;  /* Try bold */
  1667.   if (SF == CNULL) SF = "\n";
  1668.  
  1669.   /* cr and nl are often not defined but result in great optimization.
  1670.    * I only hope that minicom does not break on terminals where this
  1671.    * really does not work..
  1672.    */
  1673.   if (CR == CNULL) CR = "\r";
  1674.   if (NL == CNULL) NL = "\n";
  1675.  
  1676.   /* Reset attributes */
  1677.   olduseattr = useattr;
  1678.   useattr = 1;
  1679.   _setattr(A_NORMAL, COLATTR(WHITE, BLACK));
  1680.   useattr = olduseattr;
  1681.  
  1682.   /* No reverse? don't use attributes at all. */
  1683.   if (MR == CNULL) useattr = 0;
  1684.  
  1685.   /* If we have the "ug" flag, don't allow attributes to be displayed. */
  1686.   if (tgetnum("ug") > 0) useattr = 0;
  1687.   
  1688.   _has_am = tgetflag("am");
  1689.   _mv_standout = tgetflag("ms");
  1690.   if (tgetflag("bs"))
  1691.     if (BC == CNULL) BC = "\b";
  1692.   else
  1693.       BC = CNULL;    
  1694.  
  1695.   /* Special box-drawing characters */
  1696.   D_UL  = 201;
  1697.   D_HOR = 205;
  1698.   D_UR  = 187;
  1699.   D_LL  = 200;
  1700.   D_VER = 186;
  1701.   D_LR  = 188;
  1702.   
  1703.   S_UL  = 218;
  1704.   S_HOR = 196;
  1705.   S_UR  = 191;
  1706.   S_LL  = 192;
  1707.   S_VER = 179;
  1708.   S_LR  = 217;
  1709.   
  1710.   if ((p = tgetstr("gA", &_tptr)) != CNULL) wcharmap[201] = *p;
  1711.   if ((p = tgetstr("gB", &_tptr)) != CNULL) wcharmap[205] = *p;
  1712.   if ((p = tgetstr("gC", &_tptr)) != CNULL) wcharmap[187] = *p;
  1713.   if ((p = tgetstr("gD", &_tptr)) != CNULL) wcharmap[200] = *p;
  1714.   if ((p = tgetstr("gE", &_tptr)) != CNULL) wcharmap[186] = *p;
  1715.   if ((p = tgetstr("gF", &_tptr)) != CNULL) wcharmap[188] = *p;
  1716.   if ((p = tgetstr("gG", &_tptr)) != CNULL) wcharmap[218] = *p;
  1717.   if ((p = tgetstr("gH", &_tptr)) != CNULL) wcharmap[196] = *p;
  1718.   if ((p = tgetstr("gI", &_tptr)) != CNULL) wcharmap[191] = *p;
  1719.   if ((p = tgetstr("gJ", &_tptr)) != CNULL) wcharmap[192] = *p;
  1720.   if ((p = tgetstr("gK", &_tptr)) != CNULL) wcharmap[179] = *p;
  1721.   if ((p = tgetstr("gL", &_tptr)) != CNULL) wcharmap[217] = *p;
  1722.  
  1723.   /* Memory for global map */
  1724.   if ((gmap = (ELM *)malloc(sizeof(ELM) * LINES * COLS)) == (ELM *)0) {
  1725.       fprintf(stderr, "Not enough memory\n");
  1726.       return(-1);
  1727.   };
  1728.   _buffend = _bufstart + BUFFERSIZE;
  1729.  
  1730.   /* Initialize stdwin */
  1731.   stdwin = &_stdwin;
  1732.  
  1733.   stdwin->wrap = 1;
  1734.   stdwin->cursor = CNORMAL;
  1735.   stdwin->autocr = 1;
  1736.   stdwin->doscroll = 1;
  1737.   stdwin->x1 = 0;
  1738.   stdwin->sy1 = stdwin->y1 = 0;
  1739.   stdwin->x2 = COLS - 1;
  1740.   stdwin->sy2 = stdwin->y2 = LINES - 1;
  1741.   stdwin->xs = COLS;
  1742.   stdwin->ys = LINES;
  1743.   stdwin->attr = attr;
  1744.   stdwin->color = COLATTR(fg, bg);
  1745.   stdwin->direct = 1;
  1746. #if HISTORY
  1747.   stdwin->histbuf = (ELM *)0;
  1748. #endif
  1749.  
  1750.   if (KS != CNULL) outstr(KS); /* Keypad mode */
  1751.   if (IS != CNULL) outstr(IS); /* Initialization string */
  1752.   
  1753.   (void) setcbreak(1); /* Cbreak, no echo */
  1754.  
  1755.   winclr(stdwin);
  1756.   w_init = 1;
  1757.   return(0);
  1758. }
  1759.  
  1760. void win_end()
  1761. {
  1762.   if (gmap == (ELM *)0 || w_init == 0) return;
  1763.   (void) setcbreak(0); /* Reset */
  1764.   stdwin->attr = A_NORMAL;
  1765.   stdwin->color = COLATTR(WHITE, BLACK);
  1766.   _setattr(stdwin->attr, stdwin->color);
  1767.   winclr(stdwin);
  1768.   wcursor(stdwin, CNORMAL);
  1769.   if (KE != CNULL) outstr(KE);
  1770.   if (RS != CNULL) outstr(RS);
  1771.   wflush();
  1772.   free(gmap);
  1773.   gmap = (ELM *)0;
  1774.   stdwin = NIL_WIN;
  1775.   w_init = 0;
  1776. }
  1777.