window.c
上传用户:tianjinjs
上传日期:2007-01-05
资源大小:309k
文件大小:41k
源码类别:

Modem编程

开发平台:

Unix_Linux

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