home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2882 / display.c
Encoding:
C/C++ Source or Header  |  1991-02-28  |  48.0 KB  |  1,661 lines

  1. /*
  2. * The functions in this file handle redisplay. The
  3. * redisplay system knows almost nothing about the editing
  4. * process; the editing functions do, however, set some
  5. * hints to eliminate a lot of the grinding. There is more
  6. * that can be done; the "vtputc" interface is a real
  7. * pig. Two conditional compilation flags; the GOSLING
  8. * flag enables dynamic programming redisplay, using the
  9. * algorithm published by Jim Gosling in SIGOA. The MEMMAP
  10. * changes things around for memory mapped video. With
  11. * both off, the terminal is a VT52.
  12. */
  13.  
  14. #define LINT_ARGS   1           /* enable lint type checking */
  15. #include    "def.h"
  16.  
  17. D32 get_long ();
  18. D16 get_int ();
  19. void writ_echo ();
  20. void uline ();
  21. void ucopy ();
  22. void modeline ();
  23. void bin_to_text ();
  24. uint fill_buf ();
  25. uint get_currow ();
  26. uint get_curcol ();
  27. #if MSDOS
  28. void    mem_line ();
  29. #endif
  30.  
  31.     extern    char    MSG_prn_to[];
  32.     extern    char    MSG_disp_r_n[];
  33.     extern    char    MSG_11lX[];
  34.     extern    char    MSG_11lo[];
  35.     extern    char    MSG_11ld[];
  36.     extern    char    MSG_03o[];
  37.     extern    char    MSG_06o[];
  38.     extern    char    MSG_011lo[];
  39.     extern    char    MSG_03u[];
  40.     extern    char    MSG_05u[];
  41.     extern    char    MSG_010lu[];
  42.     extern    char    MSG_02X[];
  43.     extern    char    MSG_04X[];
  44.     extern    char    MSG_08lX[];
  45.     extern    char    MSG_prog_name[];
  46.     extern    char    MSG_disp_b_lst[];
  47.     extern    char    MSG_file[];
  48.     extern    char    MSG_RO[];
  49.     extern    char    MSG_WL[];
  50.     extern    char    MSG_RW[];
  51.     extern    char    MSG_AU[];
  52.     extern    char    MSG_NOT_AU[];
  53.     extern    char    MSG_curs_asc[];
  54.     extern    char    MSG_curs_ebc[];
  55.     extern    char    MSG_curs_hex[];
  56.     extern    char    MSG_curs_bin[];
  57.     extern    char    MSG_curs_dec[];
  58.     extern    char    MSG_curs_oct[];
  59.     extern    char    MSG_siz_8[];
  60.     extern    char    MSG_siz_16[];
  61.     extern    char    MSG_siz_32[];
  62.     extern    char    MSG_siz_null[];
  63.     extern    char    MSG_int_shift[];
  64.     extern    char    MSG_mot_shift[];
  65.     extern    char    MSG_print1[];
  66.     extern    char    MSG_print2[];
  67. #if RUNCHK
  68.     extern    char    ERR_disp_1[];
  69.     extern    char    ERR_disp_2[];
  70.     extern    char    ERR_disp_3[];
  71.     extern    char    ERR_disp_4[];
  72.     extern    char    ERR_disp_5[];
  73.     extern    char    ERR_disp_6[];
  74. #endif
  75.  
  76. #include    "lintfunc.dec"
  77. extern char ebcdic_table[];
  78.  
  79. extern  bool    mem_map;
  80.  
  81. /*
  82. * You can change these back to the types
  83. * implied by the name if you get tight for space. If you
  84. * make both of them "int" you get better code on the VAX.
  85. * They do nothing if this is not Gosling redisplay, except
  86. * for change the size of a structure that isn't used.
  87. * A bit of a cheat.
  88. */
  89. #define XCHAR   int
  90. #define XSHORT  int
  91.  
  92. /*
  93. * A video structure always holds
  94. * an array of characters whose length is equal to
  95. * the longest line possible. Only some of this is
  96. * used if "ncol" isn't the same as "NCOL".
  97. */
  98. typedef struct vid
  99. {
  100.     short   v_hash;             /* Hash code, for compares.     */
  101.     short   v_flag;             /* Flag word.                   */
  102.     short   v_color;            /* Color of the line.           */
  103.             XSHORT v_cost;      /* Cost of display.     */
  104.     char    v_text[NCOL];       /* The actual characters.       */
  105. }                   VIDEO;
  106.  
  107. #define VFCHG   0x0001          /* Changed.                     */
  108. #define VFHBAD  0x0002          /* Hash and cost are bad.       */
  109.  
  110. /*
  111. * SCORE structures hold the optimal
  112. * trace trajectory, and the cost of redisplay, when
  113. * the dynamic programming redisplay code is used.
  114. * If no fancy redisplay, this isn't used. The trace index
  115. * fields can be "char", and the score a "short", but
  116. * this makes the code worse on the VAX.
  117. */
  118. typedef struct
  119. {
  120.     XCHAR s_itrace;             /* "i" index for track back.    */
  121.     XCHAR s_jtrace;             /* "j" index for trace back.    */
  122.     XSHORT s_cost;              /* Display cost.                */
  123. }               SCORE;
  124.  
  125. int     sgarbf = TRUE;          /* TRUE if screen is garbage.   */
  126. int     vtrow = 0;              /* Virtual cursor row.          */
  127. int     vtcol = 0;              /* Virtual cursor column.       */
  128. int     tthue = CNONE;          /* Current color.               */
  129. int     ttrow = HUGE;           /* Physical cursor row.         */
  130. int     ttcol = HUGE;           /* Physical cursor column.      */
  131. int     tttop = HUGE;           /* Top of scroll region.        */
  132. int     ttbot = HUGE;           /* Bottom of scroll region.     */
  133. char    file_off_bad = FALSE;   /* Have file offsets been changed */
  134.  
  135. VIDEO * vscreen[NROW];          /* Edge vector, virtual.        */
  136. VIDEO * pscreen[NROW];          /* Edge vector, physical.       */
  137. VIDEO video[2 * (NROW)];        /* Actual screen data.          */
  138. VIDEO blanks;                   /* Blank line image.            */
  139.  
  140. #if     GOSLING
  141. /*
  142. * This matrix is written as an array because
  143. * we do funny things in the "setscores" routine, which
  144. * is very compute intensive, to make the subscripts go away.
  145. * It would be "SCORE   score[NROW][NROW]" in old speak.
  146. * Look at "setscores" to understand what is up.
  147. */
  148. SCORE score[NROW * NROW];
  149. #endif
  150.  
  151. /*
  152. * Initialize the data structures used
  153. * by the display code. The edge vectors used
  154. * to access the screens are set up. The operating
  155. * system's terminal I/O channel is set up. Fill the
  156. * "blanks" array with ASCII blanks. The rest is done
  157. * at compile time. The original window is marked
  158. * as needing full update, and the physical screen
  159. * is marked as garbage, so all the right stuff happens
  160. * on the first call to redisplay.
  161. */
  162. void vtinit ()
  163. {
  164.     register    VIDEO * vp;
  165.     register int    i;
  166.  
  167.     ttopen ();
  168.     ttinit ();
  169.     vp = &video[0];
  170.     for (i = 0; i < NROW; ++i)
  171.         {
  172.         vscreen[i] = vp;
  173.         ++vp;
  174.         pscreen[i] = vp;
  175.         ++vp;
  176.         }
  177.     blanks.v_color = CTEXT;
  178.     for (i = 0; i < NCOL; ++i)
  179.         blanks.v_text[i] = ' ';
  180. }
  181.  
  182. /*
  183. * Tidy up the virtual display system
  184. * in anticipation of a return back to the host
  185. * operating system. Right now all we do is position
  186. * the cursor to the last line, erase the line, and
  187. * close the terminal channel.
  188. */
  189. void vttidy ()
  190. {
  191.     ttcolor (CTEXT);
  192.     ttnowindow ();              /* No scroll window.    */
  193.     ttmove (nrow - 1, 0);       /* Echo line.           */
  194.     tteeol ();
  195.     tttidy ();
  196.     ttflush ();
  197.     ttclose ();
  198. }
  199.  
  200. /*
  201. * Move the virtual cursor to an origin
  202. * 0 spot on the virtual display screen. I could
  203. * store the column as a character pointer to the spot
  204. * on the line, which would make "vtputc" a little bit
  205. * more efficient. No checking for errors.
  206. */
  207. void vtmove (row, col)
  208. {
  209.     vtrow = row;
  210.     vtcol = col;
  211. }
  212.  
  213. /*
  214. * Write a character to the virtual display,
  215. * dealing with long lines and the display of unprintable
  216. * things like control characters. Also expand tabs every 8
  217. * columns. This code only puts printing characters into
  218. * the virtual display image. Special care must be taken when
  219. * expanding tabs. On a screen whose width is not a multiple
  220. * of 8, it is possible for the virtual cursor to hit the
  221. * right margin before the next tab stop is reached. This
  222. * makes the tab code loop if you are not careful.
  223. * Three guesses how we found this.
  224. */
  225. void vtputc (c)
  226. register int    c;
  227. {
  228.     register    VIDEO * vp;
  229.  
  230.     vp = vscreen[vtrow];
  231.     if (vtcol >= ncol)
  232.         vp -> v_text[ncol - 1] = '$';
  233.     else
  234.         if (ISCTRL (c) != FALSE)
  235.             {
  236.             vtputc ('^');
  237.             vtputc (c ^ 0x40);
  238.             }
  239.         else
  240.             {
  241.             vp -> v_text[vtcol] = c;
  242.             vtcol++;
  243.             }
  244.  
  245. }
  246. /*
  247. * Write an entire screen line in the correct format.    pvr
  248. *
  249. * This code only puts printing characters into
  250. * the virtual display image.
  251. * Return TRUE if something was printed to the line.
  252. */
  253. #define REGI  register
  254. bool vtputd (wp, row)
  255. WINDOW * wp;
  256. int     row;                    /* line # to print to v screen */
  257.  
  258. {
  259.     REGI VIDEO * vp;
  260.     REGI char  *lin_ptr,
  261.                 ch,
  262.                 mode;
  263.     REGI A32    row_offst;
  264.     REGI uint   chrs_per_row,
  265.                 lin_offset,
  266.                 crs,
  267.                 i,
  268.                 j,
  269.                 k,
  270.                 chrs_in_lin;
  271.     LINE * cur_line;
  272.     REGI uchar  tempc;
  273.     REGI D32 temp_long;
  274.     REGI D16 temp_int;
  275.     static char w_buf[128];      /* temp buffer for data */
  276.     REGI char  *fmnt_ptr;       /* pointer to format structure   */
  277.  
  278.     vp = vscreen[vtrow];        /* point to VIDEO structure to print into */
  279.     mode = R_TYPE(wp);          /* get type of format structure */
  280.  
  281.  /* get number of bytes per row */
  282.     chrs_per_row = R_BYTES(wp);
  283.  
  284.  /* determine the offset from begining of the buffer for this line */
  285.     row_offst = WIND_POS(wp) + (row * chrs_per_row);
  286.  
  287.  /* search for and point to first character in buffer to be printed */
  288.     cur_line = wp -> w_linep;   /* start with current first window line */
  289.     while (TRUE)
  290.         {                       /* find line with desired character */
  291.         if (cur_line == wp -> w_bufp -> b_linep)
  292.             {                   /* at end of buffer? */
  293.             return (FALSE);
  294.             }
  295.         if (cur_line -> l_file_offset > row_offst)
  296.             {
  297.             /* if less than current line */
  298.             cur_line = cur_line -> l_bp;/* step back */
  299.             }
  300.         else
  301.             if ((cur_line -> l_file_offset + cur_line -> l_used) <= row_offst)
  302.                 {
  303.                 cur_line = cur_line -> l_fp;/* step ahead */
  304.                 }
  305.             else
  306.                 break;
  307.         }
  308.  
  309.     lin_offset = row_offst - cur_line -> l_file_offset;/* offset into line */
  310.  
  311.  /* get index into the current line to start reading the current row's data */
  312.  /* copy line text into buffer */
  313.     chrs_in_lin = fill_buf (wp, cur_line, lin_offset, w_buf, chrs_per_row);
  314.  
  315.     /* limit line length to screen width, used in TEXT mode only */
  316.     if (chrs_in_lin > NCOL)
  317.         chrs_in_lin = NCOL;
  318.  
  319.  /* Clear the line to spaces */
  320.     for (i = 0; i < NCOL; i++)
  321.         {
  322.         vp -> v_text[i] = ' ';
  323.         }
  324.     switch (mode)
  325.         {
  326.         case TEXT:
  327.             break;
  328.         case ASCII: 
  329.         case EBCDIC: 
  330.         case BINARY: 
  331.         case HEX: 
  332.         /* print the row offset from the start of the file in HEX */
  333.             sprintf (vp -> v_text, MSG_11lX, row_offst);/* to vid buf */
  334.             break;
  335.         case OCTAL: 
  336.         /* print the row offset from the start of the file */
  337.             sprintf (vp -> v_text, MSG_11lo, row_offst);/* to vid buf */
  338.             break;
  339.         case DECIMAL: 
  340.         /* print the row offset from the start of the file */
  341.             sprintf (vp -> v_text, MSG_11ld, row_offst);/* to vid buf */
  342.             break;
  343. #if RUNCHK
  344.         default:
  345.             writ_echo (ERR_disp_1);
  346.             break;
  347. #endif
  348.         }
  349.  
  350.  /* print the binary data to the text line */
  351.     bin_to_text (w_buf, vp -> v_text, chrs_in_lin,
  352.             wp -> w_fmt_ptr);
  353.  
  354.     vtcol = NCOL;
  355.     return (TRUE);
  356. }
  357.  
  358. /*
  359. *   Print the contents of then binary data buffer bin_buf
  360. *   into the proper mode of text into txt_buf.
  361. *   Process 'len' bytes.
  362. *
  363. *   input:
  364. *           bin_buf     pointer to buffer of binary data to process.
  365. *           txt_buf     pointer to output buffer to print text result into.
  366. *           len         length in bytes of data in bin_buf to process.
  367. *           fmt_ptr     pointer to a ROW_FMT to use to format the data
  368. *                       conversion and printing process.
  369. *   output:
  370. *           none.       
  371. */
  372.  
  373. void bin_to_text (bin_buf, txt_buf, len, fmt_ptr)
  374.  
  375. char   *bin_buf,
  376.        *txt_buf;
  377. uint    len;
  378. ROW_FMT *fmt_ptr;
  379.  
  380. {
  381.     uchar   i,
  382.             ch,
  383.             k,
  384.             j,
  385.             mode,
  386.             size,
  387.             *posn;
  388.     uint    temp_int;
  389.     ulong   temp_long;
  390.  
  391.     mode = fmt_ptr -> r_type;   /* get type of format structure */
  392.     size = fmt_ptr -> r_size;   /* get size of format structure */
  393.     posn = fmt_ptr -> r_positions;/* pointer to array of display positions */
  394.  
  395.     switch (mode)
  396.         {
  397.         case TEXT: 
  398.         case ASCII: 
  399.             for (i = 0; i < len; i++)
  400.                 {
  401.                 ch = bin_buf[i];
  402.                 if ((ch >= ' ') && (ch < 0x7f))
  403.                     txt_buf[posn[0] + i] = ch;
  404.                 else
  405.                     txt_buf[posn[0] + i] = '.';
  406.                 }
  407.             break;
  408.  
  409.         case EBCDIC: 
  410.             for (i = 0; i < len; i++)
  411.                 {
  412.                 txt_buf[posn[0] + i] =
  413.                     0xff & ebcdic_table[0xff & bin_buf[i]];
  414.                 }
  415.             break;
  416.  
  417.         case OCTAL: 
  418.             switch (size)
  419.                 {
  420.                 case BYTES:     /* print octal bytes */
  421.                     for (i = 0; i < len; i++)
  422.                         {
  423.                         sprintf (&txt_buf[
  424.                                     posn[i]], MSG_03o, 0xff & bin_buf[i]);
  425.                         }
  426.                     break;
  427.  
  428.                 case WORDS:     /* print octal words */
  429.                     k = 0;
  430.                     for (i = 0; i < len;
  431.                             i += 2)
  432.                         {
  433.                         temp_int = get_int (&bin_buf[i]);
  434.                         sprintf (&txt_buf[posn[k++]], MSG_06o, temp_int);
  435.                         }
  436.                     break;
  437.  
  438.                 case DWORDS:    /* print octal double words */
  439.                     k = 0;
  440.                     for (i = 0; i < len;
  441.                             i += 4)
  442.                         {
  443.                         temp_long = get_long (&bin_buf[i]);
  444.                         sprintf (&txt_buf[posn[k++]], MSG_011lo, temp_long);
  445.                         }
  446.                     break;
  447.                 }
  448.             break;
  449.  
  450.         case DECIMAL: 
  451.             switch (size)
  452.                 {
  453.                 case BYTES:     /* print decimal bytes */
  454.                     for (i = 0; i < len; i++)
  455.                         {
  456.                         sprintf (&txt_buf[
  457.                                     posn[i]], MSG_03u, 0xff & bin_buf[i]);
  458.                         }
  459.                     break;
  460.  
  461.                 case WORDS:     /* print decimal words */
  462.                     k = 0;
  463.                     for (i = 0; i < len;
  464.                             i += 2)
  465.                         {
  466.                         temp_int = get_int (&bin_buf[i]);
  467.                         sprintf (&txt_buf[
  468.                                     posn[k++]], MSG_05u, temp_int);
  469.                         }
  470.                     break;
  471.  
  472.                 case DWORDS:    /* print decimal double words */
  473.                     k = 0;
  474.                     for (i = 0; i < len; i += 4)
  475.                         {
  476.                         temp_long = get_long (&bin_buf[i]);
  477.                         sprintf (&txt_buf[
  478.                                     posn[k++]], MSG_010lu, temp_long);
  479.                         }
  480.                     break;
  481.                 }
  482.             break;
  483.  
  484.         case HEX: 
  485.             switch (size)
  486.                 {
  487.                 case BYTES:     /* print hex bytes and ascii chars */
  488.                     for (i = 0; i < len; i++)
  489.                         {
  490.                         if ((bin_buf[i] >= ' ') && (bin_buf[i] < 0x7f))
  491.                             txt_buf[posn[i + 16]] = 0xff & bin_buf[i];
  492.                         else
  493.                             txt_buf[posn[i + 16]] = '.';
  494.                         sprintf (&txt_buf[posn[i]], MSG_02X, 0xff & bin_buf[i]);
  495.                         }
  496.                     break;
  497.  
  498.                 case WORDS:     /* print hex words */
  499.                     k = 0;
  500.                     for (i = 0; i < len; i += 2)
  501.                         {
  502.                         temp_int = get_int (&bin_buf[i]);
  503.                         sprintf (&txt_buf[
  504.                                     posn[k++]], MSG_04X, temp_int);
  505.                         }
  506.                     break;
  507.  
  508.                 case DWORDS:    /* print hex double words */
  509.                     k = 0;
  510.                     for (i = 0; i < len; i += 4)
  511.                         {
  512.                         temp_long = get_long (&bin_buf[i]);
  513.                         sprintf (&txt_buf[
  514.                                     posn[k++]], MSG_08lX, temp_long);
  515.                         }
  516.                     break;
  517.                 }
  518.             break;
  519.  
  520.         case BINARY: 
  521.             switch (size)
  522.                 {
  523.                 case BYTES:     /* print binary bits */
  524.                     for (i = 0; i < len; i++)
  525.                         {
  526.                         ch = bin_buf[i];/* get char to convert */
  527.                         for (k = 0; k < 8; k++)
  528.                             {
  529.                             if (ch & 0x80)
  530.                                 txt_buf[posn[i] + k]
  531.                                     = '1';
  532.                             else
  533.                                 txt_buf[posn[i] + k]
  534.                                     = '0';
  535.                             ch = ch << 1;/* slide next bit into place */
  536.                             }
  537.                         }
  538.                     break;
  539.  
  540.                 case WORDS: 
  541.                     j = 0;
  542.                     for (i = 0; i < len; i += 2)
  543.                         {
  544.                         temp_int = get_int (&bin_buf[i]);
  545.  
  546.                         for (k = 0; k < 16; k++)
  547.                             {
  548.                             if (temp_int & 0x8000)
  549.                                 txt_buf[posn[j] + k]
  550.                                     = '1';
  551.                             else
  552.                                 txt_buf[posn[j] + k]
  553.                                     = '0';
  554.                             temp_int = temp_int << 1;
  555.                         /* slide next bit into place */
  556.                             }
  557.                         j++;
  558.                         }
  559.                     break;
  560.  
  561.                 case DWORDS: 
  562.                     j = 0;
  563.                     for (i = 0; i < len; i += 4)
  564.                         {
  565.                         temp_long = get_long (&bin_buf[i]);
  566.                         for (k = 0; k < 32; k++)
  567.                             {
  568.                             if (temp_long & 0x80000000)
  569.                                 txt_buf[posn[j] + k]
  570.                                     = '1';
  571.                             else
  572.                                 txt_buf[posn[j] + k]
  573.                                     = '0';
  574.                             temp_long = temp_long << 1;
  575.                         /* slide next bit into place */
  576.                             }
  577.                         j++;
  578.                         }
  579.                     break;
  580.                 }
  581.             break;
  582. #if RUNCHK
  583.         default:
  584.             writ_echo (ERR_disp_2);
  585.             break;
  586. #endif
  587.         }
  588.     len *= (fmt_ptr -> r_chr_per_u + 1);
  589.  /* Clean up any garbage characters left by the sprintf's */
  590.     for (i = 0; i < NCOL; i++)
  591.         {
  592.         if (txt_buf[i] == 0)
  593.             txt_buf[i] = ' ';
  594.         }
  595. }
  596.  
  597. /*
  598. *   Get an int from the buffer.
  599. *   Perform the Intel byte shuffle if necessary
  600. */
  601.  
  602. D16 get_int (w_buf)
  603. uchar  *w_buf;
  604.  
  605. {
  606.     int     temp_int;
  607.  
  608.     if (curwp -> w_intel_mode)
  609.         {
  610.         temp_int = 0xff & w_buf[1];
  611.         temp_int <<= 8;
  612.         temp_int |= 0xff & w_buf[0];
  613.         }
  614.     else
  615.         {
  616.         temp_int = 0xff & w_buf[0];
  617.         temp_int <<= 8;
  618.         temp_int |= 0xff & w_buf[1];
  619.         }
  620.     return (temp_int);
  621. }
  622.  
  623. /*
  624. *   Get an long from the buffer.
  625. *   Perform the Intel byte shuffle if necessary
  626. */
  627.  
  628. D32 get_long (w_buf)
  629. uchar  *w_buf;
  630.  
  631. {
  632.     long    temp_long;
  633.  
  634.     if (curwp -> w_intel_mode)
  635.         {
  636.         temp_long = 0xff & w_buf[3];
  637.         temp_long <<= 8;
  638.         temp_long |= 0xff & w_buf[2];
  639.         temp_long <<= 8;
  640.         temp_long |= 0xff & w_buf[1];
  641.         temp_long <<= 8;
  642.         temp_long |= 0xff & w_buf[0];
  643.         }
  644.     else
  645.         {
  646.         temp_long = 0xff & w_buf[0];
  647.         temp_long <<= 8;
  648.         temp_long |= 0xff & w_buf[1];
  649.         temp_long <<= 8;
  650.         temp_long |= 0xff & w_buf[2];
  651.         temp_long <<= 8;
  652.         temp_long |= 0xff & w_buf[3];
  653.         }
  654.     return (temp_long);
  655. }
  656.  
  657.  
  658. /*
  659. *   Copy a length of bytes from the buffer LINEs into the designated
  660. *   buffer.   If the current LINE does not have enough bytes then
  661. *   advance to the next.   Return the actual number of bytes copied.
  662. *   The number copied would be less than the number requested if
  663. *   end of file is reached.
  664. */
  665.  
  666. uint    fill_buf (wp, lin, lin_off, w_buff, cnt)
  667. WINDOW  *wp;
  668. LINE    *lin;
  669. uint    lin_off,
  670.         cnt;
  671. char    *w_buff;
  672. {
  673.     REGI uint   src,
  674.                 dest,
  675.                 i;
  676.  
  677.     src = lin_off;              /* initialize source line index */
  678.     dest = 0;                   /* initialize destination buffer index */
  679.  
  680.     while (TRUE)
  681.         {
  682.         while (src < lin -> l_used)
  683.             {
  684.             w_buff[dest++] = lin -> l_text[src++];/* copy byte */
  685.  
  686.             if (dest == cnt)
  687.                 {               /* if done */
  688.                 return (cnt);   /* then leave */
  689.                 }
  690.             }
  691.         if (R_TYPE(curwp) == TEXT)
  692.             return (dest);   /* in text mode don't advance to next line */
  693.  
  694.         lin = lin -> l_fp;      /* move to the next line */
  695.         if (lin == wp -> w_bufp -> b_linep)
  696.             {                   /* if past last line */
  697.             {
  698.                 for (i = dest; i < cnt; ++i)
  699.                     w_buff[i] = 0;/* fill rest of buffer with zeros */
  700.                 return (dest);  /* return number of chars copied */
  701.             }
  702.             }
  703.         src = 0;                /* start next LINE at first byte */
  704.         }
  705. }
  706.  
  707. /*
  708. * Erase from the end of the
  709. * software cursor to the end of the
  710. * line on which the software cursor is
  711. * located. The display routines will decide
  712. * if a hardware erase to end of line command
  713. * should be used to display this.
  714. */
  715. void vteeol ()
  716. {
  717.     register    VIDEO * vp;
  718.  
  719.     vp = vscreen[vtrow];
  720.     while (vtcol < ncol)
  721.         vp -> v_text[vtcol++] = ' ';
  722. }
  723.  
  724. /*
  725. * Make sure that the display is
  726. * right. This is a three part process. First,
  727. * scan through all of the windows looking for dirty
  728. * ones. Check the framing, and refresh the screen.
  729. * Second, make the
  730. * virtual and physical screens the same.
  731. */
  732. void update ()
  733. {
  734.     register    LINE * lp;
  735.     register    WINDOW * wp;
  736.     register    VIDEO * vp1;
  737.     register    VIDEO * vp2;
  738.     register uint    i;
  739.     register int    j,
  740.                     k;
  741.     register int    c;
  742.     register int    hflag;
  743.     register int    offs;
  744.     register int    size;
  745.  
  746.     hflag = FALSE;              /* Not hard.            */
  747.     wp = wheadp;
  748.     while (wp != NULL)
  749.         {
  750.     /* is this window to be displayed in linked mode */
  751.         if ((curbp -> b_flag & BFLINK) &&
  752.                 (wp -> w_bufp == curbp))
  753.             {                   /* move dot to current window's dot position */
  754.             wp -> w_dotp = curwp -> w_dotp;
  755.             wp -> w_doto = curwp -> w_doto;
  756.             move_ptr (wp, 0L, TRUE, TRUE, TRUE); /* insure dot is aligned */
  757.             wind_on_dot (wp);   /* move window to new dot position */
  758.             }
  759.  
  760.         if (wp -> w_flag != 0)
  761.  
  762.             {                   /* Need update.         */
  763.             move_ptr (wp, 0L, FALSE, TRUE, TRUE); /* window on row boundary */
  764.             move_ptr (wp, 0L, TRUE, TRUE, TRUE); /* dot on unit boundary */
  765.             if ((wp -> w_flag & WFFORCE) == 0)
  766.                 {
  767.                 wind_on_dot (wp);/* position window on dot */
  768.                 }
  769.             i = get_currow (wp); /* Redo this one line, mabey.    */
  770.             if ((wp -> w_flag & ~WFMODE) == WFEDIT)
  771.                 {
  772.                 vscreen[i] -> v_color = CTEXT;
  773.                 vscreen[i] -> v_flag |= (VFCHG | VFHBAD);
  774.                 vtmove (i, 0);
  775.                 vtputd (wp, i - wp -> w_toprow);/* print line to the screen */
  776.                 }
  777.             else
  778.                 if ((wp -> w_flag & ~WFMODE) == WFMOVE)
  779.                     {
  780.                     while (i < wp -> w_toprow + wp -> w_ntrows)
  781.                         {
  782.                         /* paint entire window */
  783.                         vscreen[i] -> v_color = CTEXT;
  784.                         vscreen[i] -> v_flag |= (VFCHG | VFHBAD);
  785.                         vtmove (i, 0);
  786.                         /* print line to the screen */
  787.                         if (!vtputd (wp, i - wp -> w_toprow))
  788.                             vteeol ();
  789.                         ++i;
  790.                         }
  791.                     }
  792.                 else
  793.                     if ((wp -> w_flag & (WFEDIT | WFHARD)) != 0)
  794.                         {
  795.                         hflag = TRUE;
  796.                         i = wp -> w_toprow;
  797.                         while (i < wp -> w_toprow + wp -> w_ntrows)
  798.                             {
  799.                             /* paint entire window */
  800.                             vscreen[i] -> v_color = CTEXT;
  801.                             vscreen[i] -> v_flag |= (VFCHG | VFHBAD);
  802.                             vtmove (i, 0);
  803.                             /* print line to the screen */
  804.                             if (!vtputd (wp, i - wp -> w_toprow))
  805.                                 vteeol ();
  806.                             ++i;
  807.                             }
  808.                         }
  809.             if ((wp -> w_flag & WFMODE) ||
  810.                     (wp -> w_flag & WFMOVE) ||
  811.                     (wp -> w_flag & WFHARD))
  812.                 modeline (wp);
  813.             wp -> w_flag = 0;
  814.             }
  815.         wp = wp -> w_wndp;
  816.         }
  817.     if (sgarbf != FALSE)
  818.         {                       /* Screen is garbage.   */
  819.         sgarbf = FALSE;         /* Erase-page clears    */
  820.         epresf = FALSE;         /* the message area.    */
  821.         tttop = HUGE;           /* Forget where you set */
  822.         ttbot = HUGE;           /* scroll region.       */
  823.         tthue = CNONE;          /* Color unknown.       */
  824.         ttmove (0, 0);
  825.         tteeop ();
  826. #if MSDOS
  827.         if (mem_map)
  828.             {
  829.             for (i = 0; i < nrow; ++i)
  830.                 {
  831.                 mem_line (i, vscreen[i]);
  832.                 }
  833.             }
  834.         else
  835.             {
  836. #endif
  837.             for (i = 0; i < nrow; ++i)
  838.                 {
  839.                 uline (i, vscreen[i], &blanks);
  840.                 ucopy (vscreen[i], pscreen[i]);
  841.                 }
  842. #if MSDOS
  843.             }
  844. #endif
  845.         ttmove (get_currow (curwp), get_curcol (curwp));
  846.         ttflush ();
  847.         return;
  848.         }
  849. #if     GOSLING
  850.     if (hflag != FALSE)
  851.         {                       /* Hard update?         */
  852.         for (i = 0; i < nrow; ++i)
  853.             {                   /* Compute hash data.   */
  854.             hash (vscreen[i]);
  855.             hash (pscreen[i]);
  856.             }
  857.         offs = 0;               /* Get top match.       */
  858.         while (offs != nrow)
  859.             {
  860.             vp1 = vscreen[offs];
  861.             vp2 = pscreen[offs];
  862.             if (vp1 -> v_color != vp2 -> v_color
  863.                     || vp1 -> v_hash != vp2 -> v_hash)
  864.                 break;
  865. #if MSDOS
  866.             if (mem_map)
  867.                 mem_line (offs, vp1);
  868.             else
  869. #endif
  870.                 {
  871.                 uline (offs, vp1, vp2);
  872.                 ucopy (vp1, vp2);
  873.                 }
  874.             ++offs;
  875.             }
  876.         if (offs == nrow - 1)
  877.             {                   /* Might get it all.    */
  878.             ttmove (get_currow (curwp), get_curcol (curwp));
  879.             ttflush ();
  880.             return;
  881.             }
  882.         size = nrow;        /* Get bottom match.    */
  883.         while (size != offs)
  884.             {
  885.             vp1 = vscreen[size - 1];
  886.             vp2 = pscreen[size - 1];
  887.             if (vp1 -> v_color != vp2 -> v_color
  888.                     || vp1 -> v_hash != vp2 -> v_hash)
  889.                 break;
  890. #if MSDOS
  891.             if (mem_map)
  892.                 mem_line (size - 1, vp1);
  893.             else
  894. #endif
  895.                 {
  896.                 uline (size - 1, vp1, vp2);
  897.                 ucopy (vp1, vp2);
  898.                 }
  899.             --size;
  900.             }
  901.         if ((size -= offs) == 0)/* Get screen size.     */
  902.             abort ();
  903.         setscores (offs, size); /* Do hard update.      */
  904.         traceback (offs, size, size, size);
  905.         for (i = 0; i < size; ++i)
  906.             ucopy (vscreen[offs + i], pscreen[offs + i]);
  907.         ttmove (get_currow (curwp), get_curcol (curwp));
  908.         ttflush ();
  909.         return;
  910.         }
  911. #endif
  912.     for (i = 0; i < nrow; ++i)
  913.         {                       /* Easy update.         */
  914.         vp1 = vscreen[i];
  915.         vp2 = pscreen[i];
  916.         if ((vp1 -> v_flag & VFCHG) != 0)
  917.             {
  918. #if MSDOS
  919.             if (mem_map)
  920.                 mem_line (i, vp1);
  921.             else
  922. #endif
  923.                 {
  924.                 uline (i, vp1, vp2);
  925.                 ucopy (vp1, vp2);
  926.                 }
  927.             }
  928.         }
  929.     ttmove (get_currow (curwp), get_curcol (curwp));
  930.     ttflush ();
  931. }
  932. /*
  933. *   Get the window relative row in which the cursor will
  934. *   appear. pvr
  935. */
  936. uint    get_currow (wp)
  937.         WINDOW * wp;
  938. {
  939.     A32    row;
  940.  /* number of bytes from start of window */
  941.     row = DOT_POS(wp) - WIND_POS(wp);
  942.  /* number of rows down in window */
  943.     row /= R_BYTES(wp);
  944.     row += wp -> w_toprow;
  945. #if RUNCHK
  946.     if (row < wp -> w_toprow)
  947.         printf (ERR_disp_3);
  948.     if (row > (wp -> w_ntrows + wp -> w_toprow))
  949.         printf (ERR_disp_4);
  950. #endif
  951.     return (row & 0xffff);
  952. }
  953.  
  954. /*
  955. *   Get the window relative column in which the cursor will
  956. *   appear. pvr
  957. */
  958. uint    get_curcol (wp)
  959.         WINDOW * wp;
  960. {
  961.     long    offset,
  962.             index;
  963.     uint    b_per_u, pos;
  964.  
  965.     b_per_u = R_B_PER_U(wp);
  966.  /* dot offset from start of buffer */
  967.     offset = DOT_POS(wp);
  968.     offset -= wp -> w_disp_shift;
  969.     offset &= ~(b_per_u - 1);
  970.  /* calculate mod of the current file position */
  971.     index = offset & (R_BYTES(wp) - 1);
  972.     index /= b_per_u;
  973.     /* limit to window width */
  974.     if (index >= NCOL)
  975.         index = NCOL;
  976.     pos = wp -> w_fmt_ptr -> r_positions[index] + wp -> w_unit_offset;
  977.     return (pos);
  978. }
  979. #if MSDOS
  980. void    mem_line (row, vvp)
  981. int     row;
  982. VIDEO * vvp;
  983.     {
  984.     vvp -> v_flag &= ~VFCHG;    /* Changes done.        */
  985.     ttcolor (vvp -> v_color);
  986.     putline (row + 1, 1, ncol, &vvp -> v_text[0]);
  987.     }
  988. #endif
  989. /*
  990. * Update a saved copy of a line,
  991. * kept in a VIDEO structure. The "vvp" is
  992. * the one in the "vscreen". The "pvp" is the one
  993. * in the "pscreen". This is called to make the
  994. * virtual and physical screens the same when
  995. * display has done an update.
  996. */
  997. void ucopy (vvp, pvp)
  998. register    VIDEO * vvp;
  999. register    VIDEO * pvp;
  1000. {
  1001.     register int    i;
  1002.  
  1003.     vvp -> v_flag &= ~VFCHG;    /* Changes done.        */
  1004.     pvp -> v_flag = vvp -> v_flag;/* Update model.        */
  1005.     pvp -> v_hash = vvp -> v_hash;
  1006.     pvp -> v_cost = vvp -> v_cost;
  1007.     pvp -> v_color = vvp -> v_color;
  1008.     for (i = 0; i < ncol; ++i)
  1009.         pvp -> v_text[i] = vvp -> v_text[i];
  1010. }
  1011.  
  1012. /*
  1013. * Update a single line. This routine only
  1014. * uses basic functionality (no insert and delete character,
  1015. * but erase to end of line). The "vvp" points at the VIDEO
  1016. * structure for the line on the virtual screen, and the "pvp"
  1017. * is the same for the physical screen. Avoid erase to end of
  1018. * line when updating CMODE color lines, because of the way that
  1019. * reverse video works on most terminals.
  1020. */
  1021. void uline (row, vvp, pvp)
  1022. VIDEO * vvp;
  1023. VIDEO * pvp;
  1024. {
  1025.     register char  *cp1;
  1026.     register char  *cp2;
  1027.     register char  *cp3;
  1028.     register char  *cp4;
  1029.     register char  *cp5;
  1030.     register int    nbflag;
  1031.  
  1032.     if (vvp -> v_color != pvp -> v_color)
  1033.         {                       /* Wrong color, do a    */
  1034.         ttmove (row, 0);        /* full redraw.         */
  1035.         ttcolor (vvp -> v_color);
  1036.         cp1 = &vvp -> v_text[0];
  1037.         cp2 = &vvp -> v_text[ncol];
  1038.         while (cp1 != cp2)
  1039.             {
  1040.             ttputc (*cp1++);
  1041.             ++ttcol;
  1042.             }
  1043.         return;
  1044.         }
  1045.     cp1 = &vvp -> v_text[0];    /* Compute left match.  */
  1046.     cp2 = &pvp -> v_text[0];
  1047.     while (cp1 != &vvp -> v_text[ncol] && cp1[0] == cp2[0])
  1048.         {
  1049.         ++cp1;
  1050.         ++cp2;
  1051.         }
  1052.     if (cp1 == &vvp -> v_text[ncol])/* All equal.           */
  1053.         return;
  1054.     nbflag = FALSE;
  1055.     cp3 = &vvp -> v_text[ncol]; /* Compute right match. */
  1056.     cp4 = &pvp -> v_text[ncol];
  1057.     while (cp3[-1] == cp4[-1])
  1058.         {
  1059.         --cp3;
  1060.         --cp4;
  1061.         if (cp3[0] != ' ')      /* Note non-blanks in   */
  1062.             nbflag = TRUE;      /* the right match.     */
  1063.         }
  1064.     cp5 = cp3;                  /* Is erase good?       */
  1065.     if (nbflag == FALSE && vvp -> v_color == CTEXT)
  1066.         {
  1067.         while (cp5 != cp1 && cp5[-1] == ' ')
  1068.             --cp5;
  1069.     /* Alcyon hack */
  1070.         if ((int) (cp3 - cp5) <= tceeol)
  1071.             cp5 = cp3;
  1072.         }
  1073.  /* Alcyon hack */
  1074.     ttmove (row, (int) (cp1 - &vvp -> v_text[0]));
  1075.     ttcolor (vvp -> v_color);
  1076.     while (cp1 != cp5)
  1077.         {
  1078.         ttputc (*cp1++);
  1079.         ++ttcol;
  1080.         }
  1081.     if (cp5 != cp3)             /* Do erase.            */
  1082.         tteeol ();
  1083. }
  1084.  
  1085. /*
  1086. * Redisplay the mode line for
  1087. * the window pointed to by the "wp".
  1088. * This is the only routine that has any idea
  1089. * of how the modeline is formatted. You can
  1090. * change the modeline format by hacking at
  1091. * this routine. Called by "update" any time
  1092. * there is a dirty window.
  1093. */
  1094.  
  1095. void modeline (wp)
  1096. register    WINDOW * wp;
  1097. {
  1098.     register char  *cp,
  1099.                     mode,
  1100.                     size,
  1101.                     u_posn,
  1102.                    *s;
  1103.     register int    c;
  1104.     register int    n;
  1105.     register    BUFFER * bp;
  1106.     register    A32 posn;
  1107.  
  1108.     static char posn_buf[30] =
  1109.     {0
  1110.     };                          /* krw */
  1111.  
  1112.     mode = wp -> w_fmt_ptr -> r_type;/* get type of format structure */
  1113.     size = wp -> w_fmt_ptr -> r_size;/* get size of format structure */
  1114.  
  1115.     n = wp -> w_toprow + wp -> w_ntrows;/* Location.            */
  1116.     vscreen[n] -> v_color = CMODE;/* Mode line color.     */
  1117.     vscreen[n] -> v_flag |= (VFCHG | VFHBAD);/* Recompute, display.  */
  1118.     vtmove (n, 0);              /* Seek to right line.  */
  1119.     bp = wp -> w_bufp;
  1120.  
  1121.     cp = MSG_prog_name;               /* Program name.  pvr    */
  1122.     n = 5;         
  1123.     while ((c = *cp++) != 0)
  1124.         {
  1125.         vtputc (c);
  1126.         ++n;
  1127.         }
  1128.  
  1129.     if ((bp -> b_flag & BFBAD) != 0)/* "?" if trashed.      */
  1130.         vtputc ('?');
  1131.     else
  1132.         vtputc (' ');
  1133.  
  1134.     if ((bp -> b_flag & BFCHG) != 0)/* "*" if changed.      */
  1135.         vtputc ('*');
  1136.     else
  1137.         vtputc (' ');
  1138.  
  1139.     if (insert_mode)            /* "I" if insert mode  */
  1140.         vtputc ('I');
  1141.     else
  1142.         vtputc ('O');
  1143.  
  1144.     if (bp == blistp)
  1145.         {                       /* special list */
  1146.         cp = MSG_disp_b_lst;
  1147.         while ((c = *cp++) != 0)
  1148.             {
  1149.             vtputc (c);
  1150.             ++n;
  1151.             }
  1152.         goto pad;
  1153.         }
  1154.  
  1155. /* Buffer name */
  1156.     vtputc (' ');
  1157.     ++n;
  1158.     cp = &bp -> b_bname[0];
  1159.     while ((c = *cp++) != 0)
  1160.         {
  1161.         vtputc (c);
  1162.         ++n;
  1163.         }
  1164.     while ((int) (cp - &bp -> b_bname[0]) < NBUFN)
  1165.         {
  1166.         vtputc (' ');
  1167.         n++;
  1168.         cp++;
  1169.         }
  1170.  
  1171.  /* File name.           */
  1172.     vtputc (' ');
  1173.     ++n;
  1174.     cp = MSG_file;
  1175.     while ((c = *cp++) != 0)
  1176.         {
  1177.         vtputc (c);
  1178.         ++n;
  1179.         }
  1180.     cp = &bp -> b_fname[0];
  1181.     while ((c = *cp++) != 0)
  1182.         {
  1183.         vtputc (c);
  1184.         ++n;
  1185.         }
  1186.     cp--;
  1187.     while ((int) (cp - &bp -> b_fname[0]) < NFILE)
  1188.         {
  1189.         vtputc (' ');
  1190.         n++;
  1191.         cp++;
  1192.         }
  1193.  
  1194.     if (bp -> b_flag & BFVIEW)
  1195.         s = MSG_RO;
  1196.     else if (bp -> b_flag & BFSLOCK)
  1197.         s = MSG_WL;
  1198.     else
  1199.         s = MSG_RW;
  1200.  
  1201.     while (*s)
  1202.         {                       /* krw */
  1203.         vtputc (*s++);
  1204.         ++n;
  1205.         }
  1206.  
  1207.     if (auto_update && !(bp -> b_flag & BFVIEW) && bp -> b_bname[0])/* jam */
  1208.         s = MSG_AU;
  1209.     else
  1210.         s = MSG_NOT_AU;
  1211.     for (; *s && n < NCOL;)
  1212.         {
  1213.         vtputc (*s++);
  1214.         ++n;
  1215.         }
  1216.  
  1217.  /* Insert current dot position into mode line. */
  1218.     posn = DOT_POS(wp);
  1219.     u_posn = R_CHR_PER_U(wp) - wp -> w_unit_offset - 1;
  1220.     if (u_posn < 0)
  1221.         u_posn = 0;
  1222.     switch (mode)
  1223.         {
  1224.         case TEXT: 
  1225.         case ASCII: 
  1226.             sprintf (posn_buf, MSG_curs_asc, posn);
  1227.             break;
  1228.         case EBCDIC: 
  1229.             sprintf (posn_buf, MSG_curs_ebc, posn);
  1230.             break;
  1231.         case HEX: 
  1232.             sprintf (posn_buf, MSG_curs_hex, posn, u_posn);
  1233.             break;
  1234.         case BINARY: 
  1235.             sprintf (posn_buf, MSG_curs_bin, posn, u_posn);
  1236.             break;
  1237.         case DECIMAL: 
  1238.             sprintf (posn_buf, MSG_curs_dec, posn, u_posn);
  1239.             break;
  1240.         case OCTAL: 
  1241.             sprintf (posn_buf, MSG_curs_oct, posn, u_posn);
  1242.             break;
  1243. #if RUNCHK
  1244.         default:
  1245.             writ_echo (ERR_disp_5);
  1246.             break;
  1247. #endif
  1248.         }
  1249.  
  1250.     cp = posn_buf;
  1251.     while ((c = *cp++) != 0)
  1252.         {
  1253.         vtputc (c);
  1254.         ++n;
  1255.         }
  1256.  
  1257.  
  1258.     if ((mode == HEX) ||
  1259.             (mode == DECIMAL) ||
  1260.             (mode == OCTAL))
  1261.         {
  1262.         switch (size)
  1263.             {
  1264.             case BYTES: 
  1265.                 sprintf (posn_buf, MSG_siz_8);
  1266.                 break;
  1267.             case WORDS: 
  1268.                 sprintf (posn_buf, MSG_siz_16);
  1269.                 break;
  1270.             case DWORDS: 
  1271.                 sprintf (posn_buf, MSG_siz_32);
  1272.                 break;
  1273. #if RUNCHK
  1274.             default:
  1275.                 writ_echo (ERR_disp_6);
  1276.                 break;
  1277. #endif
  1278.             }
  1279.         }
  1280.     else
  1281.         sprintf (posn_buf, MSG_siz_null);
  1282.  
  1283.     cp = posn_buf;
  1284.     while ((c = *cp++) != 0)
  1285.         {
  1286.         vtputc (c);
  1287.         ++n;
  1288.         }
  1289.  
  1290.     if (wp -> w_intel_mode)
  1291.         sprintf (posn_buf, MSG_int_shift, wp -> w_disp_shift);
  1292.     else
  1293.         sprintf (posn_buf, MSG_mot_shift, wp -> w_disp_shift);
  1294.     cp = posn_buf;
  1295.     while ((c = *cp++) != 0)
  1296.         {
  1297.         vtputc (c);
  1298.         ++n;
  1299.         }
  1300.  
  1301.  
  1302.  /* pad out */
  1303. pad: 
  1304.     while (n < ncol)
  1305.         {
  1306.         vtputc (' ');
  1307.         ++n;
  1308.         }
  1309. }
  1310.  
  1311. /*
  1312. * write text to the echo line 
  1313. */
  1314. void    writ_echo (buf)
  1315. char    *buf;
  1316.     {
  1317.     int     i, len;
  1318.     char    *vpp;
  1319.     bool    fill_spac;
  1320.  
  1321.     fill_spac = FALSE;
  1322.     vpp = vscreen[nrow - 1] -> v_text; 
  1323.     vscreen[nrow - 1] -> v_color = CTEXT;
  1324.     vscreen[nrow - 1] -> v_flag |= VFCHG;
  1325.     epresf = TRUE;
  1326.  
  1327.     for (i = 0; i < NCOL; i++)
  1328.         {
  1329.         if (buf[i] == 0)
  1330.             fill_spac = TRUE;
  1331.         if (fill_spac)
  1332.             vpp[i] = ' ';    
  1333.         else    
  1334.             vpp[i] = buf[i];    
  1335.         }
  1336. #if MSDOS
  1337.     if (mem_map)
  1338.         {
  1339.         mem_line (nrow - 1, vscreen[nrow - 1]);
  1340.         }
  1341.     else
  1342. #endif
  1343.         {
  1344.         uline (nrow - 1, vscreen[nrow - 1], pscreen[nrow - 1]);
  1345. /*        uline (nrow - 1, vscreen[nrow - 1], &blanks); */
  1346.         ucopy (vscreen[nrow - 1], pscreen[nrow - 1]);
  1347.         ttflush ();
  1348.         }
  1349.     }
  1350.  
  1351. #if     GOSLING
  1352. /*
  1353. * Compute the hash code for
  1354. * the line pointed to by the "vp". Recompute
  1355. * it if necessary. Also set the approximate redisplay
  1356. * cost. The validity of the hash code is marked by
  1357. * a flag bit. The cost understand the advantages
  1358. * of erase to end of line. Tuned for the VAX
  1359. * by Bob McNamara; better than it used to be on
  1360. * just about any machine.
  1361. */
  1362. void hash (vp)
  1363. register    VIDEO * vp;
  1364. {
  1365.     register int    i;
  1366.     register int    n;
  1367.     register char  *s;
  1368.  
  1369.     if ((vp -> v_flag & VFHBAD) != 0)
  1370.         {                       /* Hash bad.            */
  1371.         s = &vp -> v_text[ncol - 1];
  1372.         for (i = ncol; i != 0; --i, --s)
  1373.             if (*s != ' ')
  1374.                 break;
  1375.         n = ncol - i;           /* Erase cheaper?       */
  1376.         if (n > tceeol)
  1377.             n = tceeol;
  1378.         vp -> v_cost = i + n;   /* Bytes + blanks.      */
  1379.         for (n = 0; i != 0; --i, --s)
  1380.             n = (n << 5) + n + *s;
  1381.         vp -> v_hash = n;       /* Hash code.           */
  1382.         vp -> v_flag &= ~VFHBAD;/* Flag as all done.    */
  1383.         }
  1384. }
  1385.  
  1386. /*
  1387. * Compute the Insert-Delete
  1388. * cost matrix. The dynamic programming algorithm
  1389. * described by James Gosling is used. This code assumes
  1390. * that the line above the echo line is the last line involved
  1391. * in the scroll region. This is easy to arrange on the VT100
  1392. * because of the scrolling region. The "offs" is the origin 0
  1393. * offset of the first row in the virtual/physical screen that
  1394. * is being updated; the "size" is the length of the chunk of
  1395. * screen being updated. For a full screen update, use offs=0
  1396. * and size=nrow-1.
  1397. *
  1398. * Older versions of this code implemented the score matrix by
  1399. * a two dimensional array of SCORE nodes. This put all kinds of
  1400. * multiply instructions in the code! This version is written to
  1401. * use a linear array and pointers, and contains no multiplication
  1402. * at all. The code has been carefully looked at on the VAX, with
  1403. * only marginal checking on other machines for efficiency. In
  1404. * fact, this has been tuned twice! Bob McNamara tuned it even
  1405. * more for the VAX, which is a big issue for him because of
  1406. * the 66 line X displays.
  1407. *
  1408. * On some machines, replacing the "for (i=1; i<=size; ++i)" with
  1409. * i = 1; do 
  1410.     {    }while (++i <=size)" will make the code quite a
  1411. * bit better; but it looks ugly.
  1412. */
  1413. void setscores (offs, size)
  1414. {
  1415.     register    SCORE * sp;
  1416.     register int    tempcost;
  1417.     register int    bestcost;
  1418.     register int    j;
  1419.     register int    i;
  1420.     register    VIDEO ** vp;
  1421.     register    VIDEO ** pp;
  1422.     register    SCORE * sp1;
  1423.     register    VIDEO ** vbase;
  1424.     register    VIDEO ** pbase;
  1425.  
  1426.     vbase = &vscreen[offs - 1]; /* By hand CSE's.       */
  1427.     pbase = &pscreen[offs - 1];
  1428.     score[0].s_itrace = 0;      /* [0, 0]               */
  1429.     score[0].s_jtrace = 0;
  1430.     score[0].s_cost = 0;
  1431.     sp = &score[1];             /* Row 0, inserts.      */
  1432.     tempcost = 0;
  1433.     vp = &vbase[1];
  1434.     for (j = 1; j <= size; ++j)
  1435.         {
  1436.         sp -> s_itrace = 0;
  1437.         sp -> s_jtrace = j - 1;
  1438.         tempcost += tcinsl;
  1439.         tempcost += (*vp) -> v_cost;
  1440.         sp -> s_cost = tempcost;
  1441.         ++vp;
  1442.         ++sp;
  1443.         }
  1444.     sp = &score[NROW];          /* Column 0, deletes.   */
  1445.     tempcost = 0;
  1446.     for (i = 1; i <= size; ++i)
  1447.         {
  1448.         sp -> s_itrace = i - 1;
  1449.         sp -> s_jtrace = 0;
  1450.         tempcost += tcdell;
  1451.         sp -> s_cost = tempcost;
  1452.         sp += NROW;
  1453.         }
  1454.     sp1 = &score[NROW + 1];     /* [1, 1].              */
  1455.     pp = &pbase[1];
  1456.     for (i = 1; i <= size; ++i)
  1457.         {
  1458.         sp = sp1;
  1459.         vp = &vbase[1];
  1460.         for (j = 1; j <= size; ++j)
  1461.             {
  1462.             sp -> s_itrace = i - 1;
  1463.             sp -> s_jtrace = j;
  1464.             bestcost = (sp - NROW) -> s_cost;
  1465.             if (j != size)      /* Cd(A[i])=0 @ Dis.    */
  1466.                 bestcost += tcdell;
  1467.             tempcost = (sp - 1) -> s_cost;
  1468.             tempcost += (*vp) -> v_cost;
  1469.             if (i != size)      /* Ci(B[j])=0 @ Dsj.    */
  1470.                 tempcost += tcinsl;
  1471.             if (tempcost < bestcost)
  1472.                 {
  1473.                 sp -> s_itrace = i;
  1474.                 sp -> s_jtrace = j - 1;
  1475.                 bestcost = tempcost;
  1476.                 }
  1477.             tempcost = (sp - NROW - 1) -> s_cost;
  1478.             if ((*pp) -> v_color != (*vp) -> v_color
  1479.                     || (*pp) -> v_hash != (*vp) -> v_hash)
  1480.                 tempcost += (*vp) -> v_cost;
  1481.             if (tempcost < bestcost)
  1482.                 {
  1483.                 sp -> s_itrace = i - 1;
  1484.                 sp -> s_jtrace = j - 1;
  1485.                 bestcost = tempcost;
  1486.                 }
  1487.             sp -> s_cost = bestcost;
  1488.             ++sp;               /* Next column.         */
  1489.             ++vp;
  1490.             }
  1491.         ++pp;
  1492.         sp1 += NROW;            /* Next row.            */
  1493.         }
  1494. }
  1495.  
  1496. /*
  1497. * Trace back through the dynamic programming cost
  1498. * matrix, and update the screen using an optimal sequence
  1499. * of redraws, insert lines, and delete lines. The "offs" is
  1500. * the origin 0 offset of the chunk of the screen we are about to
  1501. * update. The "i" and "j" are always started in the lower right
  1502. * corner of the matrix, and imply the size of the screen.
  1503. * A full screen traceback is called with offs=0 and i=j=nrow-1.
  1504. * There is some do-it-yourself double subscripting here,
  1505. * which is acceptable because this routine is much less compute
  1506. * intensive then the code that builds the score matrix!
  1507. */
  1508. void traceback (offs, size, i, j)
  1509. {
  1510.     register int    itrace;
  1511.     register int    jtrace;
  1512.     register int    k;
  1513.     register int    ninsl;
  1514.     register int    ndraw;
  1515.     register int    ndell;
  1516.  
  1517.     if (i == 0 && j == 0)       /* End of update.       */
  1518.         return;
  1519.     itrace = score[(NROW * i) + j].s_itrace;
  1520.     jtrace = score[(NROW * i) + j].s_jtrace;
  1521.     if (itrace == i)
  1522.         {                       /* [i, j-1]             */
  1523.         ninsl = 0;              /* Collect inserts.     */
  1524.         if (i != size)
  1525.             ninsl = 1;
  1526.         ndraw = 1;
  1527.         while (itrace != 0 || jtrace != 0)
  1528.             {
  1529.             if (score[(NROW * itrace) + jtrace].s_itrace != itrace)
  1530.                 break;
  1531.             jtrace = score[(NROW * itrace) + jtrace].s_jtrace;
  1532.             if (i != size)
  1533.                 ++ninsl;
  1534.             ++ndraw;
  1535.             }
  1536.         traceback (offs, size, itrace, jtrace);
  1537.         if (ninsl != 0)
  1538.             {
  1539.             ttcolor (CTEXT);
  1540.             ttinsl (offs + j - ninsl, offs + size - 1, ninsl);
  1541.             }
  1542.         do
  1543.             {                   /* B[j], A[j] blank.    */
  1544.             k = offs + j - ndraw;
  1545.             uline (k, vscreen[k], &blanks);
  1546.         } while (--ndraw);
  1547.         return;
  1548.         }
  1549.     if (jtrace == j)
  1550.         {                       /* [i-1, j]             */
  1551.         ndell = 0;              /* Collect deletes.     */
  1552.         if (j != size)
  1553.             ndell = 1;
  1554.         while (itrace != 0 || jtrace != 0)
  1555.             {
  1556.             if (score[(NROW * itrace) + jtrace].s_jtrace != jtrace)
  1557.                 break;
  1558.             itrace = score[(NROW * itrace) + jtrace].s_itrace;
  1559.             if (j != size)
  1560.                 ++ndell;
  1561.             }
  1562.         if (ndell != 0)
  1563.             {
  1564.             ttcolor (CTEXT);
  1565.             ttdell (offs + i - ndell, offs + size - 1, ndell);
  1566.             }
  1567.         traceback (offs, size, itrace, jtrace);
  1568.         return;
  1569.         }
  1570.     traceback (offs, size, itrace, jtrace);
  1571.     k = offs + j - 1;
  1572.     uline (k, vscreen[k], pscreen[offs + i - 1]);
  1573. }
  1574. #endif
  1575.  
  1576. /*
  1577. * Print the current buffer from mark to dot using the 
  1578. * current window's display format.
  1579. * Prompt for file name or io device to print to.
  1580. */
  1581.  
  1582. bool    print ()
  1583.     {
  1584.     LINE    *dot_l_sav, *mark_l_sav, *wind_l_sav;
  1585.     int     dot_off_sav, mark_off_sav, wind_off_sav, i;
  1586.     char   s;
  1587.     char    fname[NFILEN];
  1588.     register int    nline;
  1589.     char    buf[80], buf1[60];
  1590.  
  1591.     /* save the original window state */
  1592.     dot_l_sav = curwp -> w_dotp;
  1593.     dot_off_sav = curwp -> w_doto;
  1594.     mark_l_sav = curwp -> w_markp;
  1595.     mark_off_sav = curwp -> w_marko;
  1596.     wind_l_sav = curwp -> w_linep;
  1597.     wind_off_sav = curwp -> w_loff;
  1598.  
  1599.     /* if mark is not set then set it to location zero */
  1600.     if (curwp -> w_markp == NULL)
  1601.         {
  1602.         curwp -> w_markp = curwp -> w_bufp -> b_linep -> l_fp;
  1603.         curwp -> w_marko = 0;
  1604.         }
  1605.  
  1606.     nline = 0;
  1607.     if ((s = ereply (MSG_prn_to, fname, NFILEN, NULL)) == ABORT)
  1608.         return (s);
  1609.     adjustcase (fname);
  1610.     if ((s = ffwopen (fname)) != FIOSUC)/* Open writes message. */
  1611.         return (FALSE);
  1612.  
  1613.     sprintf (buf, MSG_print1, fname);
  1614.     writ_echo (buf);
  1615.     /* make dot before mark */
  1616.     if (DOT_POS(curwp) > MARK_POS(curwp))
  1617.         swapmark ();    /* make mark first */
  1618.  
  1619.     while (DOT_POS(curwp) <= MARK_POS(curwp))
  1620.         {
  1621.         /* check if we should quit */
  1622.         if (ttkeyready ())
  1623.             {
  1624.             ttgetc ();  /* through away char that was struck */
  1625.             break;
  1626.             }
  1627.         nline++;
  1628.         /* move window so that first line is on dot */
  1629.         move_ptr (curwp, DOT_POS(curwp), FALSE, TRUE, FALSE);
  1630.  
  1631.         if (vtputd (curwp, 0))   /* print line into video buffer */
  1632.             {
  1633.             for (i = NCOL; (vscreen[vtrow] -> v_text[i] < '!') ||
  1634.                     (vscreen[vtrow] -> v_text[i] > '~'); i--)
  1635.                 ;
  1636.             i++;
  1637.             if ((s = ffputline (vscreen[vtrow] -> v_text, i)) != FIOSUC)
  1638.                 break;
  1639.             if ((s = ffputline (MSG_disp_r_n, 2)) != FIOSUC)
  1640.                 break;
  1641.             }
  1642.         else
  1643.             break;
  1644.         forwline (0, 1, KRANDOM);   /* advance to next line */
  1645.         }
  1646.     ffclose ();
  1647.     sprintf (buf1, MSG_print2, R_POS_FMT(curwp));
  1648.     sprintf (buf, buf1, (long) nline);
  1649.     writ_echo (buf);
  1650.  
  1651.     /* restore the original window state */
  1652.     curwp -> w_dotp = dot_l_sav;
  1653.     curwp -> w_doto = dot_off_sav;
  1654.     curwp -> w_markp = mark_l_sav;
  1655.     curwp -> w_marko = mark_off_sav;
  1656.     curwp -> w_linep = wind_l_sav;
  1657.     curwp -> w_loff = wind_off_sav;
  1658.     curwp -> w_flag |= WFHARD;  /* insure that window is still presentable */
  1659.     return (TRUE);
  1660.     }
  1661.