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