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