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