home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia: Special Games (Alt) / INFESPGAMES.iso / os2 / backgam / source / output.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-10  |  34.4 KB  |  1,356 lines

  1. /*************************************************************
  2.  *    ______                                                 *
  3.  *   /     /\  TinyFugue was derived from a client initially *
  4.  *  /   __/  \ written by Anton Rang (Tarrant) and later     *
  5.  *  |  / /\  | modified by Leo Plotkin (Grod).  The early    *
  6.  *  |  |/    | versions of TinyFugue written by Greg Hudson  *
  7.  *  |  X__/  | (Explorer_Bob).  The current version is       *
  8.  *  \ /      / written and maintained by Ken Keys (Hawkeye), *
  9.  *   \______/  who can be reached at kkeys@ucsd.edu.         *
  10.  *                                                           *
  11.  *             No copyright 1992, no rights reserved.        *
  12.  *             Fugue is in the public domain.                *
  13.  *************************************************************/
  14.  
  15. /*****************************************************************
  16.  * Fugue output handling                                         *
  17.  *                                                               *
  18.  * Screen handling written by Greg Hudson (Explorer_Bob) and     *
  19.  * Ken Keys (Hawkeye).  Output queueing written by Ken Keys.     *
  20.  * Handles all screen-related phenomena.                         *
  21.  *****************************************************************/
  22.  
  23. #include <ctype.h>
  24. #include <stdio.h>
  25. #include "tf.h"
  26. #include "dstring.h"
  27. #include "util.h"
  28. #include "history.h"
  29. #include "world.h"
  30. #include "socket.h"
  31. #include "macro.h"
  32. #include "output.h"
  33.  
  34. #ifdef HARDCODE
  35.    smallstr BUF;
  36. #  define clear_line()     ewrite("\r\033[K")
  37. #  define clear_to_end()   ewrite("\033[K")
  38. #  define attributes_off() ewrite("\033[m")
  39. #  define enable_cm()      /* not used by vt100 */
  40. #  define disable_cm()     /* not used by vt100 */
  41. #  define xy(x,y)     do { \
  42.                           sprintf(BUF,"\033[%d;%dH",(y),(x)); ewrite(BUF); \
  43.                       } while (0)
  44. #  define scroll(Y,y) 
  45.  
  46. #else
  47. #  ifdef TERMCAP
  48.      static int   FDECL(getcap,(char *cap, Stringp str));
  49.      static void  FDECL(tp,(char *s));
  50. #    define clear_to_end()   tp(clear_to_eol->s)
  51. #    define attributes_off() tp(attr_off->s)
  52. #    define enable_cm()      tp(ti->s)
  53. #    define disable_cm()     tp(te->s)
  54. #    define xy(x,y)          tp(tgoto(cm->s, (x) - 1, (y) - 1));
  55. #    define scroll(Y,y)      tp(tgoto(cs->s, (y) - 1, (Y) - 1));
  56.  
  57. #  else
  58. #    define clear_to_end()   /* not supported w/o TERMCAP or HARDCODE */
  59. #    define attributes_off() /* not supported w/o TERMCAP or HARDCODE */
  60. #    define xy(x,y)          /* not supported w/o TERMCAP or HARDCODE */
  61. #    define scroll(Y,y)      /* not supported w/o TERMCAP or HARDCODE */
  62. #  endif
  63. #endif
  64.  
  65. #ifndef HARDCODE
  66. static void  NDECL(clear_line);
  67. #endif
  68. static void  NDECL(empty_input_window);
  69. static void  NDECL(scroll_input);
  70. static void  FDECL(ioutput,(int c));
  71. static void  FDECL(lwrite,(char *str, int len));
  72. static void  FDECL(hwrite,(char *s, int len, int attrs));
  73. static void  NDECL(discard_screen_queue);
  74. static int   NDECL(check_more);
  75. static char *FDECL(wrapline,(int *lenp, short *attrp));
  76. static void  NDECL(output_novisual);
  77. #ifdef VISUAL
  78. static void  NDECL(output_noscroll);
  79. static void  NDECL(output_scroll);
  80. #else
  81. # define output_noscroll()      /* not supported without TERMCAP or HARDCODE */
  82. # define output_scroll()        /* not supported without TERMCAP or HARDCODE */
  83. #endif
  84. #define ewrite(str) lwrite(str, strlen(str))
  85. #define tputch(c) (putch(((c) == '\t') ? '@' : (c)))
  86.  
  87. void NDECL(ipos);
  88. void NDECL(clr);
  89. void FDECL(putch,(int c));
  90. void NDECL(init_term);
  91. void NDECL(setup_screen);
  92. void NDECL(oflush);
  93. void FDECL(clear_more,(int new));
  94. #ifdef VISUAL
  95. void FDECL(put_world,(char *name));
  96. void FDECL(put_mail,(int flag));
  97. void FDECL(put_logging,(int flag));
  98. void FDECL(put_active,(int count));
  99. #endif
  100. void NDECL(toggle_insert);
  101. void NDECL(fix_screen);
  102. void NDECL(clear_input_window);
  103. void FDECL(iputs,(char *s));
  104. void NDECL(inewline);
  105. void NDECL(ibs);
  106. void FDECL(ibackword,(int place));
  107. void FDECL(newpos,(int place));
  108. void NDECL(dEOL);
  109. void NDECL(do_line_refresh);
  110. void NDECL(do_replace);
  111. void NDECL(reset_outcount);
  112. void FDECL(localoutput,(Aline *aline));
  113. void FDECL(aoutput,(Aline *aline));
  114. void FDECL(enable_wrap,(int column));
  115. void NDECL(disable_wrap);
  116. int  NDECL(getwrap);
  117. void FDECL(setprompt,(char *s));
  118.  
  119. void NDECL(do_refresh);
  120. void NDECL(do_page);
  121. void NDECL(do_hpage);
  122. void NDECL(do_line);
  123. void NDECL(do_flush);
  124.  
  125. #define Wrap (current_wrap_column ? current_wrap_column : columns)
  126. #define keyboard_end (keybuf->len)
  127.  
  128. #define DEFAULT_LINES 25
  129. #define DEFAULT_COLUMNS 80
  130. #define DEFAULT_BOARD_SIZE 13
  131.  
  132. extern char board_buffer[2048];
  133. extern int do_board();
  134. extern char *board_diff();
  135.  
  136. /* Flags */
  137.  
  138. extern int beeping, hilite, gag;
  139. extern int visual;              /* Visual mode? */
  140. extern int clear;               /* Clear rather than scroll input? */
  141. extern int cleardone;           /* Clear input window for each line? */
  142. extern int wrapspace;           /* Indent wrapped lines */
  143. extern int more;                /* paging: 0 == off, 1 == on, 2 == paused */
  144. extern int log_on;
  145. extern int board;
  146. extern int style;
  147.  
  148. /* Termcap strings and flags */
  149.  
  150. #ifdef TERMCAP
  151. static Stringp write_buffer;
  152. static Stringp ti;             /* Cursor motion mode */
  153. static Stringp te;             /* Cursor motion mode */
  154. static Stringp cl;             /* Clear screen       */
  155. static Stringp cm;             /* Move cursor        */
  156. static Stringp cs;             /* Set scroll area    */
  157. static Stringp underline;      /* termcap us         */
  158. static Stringp reverse;        /* termcap mr         */
  159. static Stringp blink;          /* termcap mb         */
  160. static Stringp dim;            /* termcap mh         */
  161. static Stringp bold;           /* termcap md         */
  162. static Stringp attr_off;       /* termcap me         */
  163. static Stringp start_of_line;  /* termcap cr or '\r' */
  164. static Stringp clear_to_eol;   /* termcap ce         */
  165. #endif
  166. static short have_attr;
  167. static int have_clear, have_scroll;
  168.  
  169. int input_cursor = TRUE;            /* is cursor in input window position? */
  170. int can_have_visual = FALSE;        /* cm, cl and ce caps necessary */
  171.  
  172. /* Others */
  173.  
  174. extern int keyboard_pos;            /* position of logical cursor in keybuf */
  175. extern int mail_size;               /* size of mail file */
  176. extern int active_count;            /* number of active sockets */
  177. extern Stringp keybuf;              /* input buffer */
  178.  
  179. static int ox, oy, oy1;             /* Current position in output window */
  180. static int ix, iy, iy1;             /* Current position in input window */
  181. static int bx,by,bendy;             /* Current position of bg board */
  182. static int linestart, iendx, iendy;
  183. static Stringp lpprompt;            /* LP prompt */
  184. static Stringp moreprompt;          /* pager prompt */
  185. static String *prompt;              /* current prompt */
  186. static int default_wrap_column;
  187. static int outcount;                /* lines remaining until more prompt */
  188. static short more_attrs;            /* attributes for more prompt */
  189. static Aline *currentline = NULL;   /* current logical line for printing */
  190. static char *physline = NULL;       /* start of next physical line */
  191.  
  192. int ilines = 0;                     /* input window size */
  193. int insert = TRUE;                  /* keyboard insert mode */
  194. int current_wrap_column;
  195. int lines, columns;                 /* Take a wild guess */
  196. int screen_setup = FALSE;           /* is *screen* in visual mode? */
  197. Queue screen_queue[1];              /* text waiting to be displayed */
  198. Queue *output_dest = screen_queue;  /* where to queue output */
  199.  
  200. #ifdef TERMCAP
  201. extern char *FDECL(tgoto,(char *code, int destcol, int destline));
  202. extern char *FDECL(tgetstr,(char *id, char **area));
  203. #endif
  204.  
  205. /********************************
  206.  * INTERMEDIARY OUTPUT ROUTINES *
  207.  ********************************/
  208.  
  209. void putch(c)
  210.     char c;
  211. {
  212.     while (write(1, &c, 1) != 1);
  213. }
  214.  
  215. static void lwrite(str, len)
  216.     char *str;
  217.     int len;
  218. {
  219.     int numwritten;
  220.  
  221.     while (len > 0) {
  222.         if ((numwritten = write(1, str, len)) == -1) numwritten = 0;
  223.         len -= numwritten;
  224.         str += numwritten;
  225.         if (len > 0) sleep(1);
  226.     }
  227. }
  228.  
  229. /********************************************************
  230.  *                                                      *
  231.  *                   TERMCAP ROUTINES                   *
  232.  *                                                      *
  233.  ********************************************************/
  234.  
  235. #ifdef TERMCAP
  236. static int getcap(cap, str)
  237.     char *cap;
  238.     Stringp str;
  239. {
  240.     char tempstr[1024];    /* max length of termcap string is 1024 */
  241.     char *temp;
  242.  
  243.     temp = tempstr;
  244.     if (tgetstr(cap, &temp) == NULL) return 0;
  245.     else Stringcpy(str, tempstr);
  246.     return 1;
  247. }
  248. #endif
  249.  
  250. void init_term()
  251. {
  252.     char blob[1024];
  253.     char *termtype;
  254.  
  255.     do_board(NULL);
  256.     ix = 1;
  257.     init_queue(screen_queue);
  258.     Stringinit(lpprompt);
  259.     Stringinit(moreprompt);
  260.     Stringcpy(moreprompt, "--More--");
  261.     prompt = lpprompt;
  262.     lines = DEFAULT_LINES;
  263.     columns = DEFAULT_COLUMNS;
  264. #ifdef HARDCODE
  265.     have_attr = F_UNDERLINE | F_REVERSE | F_FLASH | F_HILITE | F_BELL;
  266.     have_scroll = FALSE;
  267.     can_have_visual = TRUE;
  268.     have_clear = TRUE;
  269. #else
  270. # ifdef TERMCAP
  271.     Stringinit(write_buffer);
  272.     Stringinit(start_of_line);
  273.     Stringinit(clear_to_eol);
  274.     Stringinit(ti);
  275.     Stringinit(te);
  276.     Stringinit(cl);
  277.     Stringinit(cm);
  278.     Stringinit(cs);
  279.     Stringinit(underline);
  280.     Stringinit(reverse);
  281.     Stringinit(blink);
  282.     Stringinit(dim);
  283.     Stringinit(bold);
  284.     Stringinit(attr_off);
  285.     outcount = lines;
  286.     current_wrap_column = default_wrap_column = columns - 1;
  287.     if ((termtype = getenv("TERM")) == NULL) {
  288.         oputs("% Warning: null terminal type");
  289.         return;
  290.     }
  291.     if (tgetent(blob, termtype) != 1) {
  292.         oprintf("% Warning: terminal type \"%s\" unsupported.", termtype);
  293.         return;
  294.     }
  295.     have_attr = 0;
  296.     have_clear = have_scroll = can_have_visual = TRUE;
  297.  
  298.     if ((columns = tgetnum("co")) == -1) columns = DEFAULT_COLUMNS;
  299.     current_wrap_column = default_wrap_column = columns - 1;
  300.     if ((lines = tgetnum("li")) == -1) lines = DEFAULT_LINES;
  301.     if (!getcap("cr", start_of_line)) Stringcpy(start_of_line, "\r");
  302.     if (!getcap("ce", clear_to_eol)) can_have_visual = have_clear = FALSE;
  303.     if (!getcap("ti", ti)) Stringcpy(ti, "");
  304.     if (!getcap("te", ti)) Stringcpy(te, "");
  305.     if (!getcap("cl", cl)) can_have_visual = FALSE;
  306.     if (!getcap("cm", cm)) can_have_visual = FALSE;
  307.     if (!getcap("cs", cs)) have_scroll = FALSE;
  308.     if (getcap("us", underline))  have_attr |= F_UNDERLINE;
  309.     if (getcap("mr", reverse))    have_attr |= F_REVERSE;
  310.     if (getcap("mb", blink))      have_attr |= F_FLASH;
  311.     if (getcap("mh", dim))        have_attr |= F_DIM;
  312.     if (getcap("md", bold))       have_attr |= F_HILITE;
  313.     else if (getcap("so", bold))  have_attr |= F_HILITE;
  314.     if (!getcap("me", attr_off)) have_attr = 0;
  315.     have_attr |= F_BELL;
  316. # else
  317.     have_attr = F_BELL;
  318.     have_clear = have_scroll = can_have_visual = FALSE;
  319. # endif
  320. #endif
  321.     outcount = lines;
  322. }
  323.  
  324. void ipos()
  325. {
  326.     input_cursor = TRUE;
  327.     xy(ix, iy);
  328. }
  329.  
  330. void clr()
  331. {
  332. #ifdef HARDCODE
  333.     ewrite("\033[2J\033[H");
  334. #else
  335. # ifdef TERMCAP
  336.     tp(cl->s);
  337. # endif
  338. #endif
  339. }
  340.  
  341. #ifndef HARDCODE
  342. static void clear_line()
  343. {
  344.     STATIC_BUFFER(buffer)
  345.  
  346. #ifdef TERMCAP
  347.     if (have_clear) {
  348.         tp(start_of_line->s);
  349.         tp(clear_to_eol->s);
  350.         return;
  351.     }
  352. #endif
  353.     Stringterm(buffer, 0);
  354.     Stringadd(buffer, '\r');
  355.     Stringnadd(buffer, ' ', ix - 1);
  356.     Stringadd(buffer, '\r');
  357.     lwrite(buffer->s, buffer->len);
  358. }
  359. #endif
  360.  
  361. static void attributes_on(attr)
  362.     int attr;
  363. {
  364.     if ((attr & F_BELL) && beeping) putch('\007');
  365. #ifdef HARDCODE
  366.     if (!hilite) return;
  367.     if (attr & F_UNDERLINE) ewrite("\033[4m");
  368.     if (attr & F_REVERSE)   ewrite("\033[7m");
  369.     if (attr & F_FLASH)     ewrite("\033[5m");
  370.     if (attr & F_HILITE)    ewrite("\033[1m");
  371. #else
  372. # ifdef TERMCAP
  373.     if (!hilite) return;
  374.     if (have_attr & attr & F_UNDERLINE) tp(underline->s);
  375.     if (have_attr & attr & F_REVERSE)   tp(reverse->s);
  376.     if (have_attr & attr & F_FLASH)     tp(blink->s);
  377.     if (have_attr & attr & F_DIM)       tp(dim->s);
  378.     if (have_attr & attr & F_HILITE)    tp(bold->s);
  379. # endif
  380. #endif
  381. }
  382.  
  383. #ifdef TERMCAP
  384. static void tp(s)
  385.     char *s;
  386. {
  387.     tputs(s, 1, putch);
  388.     fflush(stdout);
  389. }
  390. #endif
  391.  
  392. /*****************************************************
  393.  *                                                   *
  394.  *                  WINDOW HANDLING                  *
  395.  *                                                   *
  396.  *****************************************************/
  397.  
  398. void setup_screen()
  399. {
  400.     int i;
  401.     char *line;
  402.     Stringp scr;
  403.     World *world;
  404.  
  405.     attributes_off();
  406.     if (!visual) {
  407.         if (more == 2) prompt = moreprompt;
  408. #if 0
  409.         do_replace();
  410. #endif
  411.         return;
  412.     }
  413. #ifdef VISUAL
  414.     clr();
  415.     prompt = lpprompt;
  416.     if (board)
  417.     {
  418.       switch (style)
  419.       {
  420.         case 1: 
  421.           bendy=14+1;
  422.           break;
  423.         case 2:
  424.           bendy=16+1;
  425.           break;
  426.         case 4:
  427.           bendy=13+1;
  428.           break;
  429.         default:
  430.           bendy = DEFAULT_BOARD_SIZE + 1;
  431.           break;
  432.       }
  433.     }
  434.     else
  435.       bendy = 0;
  436.     if (!ilines) ilines = 3;
  437.     if (ilines > lines - 3 - bendy)
  438.       ilines = lines - 3 - bendy;
  439.     iy1 = lines - ilines + 1;
  440.     oy1 = iy1 - 2;
  441.     outcount = oy1 - bendy;
  442.     enable_cm();
  443.  
  444.     if (have_scroll) {
  445.         Stringinit(scr);
  446.         Stringnadd(scr, '\n', ilines);
  447.         scroll(1, lines);
  448.         xy(1, lines);
  449.         lwrite(scr->s, scr->len);
  450.         Stringfree(scr);
  451.     } else clr();
  452.  
  453.     line = MALLOC(columns + 1);
  454.     strcpy(line, "_________");
  455.     if (world = fworld()) strncat(line, world->name, columns - 40 - 10 - 1);
  456.     for (i = strlen(line); i < columns - 40 - 1; i++) line[i] = '_';
  457.     if (active_count) sprintf(line + i, "(Active:%2d)_", active_count);
  458.     else strcpy(line + i, "____________");
  459.     strcat(line, log_on ? "(Logging)_" : "__________");
  460.     strcat(line, mail_size ? "(Mail)__Insert: " : "________Insert: ");
  461.     strcat(line, (insert) ? "On_" : "Off");
  462.     xy(1, iy1 - 1);
  463.     ewrite(line);
  464.     if (board)
  465.     {
  466.        for (i = 0; i < columns; i++) line[i] = '_';
  467.        xy(1,bendy);
  468.        ewrite(line);
  469.        xy(1,1);
  470.        ewrite(board_buffer);
  471.     }
  472.     FREE(line);
  473.     if (more == 2) {
  474.         xy(1, oy1 + 1);
  475.         hwrite(moreprompt->s, moreprompt->len, more_attrs);
  476.     }
  477.  
  478.     if (have_scroll) scroll(bendy+1, oy1);
  479.     ix = iendx = ox = 1;
  480.     oy = bendy + 1;
  481.     by = bx = 1;
  482.     iy = iendy = linestart = iy1;
  483.     ipos();
  484.     screen_setup = TRUE;
  485. #endif
  486. }
  487.  
  488. #ifdef VISUAL
  489. void put_world(name)
  490.     char *name;
  491. {
  492.     char *line;
  493.     int i, len;
  494.  
  495.     if (!visual) return;
  496.     len = columns - 40 - 10 - 1;
  497.     line = MALLOC(len);
  498.     strcpy(line, "");
  499.     if (name) strncat(line, name, len);
  500.     for (i = strlen(line); i < len; i++) line[i] = '_';
  501.     line[i] = '\0';
  502.     xy(10, iy1-1);
  503.     ewrite(line);
  504.     FREE(line);
  505.     ipos();
  506. }
  507.  
  508. void put_mail(flag)
  509.     int flag;
  510. {
  511.     if (screen_setup) {
  512.         xy(columns - 18, iy1 - 1);
  513.         ewrite(flag ? "(Mail)" : "______");
  514.         ipos();
  515.     }
  516. }
  517.  
  518. void put_logging(flag)
  519.     int flag;
  520. {
  521.     if (screen_setup) {
  522.         xy(columns - 28, iy1 - 1);
  523.         ewrite(flag ? "(Logging)" : "_________");
  524.         ipos();
  525.     }
  526. }
  527.  
  528. void put_active(count)
  529.     int count;
  530. {
  531.     smallstr buf;
  532.     if (screen_setup) {
  533.         xy(columns - 40, iy1 - 1);
  534.         if (count) {
  535.             sprintf(buf, "(Active:%2d)", count);
  536.             ewrite(buf);
  537.         } else ewrite("___________");
  538.         ipos();
  539.     }
  540. }
  541. #endif
  542.  
  543. void toggle_insert()
  544. {
  545.     insert = !insert;
  546.     if (screen_setup) {
  547.         xy(columns - 2, iy1 - 1);
  548.         ewrite(insert ? "On_" : "Off");
  549.         ipos();
  550.     }
  551. }
  552.  
  553. void fix_screen()
  554. {
  555.     empty_input_window();
  556. #ifdef VISUAL
  557.     if (have_scroll) scroll(1, lines);
  558.     xy(1, iy1 - 1);
  559.     input_cursor = TRUE;
  560.     clear_line();
  561.     disable_cm();
  562.     screen_setup = 0;
  563.     outcount = lines - 1;
  564. #endif
  565. }
  566.  
  567. static void empty_input_window()
  568. {
  569.     int i;
  570.  
  571.     if (!visual) clear_input_window();
  572.     for (i = iy1; i <= lines; i++) {
  573.         xy(1, i);
  574.         clear_line();
  575.     }
  576.     ix = iendx = 1;
  577.     iy = iendy = linestart = iy1;
  578.     ipos();
  579. }
  580.  
  581. void clear_input_window()
  582. {
  583.     int i;
  584.  
  585.     if (!visual) {
  586.         clear_line();
  587.         iendx = ix = 1;
  588.         return;
  589.     }
  590.     for (i = linestart; i <= iendy; i++) {
  591.         xy(1, i);
  592.         clear_to_end();
  593.     }
  594.     ix = iendx = 1;
  595.     iy = iendy = linestart;
  596.     ipos();
  597. }
  598.  
  599. static void scroll_input()
  600. {
  601.     scroll(iy1, lines);
  602.     xy(1, lines);
  603.     putch('\n');
  604.     scroll(bendy+1, oy1);
  605.     xy(iendx = 1, iy = lines);
  606. }
  607.  
  608. /***********************************************************************
  609.  *                                                                     *
  610.  *                        INPUT WINDOW HANDLING                        *
  611.  *                                                                     *
  612.  ***********************************************************************/
  613.  
  614. static void ioutput(c)
  615.     char c;
  616. {
  617.     if (visual) {
  618.         if (iendy == lines && iendx > Wrap) return;
  619.         tputch(c);
  620.         if (++iendx > Wrap && iendy != lines) xy(iendx = 1, ++iendy);
  621.     } else {
  622.         if (iendx > Wrap) return;
  623.         iendx++;
  624.         tputch(c);
  625.     }
  626. }
  627.  
  628. void iputs(s)
  629.     char *s;
  630. {
  631.     int i, j, oiex, oiey;
  632.  
  633.     if (!s[0]) return;
  634.     if (!visual) {
  635.         for (j = 0; s[j]; j++) {
  636.             putch(s[j]);
  637.             if (++iendx > Wrap) iendx = Wrap;
  638.             if (++ix > Wrap) {
  639.                 putch('\n');
  640.                 iendx = ix = 1;
  641.             }
  642.         }
  643.         if (insert || ix == 1) {
  644.             iendx = ix;
  645.             for (i = keyboard_pos; i < keyboard_end; i++)
  646.                 ioutput(keybuf->s[i]);
  647.             for (i = ix; i < iendx; i++) putch('\010');
  648.         }
  649.         return;
  650.     }
  651.  
  652.     if (!insert) {
  653.         oiex = iendx;
  654.         oiey = iendy;
  655.     }
  656.     for (j = 0; s[j]; j++) {
  657.         iendx = ix;
  658.         iendy = iy;
  659.         if (ix == Wrap && iy == lines) {
  660.             if (have_scroll && ilines > 1 && !clear) {
  661.                 tputch(s[j]);
  662.                 scroll_input();
  663.                 ix = 1;
  664.                 ipos();
  665.                 if (--linestart < iy1) linestart = iy1;
  666.             } else {
  667.                 tputch(s[j]);
  668.                 empty_input_window();
  669.             }
  670.         } else ioutput(s[j]);
  671.         ix = iendx;
  672.         iy = iendy;
  673.     }
  674.     if (insert) {
  675.         for (i = keyboard_pos; i < keyboard_end; i++) ioutput(keybuf->s[i]);
  676.         if (keyboard_pos != keyboard_end) ipos();
  677.     } else {
  678.         iendx = oiex;
  679.         iendy = oiey;
  680.     }
  681. }
  682.  
  683. void inewline()
  684. {
  685.     Stringterm(lpprompt, 0);
  686.     if (!visual) {
  687.         putch('\n');
  688.         ix = iendx = 1;
  689.         if (prompt->len > 0) set_refresh_pending();
  690.         return;
  691.     }
  692.  
  693.     if (!input_cursor) ipos();
  694.     if (cleardone) {
  695.         linestart = iy1;
  696.         clear_input_window();
  697.         iy = iy1;
  698.         ix = iendx = 1;
  699.         return;
  700.     }
  701.     iy = iendy;
  702.     if (++iy > lines) {
  703.         if (have_scroll && ilines > 1 && !clear) {
  704.             scroll_input();
  705.             linestart = lines;
  706.         } else {
  707.             empty_input_window();
  708.             iy = iy1;
  709.         }
  710.     } else linestart = iy;
  711.     iendy = iy;
  712.     ix = iendx = 1;
  713. }
  714.  
  715. void ibs()
  716. {
  717.     int kstart, pstart, i;
  718.  
  719.     if (!visual) {
  720.         ix--;
  721.         if (ix) {
  722.             putch('\010');
  723.             iendx = ix;
  724.             for (i = keyboard_pos; i < keyboard_end; i++)
  725.                 ioutput(keybuf->s[i]);
  726.             ioutput(' ');
  727.             for (i = keyboard_pos; i < keyboard_end; i++) putch('\010');
  728.             putch('\010');
  729.         } else {
  730.             ix = Wrap;
  731.             do_line_refresh();
  732.         }
  733.       return;
  734.     }
  735.  
  736.     if (!input_cursor) ipos();
  737.     if (ix == 1 && iy == iy1) {              /* Move back a screen. */
  738.         empty_input_window();
  739.         kstart = keyboard_pos - (Wrap * ilines) + 1;
  740.         if (kstart < 0) {
  741.             pstart = prompt->len + kstart;
  742.             if (pstart < 0) pstart = 0;
  743.             kstart = 0;
  744.         } else pstart = prompt->len;
  745.         while (prompt->s[pstart]) ioutput(prompt->s[pstart++]);
  746.         for (i = kstart; i < keyboard_pos; i++) ioutput(keybuf->s[i]);
  747.         ix = iendx;
  748.         iy = iendy;
  749.         for (i = keyboard_pos; i < keyboard_end; i++)
  750.             ioutput(keybuf->s[i]);
  751.         ipos();
  752.         return;
  753.     }
  754.     if (ix == 1) {
  755.         ix = Wrap;
  756.         iy--;
  757.         ipos();
  758.     } else {
  759.         ix--;
  760.         putch('\010');
  761.     }
  762.     iendx = ix;
  763.     iendy = iy;
  764.     for (i = keyboard_pos; i < keyboard_end; i++)
  765.         ioutput(keybuf->s[i]);
  766.     putch(' ');
  767.   
  768.     if ((keyboard_pos == keyboard_end) && (ix != Wrap)) putch('\010');
  769.     else ipos();
  770. }
  771.  
  772. void ibackword(place)
  773.     int place;
  774. {
  775.     int kstart, pstart, i, oiex, oiey;
  776.  
  777.     if (!visual) {
  778.         if (place == keyboard_end)
  779.             for (i = place; i < keyboard_pos; i++) ibs();
  780.         else {
  781.             keyboard_pos = place;
  782.             do_line_refresh();
  783.         }
  784.         return;
  785.     }
  786.  
  787.     if (!input_cursor) ipos();
  788.     ix -= (keyboard_pos - place);
  789.     if (ix < 1) {
  790.         ix += Wrap;
  791.         iy--;
  792.         if (iy < iy1) {
  793.             empty_input_window();
  794.             kstart = place - (Wrap * ilines) + (Wrap - ix) + 1;
  795.             if (kstart < 0) {
  796.                 pstart = prompt->len + kstart;
  797.                 if (pstart < 0) pstart = 0;
  798.                 kstart = 0;
  799.             } else pstart = prompt->len;
  800.             while(prompt->s[pstart]) ioutput(prompt->s[pstart++]);
  801.             for (i = kstart; i < place; i++) ioutput(keybuf->s[i]);
  802.             ix = iendx;
  803.             iy = iendy;
  804.             for (i = place; i < keyboard_end; i++)
  805.                 ioutput(keybuf->s[i]);
  806.             if (keyboard_pos != keyboard_end) ipos();
  807.             return;
  808.         }
  809.     }
  810.     ipos();
  811.     iendx = ix;
  812.     iendy = iy;
  813.     for (i = place; i < keyboard_end; i++)
  814.         ioutput(keybuf->s[i]);
  815.  
  816.     oiex = iendx;
  817.     oiey = iendy;
  818.     for (i = place; i < keyboard_pos; i++) ioutput(' ');
  819.     iendx = oiex;
  820.     iendy = oiey;
  821.     ipos();
  822. }
  823.  
  824. void newpos(place)
  825.     int place;
  826. {
  827.     int diff, nix, niy, i, kstart, pstart;
  828.  
  829.     if (place < 0) place = 0;
  830.     if (place > keyboard_end) place = keyboard_end;
  831.     if (place == keyboard_pos) return;
  832.     if (!visual) {
  833.         nix = ix + place - keyboard_pos;
  834.         if (nix == ix) return;
  835.         if (nix < 1 || nix > Wrap) {
  836.             keyboard_pos = place;
  837.             do_line_refresh();
  838.         } else {
  839.             if (nix < ix) 
  840.                 for (i = keyboard_pos; i > place; i--) putch('\010');
  841.             else for (i = keyboard_pos; i < place; i++) putch(keybuf->s[i]);
  842.             ix = nix;
  843.         }
  844.         keyboard_pos = place;
  845.         return;
  846.     }
  847.  
  848.     diff = place - keyboard_pos;
  849.     if (diff == 0) return;
  850.     niy = iy + diff / Wrap;
  851.     nix = ix + diff % Wrap;
  852.  
  853.     if (nix > Wrap) {
  854.         niy++;
  855.         nix -= Wrap;
  856.     }
  857.     while (niy > lines) {
  858.         kstart = keyboard_pos + (lines - iy + 1) * Wrap - ix + 1;
  859.         scroll_input();
  860.         for (i = kstart; i < keyboard_end; i++) ioutput(keybuf->s[i]);
  861.         keyboard_pos += (lines - iy1 + 1) * Wrap;
  862.         niy--;
  863.     }
  864.  
  865.     if (nix < 1) {
  866.         niy--;
  867.         nix += Wrap;
  868.     }
  869.     if (niy < iy1) {
  870.         kstart = keyboard_pos - (iy - niy) * Wrap - ix + 1;
  871.         if (kstart < 0) {
  872.             pstart = prompt->len + kstart;
  873.             if (pstart < 0) pstart = 0;
  874.             kstart = 0;
  875.         } else pstart = prompt->len;
  876.         empty_input_window();
  877.         while (prompt->s[pstart]) ioutput(prompt->s[pstart++]);
  878.         while (keybuf->s[kstart]) ioutput(keybuf->s[kstart++]);
  879.         niy = iy1;
  880.     }
  881.  
  882.     ix = nix;
  883.     iy = niy;
  884.  
  885.     ipos();
  886.     keyboard_pos = place;
  887. }
  888.  
  889. void dEOL()
  890. {
  891.     int i;
  892.  
  893.     if (!visual) {
  894.         for (i = ix; i <= iendx; i++) putch(' ');
  895.         for (i = ix; i <= iendx; i++) putch('\010');
  896.         return;
  897.     }
  898.     clear_to_end();
  899.     for (i = iy + 1; i <= iendy; i++) {
  900.         xy(1, i);
  901.         clear_to_end();
  902.     }
  903.     iendx = ix;
  904.     iendy = iy;
  905.     ipos();
  906. }
  907.  
  908. void do_refresh()
  909. {
  910.     int oix, oiy, kpos, ppos;
  911.  
  912.     if (!visual) {
  913.         do_replace();
  914.         return;
  915.     }
  916.  
  917.     kpos = keyboard_pos - (iy - linestart) * Wrap - ix + 1;
  918.     if (kpos < 0) {
  919.         ppos = prompt->len + kpos;
  920.         kpos = 0;
  921.     } else ppos = prompt->len;
  922.  
  923.     oix = ix;
  924.     oiy = iy;
  925.     clear_input_window();
  926.     while (prompt->s[ppos]) ioutput(prompt->s[ppos++]);
  927.     while (keybuf->s[kpos]) ioutput(keybuf->s[kpos++]);
  928.     ix = oix;
  929.     iy = oiy;
  930.     if (keyboard_pos != keyboard_end) ipos();
  931. }
  932.  
  933. void do_line_refresh()
  934. {
  935.     int curcol, start, pstart, i;
  936.  
  937.     if (!visual && more == 2) return;
  938.     clear_refresh_pending();
  939.     if (visual) {
  940.         ipos();
  941.         return;
  942.     }
  943.  
  944.     curcol = (prompt->len + keyboard_pos) % Wrap;
  945.     start = keyboard_pos - curcol;
  946.     if (start < 0) {
  947.         pstart = prompt->len + start;
  948.         start = 0;
  949.     } else pstart = prompt->len;
  950.  
  951.     clear_input_window();
  952.     while (prompt->s[pstart]) ioutput(prompt->s[pstart++]);
  953.     while (keybuf->s[start]) ioutput(keybuf->s[start++]);
  954.     ix = curcol + 1;
  955.     for (i = iendx; i > ix; i--) putch('\010');
  956. }
  957.  
  958. void do_replace()
  959. {
  960.     int i, okpos;
  961.  
  962.     clear_input_window();
  963.     okpos = keyboard_pos;
  964.     keyboard_pos = keyboard_end;
  965.     iputs(prompt->s);
  966.     iputs(keybuf->s);
  967.     if (visual) newpos(okpos);
  968.     keyboard_pos = okpos;
  969.     if (!visual) {
  970.         if (ix - keyboard_end + keyboard_pos >= 1)
  971.             for (i = keyboard_pos; i < keyboard_end; i++) putch('\010');
  972.         else {
  973.             putch('\n');
  974.             do_line_refresh();
  975.         }
  976.     }
  977.     clear_refresh_pending();
  978. }
  979.  
  980.  
  981. /*****************************************************
  982.  *                                                   *
  983.  *                  OUTPUT HANDLING                  *
  984.  *                                                   *
  985.  *****************************************************/
  986.  
  987. /*************
  988.  * Utilities *
  989.  *************/
  990.  
  991. static void hwrite(s, len, attrs)
  992.     char *s;
  993.     int len, attrs;
  994. {
  995.     if (attrs) attributes_on(attrs);
  996.     lwrite(s, len);
  997.     if (attrs & have_attr) attributes_off();
  998. }
  999.  
  1000. void reset_outcount()
  1001. {
  1002.     outcount = visual ? oy1 - bendy : lines - 1;
  1003. }
  1004.  
  1005. /* return TRUE if okay to print */
  1006. static int check_more()
  1007. {
  1008.     if (more == 2) return FALSE;
  1009.     if (!more || ox != 1) return TRUE;
  1010.     if (outcount-- > 0) return TRUE;
  1011.  
  1012.     more = 2;                                   /* output is paused */
  1013.     if ((more_attrs = do_hook(H_MORE, NULL, "")) == 0)
  1014.         more_attrs = F_HILITE | F_REVERSE;
  1015.     if (visual) {
  1016.         xy(1, oy1 + 1);
  1017.         hwrite(moreprompt->s, moreprompt->len, more_attrs);
  1018.         ipos();
  1019.     } else {
  1020.         prompt = moreprompt;
  1021.         do_replace();
  1022.     }
  1023.     return FALSE;
  1024. }
  1025.  
  1026. void clear_more(new)
  1027.     int new;
  1028. {
  1029.     if (more != 2) return;
  1030.     more = new;
  1031.     if (visual) {
  1032.         xy(1, oy1 + 1);
  1033.         ewrite("________");
  1034.         ipos();
  1035.     } else {
  1036.         prompt = lpprompt;
  1037.         clear_input_window();
  1038.         set_refresh_pending();
  1039.     }
  1040.     oflush();
  1041. }
  1042.  
  1043. void do_page()
  1044. {
  1045.     if (more != 2) return;
  1046.     outcount = visual ? oy1 - bendy : lines - 1;
  1047.     clear_more(1);
  1048. }
  1049.  
  1050. void do_hpage() 
  1051. {
  1052.     if (more != 2) return;
  1053.     outcount = (visual ? oy1 - bendy : lines - 1) / 2;
  1054.     clear_more(1);
  1055. }
  1056.  
  1057. void do_line()
  1058. {
  1059.     if (more != 2) return;
  1060.     outcount = 1;
  1061.     clear_more(1);
  1062. }
  1063.  
  1064. void do_flush()
  1065. {
  1066.     if (more != 2) return;
  1067.     discard_screen_queue();
  1068. }
  1069.  
  1070. static void discard_screen_queue()
  1071. {
  1072.     outcount = visual ? oy1 - bendy : lines - 1;
  1073.     free_queue(screen_queue);
  1074.     if (currentline) {
  1075.         free_aline(currentline);
  1076.         currentline = NULL;
  1077.         physline = NULL;
  1078.     }
  1079.     clear_more(1);
  1080.     localoutput(new_aline("--- Output discarded ---", F_NEWLINE));
  1081. }
  1082.  
  1083. /* return the next physical line to be printed */
  1084. static char *wrapline(lenp, attrp)
  1085.     int *lenp;
  1086.     short *attrp;
  1087. {
  1088.     static short firstline = TRUE;
  1089.     char *place, *max;
  1090.     STATIC_BUFFER(dest)
  1091.  
  1092.     while (!currentline || (currentline->attrs & F_GAG) && gag) {
  1093.         if (currentline) free_aline(currentline);
  1094.         if (!(currentline = dequeue(screen_queue))) return NULL;
  1095.     }
  1096.  
  1097.     if (!check_more()) return NULL;
  1098.     Stringterm(dest, 0);
  1099.     if (!physline) {
  1100.         physline = currentline->str;
  1101.         firstline = TRUE;
  1102.     }
  1103.     max = physline + Wrap - ox + 1;
  1104.     *attrp = currentline->attrs;
  1105.     if (!firstline) {
  1106.         *attrp &= ~F_BELL;
  1107.         if (current_wrap_column) {
  1108.             Stringnadd(dest, ' ', wrapspace);
  1109.             max -= wrapspace;
  1110.         }
  1111.     }
  1112.  
  1113.     for (place = physline; *place && place < max && *place != '\n'; place++);
  1114.     if (!*place) {
  1115.         Stringcat(dest, physline);
  1116.         *lenp = dest->len;
  1117.         firstline = currentline->attrs & F_NEWLINE;
  1118.     } else if (*place == '\n') {
  1119.         Stringncat(dest, physline, place - physline);
  1120.         *lenp = dest->len;
  1121.         firstline = TRUE;
  1122.         *attrp |= F_NEWLINE;
  1123.         physline = ++place;
  1124.     } else {
  1125.         if (current_wrap_column)
  1126.             while (place != physline && !isspace(*place)) place--;
  1127.         if (place == physline) {
  1128.             Stringncat(dest, physline, max - physline);
  1129.             physline = max;
  1130.         } else {
  1131.             Stringncat(dest, physline, place - physline);
  1132.             if (current_wrap_column) for (++place; isspace(*place); ++place);
  1133.             physline = place;
  1134.         }
  1135.         *attrp |= F_NEWLINE;
  1136.         *lenp = dest->len;
  1137.         firstline = FALSE;
  1138.     }
  1139.     if (!*place) {
  1140.         physline = NULL;
  1141.         free_aline(currentline);
  1142.         currentline = NULL;
  1143.     }
  1144.     return(dest->s);
  1145. }
  1146.  
  1147.  
  1148. /****************
  1149.  * Main drivers *
  1150.  ****************/
  1151.  
  1152. void aoutput(aline)
  1153.     Aline *aline;
  1154. {
  1155.     record_local(aline);
  1156.     localoutput(aline);
  1157. }
  1158.  
  1159. void localoutput(aline)
  1160.     Aline *aline;
  1161. {
  1162.     if (output_dest == screen_queue && !currentline && !output_dest->head)
  1163.         /* shortcut if screen queue is empty */
  1164.         (currentline = aline)->links++;
  1165.     else
  1166.         enqueue(output_dest, aline);
  1167.     if (output_dest == screen_queue && more != 2) oflush();
  1168. }
  1169.  
  1170. void oflush()
  1171. {
  1172.     if (!visual || !screen_setup) output_novisual();
  1173.     else if (!have_scroll) output_noscroll();
  1174.     else output_scroll();
  1175. }
  1176.  
  1177. static void output_novisual()
  1178. {
  1179.     char *line;
  1180.     int len;
  1181.     short attrs;
  1182.  
  1183.     if (ix != 1) {
  1184.         clear_input_window();
  1185.         set_refresh_pending();
  1186.     }
  1187.     while ((line = wrapline(&len, &attrs)) != NULL) {
  1188.         hwrite(line, len, attrs);
  1189.         if (attrs & F_NEWLINE) {
  1190.             putch('\n');
  1191.             ox = 1;
  1192.         } else ox = len + 1;
  1193.     }
  1194. }
  1195.  
  1196. #ifdef VISUAL
  1197. static void output_noscroll()
  1198. {
  1199.     char *line;
  1200.     static char board_line[1024];
  1201.     int i;
  1202.     int len;
  1203.     short attrs;
  1204.     static short newline_held = TRUE;
  1205.     char *diff;
  1206.     int x;
  1207.     int y;
  1208.  
  1209.     while ((line = wrapline(&len, &attrs)) != NULL) {
  1210.         if (ox == 1) {
  1211.         if(oy == (oy1))
  1212.         {
  1213.             xy(1,bendy+2);
  1214.  
  1215.         }
  1216.                 else if(oy == (oy1-1))
  1217.                 {
  1218.                         xy(1,bendy+1);
  1219.                 }
  1220.         else
  1221.                     xy(1, (oy + 2));
  1222.             clear_to_end();
  1223.         }
  1224.  
  1225.  
  1226.         xy(ox, oy);
  1227.         input_cursor = FALSE;
  1228.  
  1229.         if (board && strncmp(line,"board:",6) == 0) {
  1230.             strcpy(board_line,line);
  1231.             strcat(board_line,wrapline(&len,&attrs));
  1232.             do_board(board_line);
  1233.             while ((diff=board_diff(&x,&y)))
  1234.             {
  1235.               xy(x,y);
  1236.               hwrite(diff,strlen(diff),attrs);
  1237.             }
  1238.             xy(ox,oy1);
  1239.         }
  1240.         else
  1241.     {
  1242.             hwrite(line, len, attrs);
  1243.         if (attrs & F_NEWLINE) {
  1244.                 ox = 1;
  1245.                 if ((oy % oy1 + 1) == 1)
  1246.         {
  1247.             oy = bendy+1;
  1248.              xy(ox, oy);
  1249.         }
  1250.         else
  1251.         {
  1252.             oy++;
  1253.             xy(ox,oy);
  1254.         }
  1255.             } 
  1256.         else 
  1257.         {
  1258.             ox = len + 1;
  1259.         }
  1260.         }
  1261.      }
  1262. }
  1263.  
  1264. static void output_scroll()
  1265. {
  1266.     char *line;
  1267.     static char board_line[1024];
  1268.     int i;
  1269.     int len;
  1270.     short attrs;
  1271.     static short newline_held = TRUE;
  1272.     char *diff;
  1273.     int x;
  1274.     int y;
  1275.  
  1276.     while ((line = wrapline(&len, &attrs)) != NULL) {
  1277.         if (input_cursor) {
  1278.             xy(ox, oy1);
  1279.             input_cursor = FALSE;
  1280.         }
  1281.         if (newline_held) putch('\n');
  1282.         if (newline_held = attrs & F_NEWLINE) ox = 1;
  1283.         else ox = len + 1;
  1284.         if (board && strncmp(line,"board:",6) == 0) {
  1285.             strcpy(board_line,line);
  1286.             strcat(board_line,wrapline(&len,&attrs));
  1287.             do_board(board_line);
  1288.             while ((diff=board_diff(&x,&y)))
  1289.             {
  1290.               xy(x,y);
  1291.               hwrite(diff,strlen(diff),attrs);
  1292.             }
  1293.             xy(ox,oy1);
  1294.         }
  1295.         else {
  1296.             hwrite(line, len, attrs);
  1297.             xy(ox, oy1);
  1298.         }
  1299.     }
  1300. }
  1301. #endif
  1302.  
  1303. /***********************************
  1304.  * Interfaces with rest of program *
  1305.  ***********************************/
  1306.  
  1307. void enable_wrap(column)
  1308.     int column;
  1309. {
  1310.     if (column) default_wrap_column = current_wrap_column = column;
  1311.     else current_wrap_column = default_wrap_column;
  1312. }
  1313.  
  1314. void disable_wrap()
  1315. {
  1316.     current_wrap_column = 0;
  1317. }
  1318.  
  1319. int getwrap()
  1320. {
  1321.     return (Wrap);
  1322. }
  1323.  
  1324. void setprompt(s)
  1325.     char *s;
  1326. {
  1327.     if (strcmp(lpprompt->s, s)) {
  1328.         Stringcpy(lpprompt, s);
  1329.         do_replace();
  1330.     }
  1331. }
  1332.  
  1333. #ifdef DMALLOC
  1334. void free_term()
  1335. {
  1336. #ifdef TERMCAP
  1337.     Stringfree(write_buffer);
  1338.     Stringfree(start_of_line);
  1339.     Stringfree(clear_to_eol);
  1340.     Stringfree(ti);
  1341.     Stringfree(te);
  1342.     Stringfree(cl);
  1343.     Stringfree(cm);
  1344.     Stringfree(cs);
  1345.     Stringfree(underline);
  1346.     Stringfree(reverse);
  1347.     Stringfree(blink);
  1348.     Stringfree(dim);
  1349.     Stringfree(bold);
  1350.     Stringfree(attr_off);
  1351. #endif
  1352.     Stringfree(lpprompt);
  1353.     Stringfree(moreprompt);
  1354. }
  1355. #endif
  1356.