1 /*
2  * The functions in this file handle redisplay. There are two halves, the
3  * ones that update the virtual display screen, and the ones that make the
4  * physical display screen the same as the virtual display screen. These
5  * functions use hints that are left in the windows by the commands.
6  *
7  */
8 
9 #include	<stdio.h>
10 #include	"estruct.h"
11 #include	"eproto.h"
12 #include	"edef.h"
13 #include	"elang.h"
14 
15 #define FARRIGHT	999		/* column beyond the right edge! */
16 
17 #if     WINDOW_MSWIN
18 static  int     foulcursor = FALSE;     /* see vtscreen() & movecursor() */
19 #endif
20 
21 static VIDEO   **vscreen;		       /* Virtual screen. */
22 #if	MEMMAP == 0
23 static VIDEO   **pscreen;		       /* Physical screen. */
24 #endif
25 
26 /*	some local function declarations	*/
27 
28 #if	PROTO
29 #if	MEMMAP
30 extern VOID PASCAL NEAR update_line(int row, struct VIDEO *vp1);
31 #else
32 extern VOID PASCAL NEAR update_line(int row, struct VIDEO *vp1, struct VIDEO *vp2);
33 #endif
34 extern VOID PASCAL NEAR update_hilite(void);
35 #else
36 extern VOID PASCAL NEAR update_line();
37 extern VOID PASCAL NEAR update_hilite();
38 #endif
39 
40 /*
41  * Initialize the data structures used by the display code. The edge vectors
42  * used to access the screens are set up. The operating system's terminal I/O
43  * channel is set up. All the other things get initialized at compile time.
44  * The original window has "WFCHG" set, so that it will get completely
45  * redrawn on the first call to "update".
46  */
47 
vtinit()48 int PASCAL NEAR vtinit()
49 {
50 	register int i;
51 	register VIDEO *vp;
52 
53 	TTopen();		/* open the screen */
54 	TTkopen();		/* open the keyboard */
55 	TTrev(FALSE);
56 
57 	/* allocate the virtual screen pointer array */
58 	vscreen = (VIDEO **)room(term.t_mrow*sizeof(VIDEO *));
59 
60 	if (vscreen == NULL)
61 #if     WINDOW_MSWIN
62 		return(FALSE);
63 #else
64 		meexit(1);
65 #endif
66 
67 
68 #if	MEMMAP == 0
69 	/* allocate the physical shadow screen array */
70 	pscreen = (VIDEO **)room(term.t_mrow*sizeof(VIDEO *));
71 	if (pscreen == NULL)
72 #if     WINDOW_MSWIN
73 		return(FALSE);
74 #else
75 		meexit(1);
76 #endif
77 #endif
78 
79 	/* for every line in the display */
80 	for (i = 0; i < term.t_mrow; ++i) {
81 
82 		/* allocate a virtual screen line */
83 		vp = (VIDEO *)room(sizeof(VIDEO)+term.t_mcol);
84 		if (vp == NULL)
85 #if     WINDOW_MSWIN
86 			return(FALSE);
87 #else
88 			meexit(1);
89 #endif
90 
91 		vp->v_flag = 0;		/* init change flags */
92 		vp->v_left = FARRIGHT;	/* init requested rev video boundries */
93 		vp->v_right = 0;
94 #if	COLOR
95 		vp->v_rfcolor = 7;	/* init fore/background colors */
96 		vp->v_rbcolor = 0;
97 #endif
98 		/* connect virtual line to line array */
99 		vscreen[i] = vp;
100 
101 #if	MEMMAP == 0
102 		/* allocate and initialize physical shadow screen line */
103 		vp = (VIDEO *)room(sizeof(VIDEO)+term.t_mcol);
104 		if (vp == NULL)
105 #if     WINDOW_MSWIN
106 			return(FALSE);
107 #else
108 			meexit(1);
109 #endif
110 
111 		vp->v_flag = VFNEW;
112 		vp->v_left = FARRIGHT;
113 		vp->v_right = 0;
114 #if	INSDEL
115 		vp->v_rline = i;	/* set requested line position */
116 #endif
117 		pscreen[i] = vp;
118 #endif
119 	}
120 	return(TRUE);
121 }
122 
123 #if	CLEAN || WINDOW_MSWIN
124 /* free up all the dynamically allocated video structures */
125 
vtfree()126 VOID PASCAL NEAR vtfree()
127 {
128 	int i;
129 	for (i = 0; i < term.t_mrow; ++i) {
130 		if (vscreen && vscreen[i]) free(vscreen[i]);
131 #if	MEMMAP == 0
132 		if (pscreen && pscreen[i]) free(pscreen[i]);
133 #endif
134 	}
135 	if (vscreen) free(vscreen);
136 #if	MEMMAP == 0
137 	if (pscreen) free(pscreen);
138 #endif
139 }
140 #endif
141 
142 #if 	WINDOW_MSWIN
143 /* vtscreen:	map a screen into the Virtual Terminal system */
144 /* ======== 						      */
145 
vtscreen(SCREEN * sp)146 VOID PASCAL NEAR vtscreen(SCREEN *sp)
147 {
148 	TTflush();
149 	term.t_roworg = sp->s_roworg;
150 	term.t_colorg = sp->s_colorg;
151 	term.t_nrow = sp->s_nrow;
152 	term.t_ncol = sp->s_ncol;
153 
154 	vscreen = sp->s_virtual;
155 	pscreen = sp->s_physical;
156 	term.t_selscr(sp);
157 	foulcursor = TRUE;
158 } /* vtscreen */
159 
160 /* vtinitscr: build a virtual terminal resource for a new screen */
161 /* =========													 */
162 
vtinitscr(SCREEN * sp,int nrow,int ncol)163 int PASCAL NEAR vtinitscr(SCREEN *sp, int nrow, int ncol)
164 
165 /* returns TRUE if successful */
166 {
167 	int 	result;
168 
169 	if (nrow < 2) nrow = 2;
170 	term.t_nrow = nrow;
171 	term.t_ncol = ncol;
172 	term.t_roworg = 0;
173 	term.t_colorg = 0;
174 	if ((result = vtinit()) == TRUE) {
175 		sp->s_virtual = vscreen;
176 		sp->s_physical = pscreen;
177 		sp->s_nrow = nrow;
178 		sp->s_ncol = ncol;
179 		sp->s_roworg = 0;
180 		sp->s_colorg = 0;
181 	}
182 	else {
183 		vtfree();
184 		sp->s_virtual = NULL;
185 		sp->s_physical = NULL;
186 	}
187 	return result;
188 } /* vtinitscr */
189 
190 /* vtfreescr:  delete a virtual terminal resource for a dying screen */
191 /* =========														 */
192 
vtfreescr(SCREEN * sp)193 PASCAL NEAR vtfreescr(SCREEN *sp)
194 {
195 	vtscreen(sp);
196 	vtfree();
197 	vtscreen(first_screen);	/* switch to an existing screen */
198 } /* vtfreescr */
199 
200 /* vtsizescr:	resize the virtual terminal resources */
201 /* =========										  */
202 
vtsizescr(SCREEN * sp,int nrow,int ncol)203 int PASCAL NEAR vtsizescr(SCREEN *sp, int nrow, int ncol)
204 
205 /* returns TRUE if successful. Otherwise, the old VIDEO structures are
206    preserved. */
207 {
208 	VIDEO	**oldvvp, **oldpvp;
209 	int 	oldnrow, oldncol;
210 
211 	oldvvp = sp->s_virtual;
212 	oldpvp = sp->s_physical;
213 	oldnrow = sp->s_nrow;
214 	oldncol = sp->s_ncol;
215 	if (vtinitscr(sp, nrow, ncol) == TRUE) {
216 		/* success! let's free the old VIDEO structures */
217 		EWINDOW *wp;
218 
219 		vscreen = oldvvp;
220 		pscreen = oldpvp;
221 		term.t_nrow = oldnrow;
222 		term.t_ncol = oldncol;
223 		vtfree();		/* get rid of the old VIDEOs (kept up to now in
224 			   case the new allocation had failed) */
225 		vtscreen(sp);	/* put the new VIDEOs into active duty */
226 		for (wp = sp->s_first_window; wp != NULL; wp = wp->w_wndp) {
227 			/* the VIDEOs have been wiped clean. Let's have every window
228 			   marked for a complete redraw */
229 			wp->w_flag |= WFHARD|WFMODE;
230 		}
231 		term.t_sizscr(sp); /* resize the MDI window */
232 		return(TRUE);
233 	}
234 	else {
235 		/* failure! we still need some kind of VIDEO structures, so we
236 			reuse the old ones */
237 		term.t_nrow = oldnrow;
238 		term.t_ncol = oldncol;
239 		sp->s_virtual = vscreen = oldvvp;
240 		sp->s_physical = pscreen = oldpvp;
241 		mlabort(TEXT94);	/* "out of memory" */
242 		return(FALSE);
243 	}
244 } /* vtsizescr */
245 #endif
246 
247 /*
248  * Clean up the virtual terminal system, in anticipation for a return to the
249  * operating system. Move down to the last line and clear it out (the next
250  * system prompt will be written in the line). Shut down the channel to the
251  * terminal.
252  */
vttidy()253 PASCAL NEAR vttidy()
254 {
255     mlerase();
256     movecursor(term.t_nrow, 0);
257     TTflush();
258     TTclose();
259     TTkclose();
260 }
261 
262 /*
263  * Set the virtual cursor to the specified row and column on the virtual
264  * screen. There is no checking for nonsense values; this might be a good
265  * idea during the early stages.
266  */
vtmove(row,col)267 PASCAL NEAR vtmove(row, col)
268 
269 int row, col;
270 
271 {
272     vtrow = row;
273     vtcol = col;
274 }
275 
276 /* Write a character to the virtual screen. The virtual row and
277    column are updated. If we are not yet on left edge, don't print
278    it yet. If the line is too long put a "$" in the last column.
279    This routine only puts printing characters into the virtual
280    terminal buffers. Only column overflow is checked.
281 */
282 
vtputc(c)283 PASCAL NEAR vtputc(c)
284 
285 int c;
286 
287 {
288 	register VIDEO *vp;	/* ptr to line being updated */
289 
290 	/* defeate automatic sign extenstion */
291 	c = c & 0xff;
292 
293 	/* this is the line to put this character! */
294 	vp = vscreen[vtrow];
295 
296 	if (c == '\t' && tabsize > 0) {
297 
298 		/* output a hardware tab as the right number of spaces */
299 		do {
300 			vtputc(' ');
301 		} while (((vtcol + taboff) % (tabsize)) != 0);
302 
303 	} else if (vtcol >= term.t_ncol) {
304 
305 		/* we are at the right edge! */
306 		++vtcol;
307 		vp->v_text[term.t_ncol - 1] = '$';
308 
309 	} else if (disphigh && c > 0x7f) {
310 
311 		/* char with high bit set is displayed
312 		   symbolically on 7 bit screens */
313 		vtputc('^');
314 		vtputc('!');
315 		c -= 0x80;
316 		if (c == '\t') {
317 			vtputc('^');
318 			vtputc('I');
319 		} else
320 			vtputc(c);
321 
322 	} else if (c < 0x20 || c == 0x7F) {
323 
324 		/* control character? */
325 		vtputc('^');
326 		vtputc(c ^ 0x40);
327 
328 	} else {
329 
330 		/* it's normal, just put it in the screen map */
331 		if (vtcol >= 0)
332 			vp->v_text[vtcol] = c;
333 		++vtcol;
334 	}
335 }
336 
337 /*
338  * Erase from the end of the software cursor to the end of the line on which
339  * the software cursor is located.
340  */
vteeol()341 PASCAL NEAR vteeol()
342 {
343     register VIDEO	*vp;
344 
345     vp = vscreen[vtrow];
346     while (vtcol < term.t_ncol) {
347     	if (vtcol >= 0)
348 		vp->v_text[vtcol] = ' ';
349 	vtcol++;
350     }
351 }
352 
353 /* upscreen:	user routine to force a screen update
354 		always finishes complete update 	*/
355 
upscreen(f,n)356 int PASCAL NEAR upscreen(f, n)
357 
358 int f,n;	/* prefix flag and argument */
359 
360 {
361 	update(TRUE);
362 	return(TRUE);
363 }
364 
365 /*
366  * Make sure that the display is right. This is a three part process. First,
367  * scan through all of the windows looking for dirty ones. Check the framing,
368  * and refresh the screen. Second, make sure that "currow" and "curcol" are
369  * correct for the current window. Third, make the virtual and physical
370  * screens the same.
371  */
update(force)372 VOID PASCAL NEAR update(force)
373 
374 int force;	/* force update past type ahead? */
375 
376 {
377 	register EWINDOW *wp;
378 #if     WINDOW_MSWIN
379 	SCREEN  *sp;
380 #endif
381 
382 #if	TYPEAH
383 	/* if we are not forcing the update, and there are keystrokes
384 	   waiting to be processed, skip the update */
385 	if (force == FALSE && typahead())
386 		return;
387 #endif
388 
389 #if	VISMAC == 0
390 	/* if we are replaying a keyboard macro, don't bother keeping updated */
391 	if (force == FALSE && kbdmode == PLAY)
392 		return;
393 #endif
394 
395 #if 	WINDOW_MSWIN
396 	/* if we are not forcing the update, allow us to defer it */
397 	if (force == FALSE) {
398 		defferupdate = TRUE;
399 		return;
400 	}
401 	else
402 		defferupdate = FALSE;
403 
404 	/* loop through all screens to update even partially hidden ones.
405 	   We update screens from back to front! */
406 	sp = first_screen;
407 	do {
408 		char scroll_flag = 0;
409 		int  scroll_fcol;
410 		static EWINDOW *scroll_wp = (EWINDOW *)NULL;
411 
412 		sp = sp->s_next_screen;
413 		if (sp == (SCREEN *)NULL) {
414 			sp = first_screen;
415 			sp->s_cur_window = curwp; /* not always up to date */
416 		}
417 		vtscreen(sp);
418 		wheadp = sp->s_first_window;
419 		scroll_fcol = sp->s_cur_window->w_fcol;
420 #endif
421 
422 		/* update any windows that need refreshing */
423 		wp = wheadp;
424 		while (wp != NULL) {
425 			if (wp->w_flag) {
426 				/* if the window has changed, service it */
427 				reframe(wp);	/* check the framing */
428 				if ((wp->w_flag & ~WFMODE) == WFEDIT)
429 					updone(wp);	/* update EDITed line */
430 				else if (wp->w_flag & ~WFMOVE)
431 					updall(wp);	/* update all lines */
432 				if (wp->w_flag & WFMODE)
433 					modeline(wp);	/* update modeline */
434 #if WINDOW_MSWIN
435 				if (wp == sp->s_cur_window) {
436 					if (wp != scroll_wp) {
437 						/* switched to another window,
438 						   force scroll bar updates */
439 						scroll_flag = WFHARD;
440 						scroll_wp = wp;
441 					} else
442 						scroll_flag = wp->w_flag & WFHARD;
443 
444 				}
445 #endif
446 				wp->w_flag = 0;
447 				wp->w_force = 0;
448 			}
449 
450 			/* on to the next window */
451 			wp = wp->w_wndp;
452 		}
453 
454 		/* recalc the current hardware cursor location */
455 #if 	WINDOW_MSWIN
456 		if (sp == first_screen) {
457 #endif
458 			updpos();
459 
460 			/* update the current window if we have to move it around */
461 			if (curwp->w_flag & WFHARD)
462 				updall(curwp);
463 			if (curwp->w_flag & WFMODE)
464 				modeline(curwp);
465 			curwp->w_flag = 0;
466 
467 			/* highlight region in the current window if needed */
468 			update_hilite();
469 
470 #if 	WINDOW_MSWIN
471 		}
472 #endif
473 
474 #if	MEMMAP
475 		/* update the cursor and flush the buffers */
476 		movecursor(currow, curcol - lbound);
477 #endif
478 
479 		/* check for lines to de-extend */
480 		upddex();
481 
482 		/* if screen is garbage, re-plot it */
483 		if (sgarbf != FALSE)
484 			if (gflags & GFSDRAW)
485 				sgarbf = FALSE;
486 			else
487 				updgar();
488 
489 		/* update the virtual screen to the physical screen */
490 		updupd(force);
491 #if 	WINDOW_MSWIN
492 		if (scroll_fcol != sp->s_cur_window->w_fcol) {
493 			scroll_flag |= WFMOVE;
494 		}
495 		if (scroll_flag)
496 			updscrollbars(sp, scroll_flag);
497 
498 	} while (sp != first_screen);
499 
500 	sgarbf = FALSE;
501 #endif
502 
503 	/* update the cursor and flush the buffers */
504 	movecursor(currow, curcol - lbound);
505 	TTflush();
506 
507 	return;
508 }
509 
510 /*	reframe:	check to see if the cursor is on in the window
511 			and re-frame it if needed or wanted		*/
512 
reframe(wp)513 VOID PASCAL NEAR reframe(wp)
514 
515 EWINDOW *wp;
516 
517 {
518 	register LINE *lp;	/* search pointer */
519 	register LINE *rp;	/* reverse search pointer */
520 	register LINE *hp;	/* ptr to header line in buffer */
521 	register LINE *tp;	/* temp debugging pointer */
522 	register int i;		/* general index/# lines to scroll */
523 	register int nlines;	/* number of lines in current window */
524 
525 	/* figure out our window size */
526 	nlines = wp->w_ntrows;
527 	if (modeflag == FALSE)
528 		nlines++;
529 
530 	/* if not a requested reframe, check for a needed one */
531 	if ((wp->w_flag & WFFORCE) == 0) {
532 		lp = wp->w_linep;
533 		for (i = 0; i < nlines; i++) {
534 
535 			/* if the line is in the window, no reframe */
536 			if (lp == wp->w_dotp)
537 				return;
538 
539 			/* if we are at the end of the file, reframe */
540 			if (lp == wp->w_bufp->b_linep)
541 				break;
542 
543 			/* on to the next line */
544 			lp = lforw(lp);
545 		}
546 	}
547 
548 	/* reaching here, we need a window refresh */
549 	i = wp->w_force;
550 
551 	/* if smooth scrolling is enabled,
552 		first.. have we gone off the top? */
553 	if (sscroll && ((wp->w_flag & WFFORCE) == 0)) {
554 		/* search thru the buffer looking for the point */
555 		tp = lp = rp = wp->w_linep;
556 		hp = wp->w_bufp->b_linep;
557 
558 		while ((lp != hp) || (rp != hp)) {
559 
560 			/* did we scroll downward? */
561 			if (lp == wp->w_dotp) {
562 				i = nlines - 1;
563 				break;
564 			}
565 
566 			/* did we scroll upward? */
567 			if (rp == wp->w_dotp) {
568 				i = 0;
569 				break;
570 			}
571 
572 			/* advance forward and back */
573 			if (lp != hp)
574 				lp = lforw(lp);
575 			if (rp != hp)
576 				rp = lback(rp);
577 
578 			/* problems????? */
579 			if (lp == tp || rp == tp) {
580 				mlforce("BUG IN SMOOTH SCROLL--GET DAN!\n");
581 				TTgetc();
582 			}
583 		}
584 	/* how far back to reframe? */
585 	} else if (i > 0) {	/* only one screen worth of lines max */
586 		if (--i >= nlines)
587 			i = nlines - 1;
588 	} else if (i < 0) {	/* negative update???? */
589 		i += nlines;
590 		if (i < 0)
591 			i = 0;
592 	} else
593 		i = nlines / 2;
594 
595 	/* backup to new line at top of window */
596 	lp = wp->w_dotp;
597 	while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
598 		--i;
599 		if (i < 0) {
600 			mlforce("OTHER BUG IN DISPLAY --- GET DAN!!!\n");
601 			TTgetc();
602 		}
603 		lp = lback(lp);
604 	}
605 
606 	/* and reset the current line at top of window */
607 	wp->w_linep = lp;
608 	wp->w_flag |= WFHARD;
609 	wp->w_flag &= ~WFFORCE;
610 }
611 
612 /*	hilite:	in the current window, marks 10 and 11 are set and the
613 		area between them is on screen, hilite that area	*/
614 
update_hilite()615 VOID PASCAL NEAR update_hilite()
616 
617 {
618 	int first_line;		/* first screen line to highlight */
619 	short first_pos;	/* position in that line */
620 	int last_line;		/* last screen line to highlight */
621 	short last_pos;		/* position in that line */
622 	LINE *forptr, *bckptr;	/* line pointers searching in current buffer */
623 	int forline, bckline;	/* screen lines of for/bck ptrs */
624 	int nlines;		/* number of text lines in current window */
625 	LINE *first_mark;	/* first mark to highlighted text */
626 	LINE *last_mark;	/* last mark to highlighted text */
627 	LINE *b_linep;		/* header line of current buffer */
628 	int temp_line;		/* temp line # for swap */
629 	short temp_pos;		/*  more of the same */
630 
631 	/* $hilight must be set to the first of 2 consecutive marks
632 	   used to define the region to highlight */
633 	if (hilite > NMARKS)
634 		return;
635 
636 	/* Both marks must be set to define a highlighted region */
637 	first_mark = curwp->w_markp[hilite];
638 	last_mark = curwp->w_markp[hilite+1];
639 	if ((first_mark == (LINE *)NULL) ||
640 	    (last_mark == (LINE *)NULL))
641 	    	return;
642 
643 	/* search for the two marks starting at the top line of this window */
644 	first_pos = last_pos = -1;
645 	forptr = curwp->w_linep;
646 	bckptr = curwp->w_linep;
647 	forline = bckline = 0;
648 	b_linep = curwp->w_bufp->b_linep;
649 	while (((first_pos == -1) || (last_pos == -1)) &&
650 		((forptr != (LINE *)NULL) || (bckptr != (LINE *)NULL))) {
651 
652 		/* have we found either mark? */
653 		if (forptr == first_mark) {
654 			first_line = forline;
655 			first_pos = findcol(forptr, curwp->w_marko[hilite]);
656 		}
657 		if (forptr == last_mark) {
658 			last_line = forline;
659 			last_pos = findcol(forptr, curwp->w_marko[hilite+1]);
660 		}
661 		if (bckptr == first_mark) {
662 			first_line = bckline;
663 			first_pos = findcol(bckptr, curwp->w_marko[hilite]);
664 		}
665 		if (bckptr == last_mark) {
666 			last_line = bckline;
667 			last_pos = findcol(bckptr, curwp->w_marko[hilite+1]);
668 		}
669 
670 		/* step outward one more line */
671 		if (forptr != (LINE *)NULL) {
672 			if (forptr != b_linep)
673 				forptr = lforw(forptr);
674 			else
675 				forptr = (LINE *)NULL;
676 			forline++;
677 		}
678 		if (bckptr != (LINE *)NULL) {
679 			bckptr = lback(bckptr);
680 			if (bckptr == b_linep)
681 				bckptr = (LINE *)NULL;
682 			bckline--;
683 		}
684 	}
685 
686 	/* if both lines are before the current window */
687 	if ((first_line < 0) && (last_line < 0))
688 		return;
689 
690 	/* if both lines are after the current window */
691 	nlines = curwp->w_ntrows;
692 	if (modeflag == FALSE)
693 		nlines++;
694 	if ((first_line >= nlines) && (last_line >= nlines))
695 		return;
696 
697 	/* if we got them backwards, swap them around */
698 	if ((first_line > last_line) ||
699 	    ((first_line == last_line) && (first_pos > last_pos))) {
700 		temp_line = first_line;
701 		first_line = last_line;
702 		last_line = temp_line;
703 		temp_pos = first_pos;
704 		first_pos = last_pos;
705 		last_pos = temp_pos;
706 	}
707 
708 	forptr = curwp->w_linep;
709 	forline = curwp->w_toprow;
710 	first_line += forline;
711 	last_line += forline;
712 	while (forline < curwp->w_toprow + nlines) {
713 		if ((forline >= first_line) && (forline <= last_line)) {
714 			vscreen[forline]->v_left = 0;
715 			vscreen[forline]->v_right = findcol(forptr, lused(forptr));
716 			if (forline == first_line)
717 				vscreen[forline]->v_left = first_pos;
718 			if (forline == last_line)
719 				vscreen[forline]->v_right = last_pos;
720 
721 			/* adjust for shifted window */
722 			vscreen[forline]->v_left -= curwp->w_fcol;
723 			vscreen[forline]->v_right -= curwp->w_fcol;
724 
725 			/* adjust for shifted line */
726 			if (vscreen[forline]->v_flag & VFEXT) {
727 				vscreen[forline]->v_left -= lbound;
728 				vscreen[forline]->v_right -= lbound;
729 			}
730 
731                 } else {
732                         vscreen[forline]->v_left = FARRIGHT;
733                         vscreen[forline]->v_right = 0;
734                 }
735 
736                 /* step up one more line */
737                 if (forptr != b_linep)
738                         forptr = lforw(forptr);
739                 forline++;
740         }
741 
742         /* we need to flag a redraw to update the hilighted region */
743         curwp->w_flag |= WFHARD;
744         return;
745 }
746 
747 /*      updone: update the current line to the virtual screen           */
748 
updone(wp)749 VOID PASCAL NEAR updone(wp)
750 
751 EWINDOW *wp;     /* window to update current line in */
752 
753 {
754         register LINE *lp;      /* line to update */
755         register int sline;     /* physical screen line to update */
756         register int i;
757 
758         /* search down the line we want */
759         lp = wp->w_linep;
760         sline = wp->w_toprow;
761         while (lp != wp->w_dotp) {
762                 ++sline;
763                 lp = lforw(lp);
764         }
765 
766         /* and update the virtual line */
767         vscreen[sline]->v_flag |= VFCHG;
768         taboff = wp->w_fcol;
769         vtmove(sline, -taboff);
770 
771         /* move each char of line to virtual screen until at end */
772         for (i=0; i < lused(lp); ++i)
773                 vtputc(lgetc(lp, i));
774 #if     COLOR
775         vscreen[sline]->v_rfcolor = wp->w_fcolor;
776         vscreen[sline]->v_rbcolor = wp->w_bcolor;
777 #endif
778         vteeol();
779         taboff = 0;
780 }
781 
782 /*      updall: update all the lines in a window on the virtual screen */
783 
updall(wp)784 VOID PASCAL NEAR updall(wp)
785 
786 EWINDOW *wp;     /* window to update lines in */
787 
788 {
789         register LINE *lp;      /* line to update */
790         register int sline;     /* physical screen line to update */
791         register int i;
792         register int nlines;    /* number of lines in the current window */
793 
794         /* search down the lines, updating them */
795         lp = wp->w_linep;
796         sline = wp->w_toprow;
797         nlines = wp->w_ntrows;
798         if (modeflag == FALSE)
799                 nlines++;
800         taboff = wp->w_fcol;
801         while (sline < wp->w_toprow + nlines) {
802 
803                 /* and update the virtual line */
804                 vscreen[sline]->v_flag |= VFCHG;
805                 vscreen[sline]->v_left = FARRIGHT;
806                 vscreen[sline]->v_right = 0;
807                 vtmove(sline, -taboff);
808                 if (lp != wp->w_bufp->b_linep) {
809                         /* if we are not at the end */
810                         for (i=0; i < lused(lp); ++i)
811                                 vtputc(lgetc(lp, i));
812                         lp = lforw(lp);
813                 }
814 
815                 /* make sure we are on screen */
816                 if (vtcol < 0)
817                         vtcol = 0;
818 
819                 /* on to the next one */
820 #if     COLOR
821                 vscreen[sline]->v_rfcolor = wp->w_fcolor;
822                 vscreen[sline]->v_rbcolor = wp->w_bcolor;
823 #endif
824                 vteeol();
825                 ++sline;
826         }
827         taboff = 0;
828 }
829 
830 /*      updpos: update the position of the hardware cursor and handle extended
831                 lines. This is the only update for simple moves.        */
832 
updpos()833 VOID PASCAL NEAR updpos()
834 
835 {
836         register LINE *lp;
837 
838         /* find the current row */
839         lp = curwp->w_linep;
840         currow = curwp->w_toprow;
841         while (lp != curwp->w_dotp) {
842                 ++currow;
843                 lp = lforw(lp);
844         }
845 
846         /* find the current column */
847 	curcol = getccol(FALSE);
848 
849         /* adjust by the current first column position */
850         curcol -= curwp->w_fcol;
851 
852         /* make sure it is not off the left side of the screen */
853         while (curcol < 0) {
854                 if (curwp->w_fcol >= hjump) {
855                         curcol += hjump;
856                         curwp->w_fcol -= hjump;
857                 } else {
858                         curcol += curwp->w_fcol;
859                         curwp->w_fcol = 0;
860                 }
861                 curwp->w_flag |= WFHARD | WFMODE;
862         }
863 
864         /* if horizontall scrolling is enabled, shift if needed */
865         if (hscroll) {
866                 while (curcol >= term.t_ncol - 1) {
867                         curcol -= hjump;
868                         curwp->w_fcol += hjump;
869                         curwp->w_flag |= WFHARD | WFMODE;
870                 }
871         } else {
872         /* if extended, flag so and update the virtual line image */
873                 if (curcol >=  term.t_ncol - 1) {
874                         vscreen[currow]->v_flag |= (VFEXT | VFCHG);
875                         updext();
876                 } else
877                         lbound = 0;
878         }
879 }
880 
881 /*      upddex: de-extend any line that derserves it            */
882 
upddex()883 VOID PASCAL NEAR upddex()
884 
885 {
886         register EWINDOW *wp;
887         register LINE *lp;
888         register int i,j;
889         register int nlines;    /* number of lines in the current window */
890 
891         wp = wheadp;
892 
893         while (wp != NULL) {
894                 lp = wp->w_linep;
895                 i = wp->w_toprow;
896                 nlines = wp->w_ntrows;
897                 if (modeflag == FALSE)
898                         nlines++;
899 
900                 while (i < wp->w_toprow + nlines) {
901                         if (vscreen[i]->v_flag & VFEXT) {
902                                 if ((wp != curwp) || (lp != wp->w_dotp) ||
903                                    (curcol < term.t_ncol - 1)) {
904                                         taboff = wp->w_fcol;
905                                         vtmove(i, -taboff);
906                                         for (j = 0; j < lused(lp); ++j)
907                                                 vtputc(lgetc(lp, j));
908                                         vteeol();
909                                         taboff = 0;
910 
911                                         /* this line no longer is extended */
912                                         vscreen[i]->v_flag &= ~VFEXT;
913                                         vscreen[i]->v_flag |= VFCHG;
914                                 }
915                         }
916                         lp = lforw(lp);
917                         ++i;
918                 }
919                 /* and onward to the next window */
920                 wp = wp->w_wndp;
921         }
922 }
923 
924 /*      updgar: if the screen is garbage, clear the physical screen and
925                 the virtual screen and force a full update              */
926 
updgar()927 VOID PASCAL NEAR updgar()
928 
929 {
930         register int i;
931 #if     MEMMAP == 0
932         register int j;
933         register char *txt;
934 #endif
935 
936         for (i = 0; i < term.t_nrow; ++i) {
937                 vscreen[i]->v_flag |= VFCHG;
938 #if     COLOR
939                 vscreen[i]->v_fcolor = gfcolor;
940                 vscreen[i]->v_bcolor = gbcolor;
941 #endif
942 #if     MEMMAP == 0
943                 pscreen[i]->v_left = FARRIGHT;
944                 pscreen[i]->v_right = 0;
945                 txt = pscreen[i]->v_text;
946                 for (j = 0; j < term.t_ncol; ++j)
947                         txt[j] = ' ';
948                 pscreen[i]->v_flag &= ~VFNEW;
949 #endif
950         }
951 
952         movecursor(0, 0);                /* Erase the screen. */
953 #if     COLOR && WINDOW_MSWIN
954         TTforg(gfcolor);        /* inform the driver of the colors */
955         TTbacg(gbcolor);        /* to be used for erase to end of page */
956 #endif
957 #if REVSTA && WINDOW_MSWIN
958         TTrev(FALSE);
959 #endif
960         TTeeop();
961 #if     !WINDOW_MSWIN
962         sgarbf = FALSE;                  /* Erase-page clears */
963         mpresf = FALSE;                  /* the message area. */
964 #endif
965 #if     COLOR
966         mlerase();                      /* needs to be cleared if colored */
967 #if     WINDOW_MSWIN
968         mpresf = FALSE;         /* MSWIN's message area handled differently.*/
969 #endif
970 #endif
971 }
972 
973 #if !WINDOW_MSWIN
974 /*      for simple screen size changes (no window re-allocation involved)
975         do the following things
976 */
977 
update_size()978 VOID PASCAL NEAR update_size()
979 
980 {
981         /* if we need the size update */
982         if ((first_screen->s_roworg != term.t_roworg) |
983             (first_screen->s_colorg != term.t_colorg) |
984             (first_screen->s_nrow != term.t_nrow) |
985             (first_screen->s_ncol != term.t_ncol)) {
986 
987                 /* reset the terminal drivers size concept */
988                 term.t_roworg = first_screen->s_roworg;
989                 term.t_colorg = first_screen->s_colorg;
990                 term.t_nrow = first_screen->s_nrow;
991                 term.t_ncol = first_screen->s_ncol;
992 
993                 /* make sure the update routines know we need a full update */
994                 sgarbf = TRUE;
995         }
996 }
997 #endif
998 
999 /*      Display a pop up window.  Page it for the user.  Any key other
1000         than a space gets pushed back into the input stream to be interpeted
1001         later as a command.
1002 */
1003 
1004 #if     PROTO
pop(BUFFER * popbuf)1005 int PASCAL NEAR pop(BUFFER *popbuf)
1006 #else
1007 int PASCAL NEAR pop(popbuf)
1008 
1009 BUFFER *popbuf;
1010 #endif
1011 {
1012         register int index;     /* index into the current output line */
1013         register int llen;      /* length of the current output line */
1014         register int cline;     /* current screen line number */
1015         LINE *lp;       /* ptr to next line to display */
1016         int numlines;   /* remaining number of lines to display */
1017         int c;          /* input character */
1018 
1019         /* add the barrior line to the end of the pop up buffer */
1020         addline(popbuf, "------------------------------------------");
1021 
1022         /* set up to scan pop up buffer */
1023         lp = lforw(popbuf->b_linep);
1024         numlines = term.t_nrow-2 + !modeflag;
1025         cline = 0;
1026 	mmove_flag = FALSE;	/* disable mouse move events */
1027 
1028         while (lp != popbuf->b_linep) {
1029 
1030                 /* update the virtual screen image for this one line */
1031                 vtmove(cline, 0);
1032                 llen = lused(lp);
1033                 for (index = 0; index < llen; index++)
1034                         vtputc(lgetc(lp, index));
1035                 vteeol();
1036 #if     COLOR
1037                 vscreen[cline]->v_rfcolor = gfcolor;
1038                 vscreen[cline]->v_rbcolor = gbcolor;
1039 #endif
1040                 vscreen[cline]->v_left = FARRIGHT;
1041                 vscreen[cline]->v_right = 0;
1042                 vscreen[cline++]->v_flag |= VFCHG|VFCOL;
1043 
1044                 if (numlines-- < 1) {
1045 
1046                         /* update the virtual screen to the physical screen */
1047                         updupd(FALSE);
1048 
1049                         /* tell the user there is more */
1050                         mlwrite("--- more ---");
1051                         TTflush();
1052 
1053                         /* and see if they want more */
1054                         if ((popwait) && ((c = tgetc()) != ' ')) {
1055                                 cpending = TRUE;
1056                                 charpending = c;
1057                                 upwind();
1058 
1059 				/* re-enable mouse move events */
1060 				mmove_flag = TRUE;
1061                                 return(TRUE);
1062                         }
1063 
1064                         /* reset the line counters */
1065                         numlines = term.t_nrow-2 + !modeflag;
1066                         cline = 0;
1067 
1068 			/* if we at the end, don't requeue for more */
1069 			if (lforw(lp) == popbuf->b_linep)
1070 				numlines = -1;
1071 
1072                 }
1073 
1074                 /* on to the next line */
1075                 lp = lforw(lp);
1076         }
1077         if (numlines >= 0) {
1078 
1079                 /* update the virtual screen to the physical screen */
1080                 updupd(FALSE);
1081                 TTflush();
1082 
1083                 if ((popwait) && ((c = tgetc()) != ' ')) {
1084                         cpending = TRUE;
1085                         charpending = c;
1086                 }
1087         }
1088         upwind();
1089 
1090 	/* re-enable mouse move events */
1091 	mmove_flag = TRUE;
1092         return(TRUE);
1093 }
1094 
1095 /*      updupd: update the physical screen from the virtual screen      */
1096 
updupd(force)1097 VOID PASCAL NEAR updupd(force)
1098 
1099 int force;      /* forced update flag */
1100 
1101 {
1102         register VIDEO *vp1;
1103         register int i;
1104 
1105         for (i = 0; i < term.t_nrow; ++i) {
1106                 vp1 = vscreen[i];
1107 
1108                 /* for each line that needs to be updated*/
1109                 if (vp1->v_flag & VFCHG) {
1110 #if     TYPEAH
1111                         if (force == FALSE && typahead())
1112                                 return;
1113 #endif
1114 #if     MEMMAP
1115                         update_line(i, vp1);
1116 #else
1117                         update_line(i, vp1, pscreen[i]);
1118 #endif
1119                 }
1120         }
1121         return;
1122 }
1123 
1124 /*      updext: update the extended line which the cursor is currently
1125                 on at a column greater than the terminal width. The line
1126                 will be scrolled right or left to let the user see where
1127                 the cursor is
1128                                                                 */
updext()1129 VOID PASCAL NEAR updext()
1130 
1131 {
1132         register int rcursor;   /* real cursor location */
1133         register LINE *lp;      /* pointer to current line */
1134         register int j;         /* index into line */
1135 
1136         /* calculate what column the real cursor will end up in */
1137         rcursor = ((curcol - term.t_ncol) % term.t_scrsiz)
1138                         + term.t_margin;
1139         lbound = curcol - rcursor + 1;
1140         taboff = lbound + curwp->w_fcol;
1141 
1142         /* scan through the line outputing characters to the virtual screen */
1143         /* once we reach the left edge                                  */
1144         vtmove(currow, -taboff); /* start scanning offscreen */
1145         lp = curwp->w_dotp;             /* line to output */
1146         for (j=0; j<lused(lp); ++j)     /* until the end-of-line */
1147                 vtputc(lgetc(lp, j));
1148 
1149         /* truncate the virtual line, restore tab offset */
1150         vteeol();
1151         taboff = 0;
1152 
1153         /* and put a '$' in column 1 */
1154         vscreen[currow]->v_text[0] = '$';
1155 }
1156 
1157 /*
1158  * Update a single line. This does not know how to use insert or delete
1159  * character sequences; we are using VT52 functionality. Update the physical
1160  * row and column variables. It does try an exploit erase to end of line.
1161  */
1162 #if     MEMMAP
1163 /*      UPDATE_LINE:    specific code for memory mapped displays */
1164 
update_line(row,vp)1165 VOID PASCAL NEAR update_line(row, vp)
1166 
1167 int row;                /* row of screen to update */
1168 struct VIDEO *vp;       /* virtual screen image */
1169 
1170 {
1171 #if     COLOR
1172         /* update the color request */
1173         vp->v_fcolor = vp->v_rfcolor;
1174         vp->v_bcolor = vp->v_rbcolor;
1175 
1176         /* write the line to the display */
1177         scwrite(row, vp->v_text, vp->v_fcolor, vp->v_bcolor,
1178                 vp->v_left, vp->v_right);
1179 #else
1180         /* write the line to the display */
1181         scwrite(row, vp->v_text, 7, 0, vp->v_left, vp->v_right);
1182 #endif
1183         /* flag this line as changed */
1184         vp->v_flag &= ~(VFCHG | VFCOL);
1185 }
1186 #else
update_line(row,vp,pp)1187 VOID PASCAL NEAR update_line(row, vp, pp)
1188 
1189 int row;                /* row of screen to update */
1190 struct VIDEO *vp;       /* virtual screen image */
1191 struct VIDEO *pp;       /* physical screen image */
1192 
1193 {
1194 
1195         register char *vir_left;        /* left pointer to virtual line */
1196         register char *phy_left;        /* left pointer to physical line */
1197         register char *vir_right;       /* right pointer to virtual line */
1198         register char *phy_right;       /* right pointer to physical line */
1199         int rev_left;                   /* leftmost reversed char index */
1200         int rev_right;                  /* rightmost reversed char index */
1201         char *left_blank;               /* left-most trailing blank */
1202         int non_blanks;                 /* non-blanks to the right flag */
1203         int update_column;              /* update column */
1204         int old_rev_state = FALSE;      /* reverse video states */
1205         int new_rev_state;
1206 
1207         /* set up pointers to virtual and physical lines */
1208         vir_left = &vp->v_text[0];
1209         vir_right = &vp->v_text[term.t_ncol];
1210         phy_left = &pp->v_text[0];
1211         phy_right = &pp->v_text[term.t_ncol];
1212         update_column = 0;
1213         rev_left = FARRIGHT;
1214         rev_right = 0;
1215 	non_blanks = TRUE;
1216 
1217         /* if this is a legitimate line to optimize */
1218         if (!(pp->v_flag & VFNEW)) {
1219 
1220                 /* advance past any common chars at the left */
1221                 while ((vir_left != &vp->v_text[term.t_ncol])
1222                        && (vir_left[0] == phy_left[0])) {
1223                         ++vir_left;
1224                         ++update_column;
1225                         ++phy_left;
1226                 }
1227 
1228 #if     DBCS
1229                 /* don't optimize on the left in the middle of a 2 byte char */
1230                 if ((vir_left > &vp->v_text[0]) && is2byte(vp->v_text, vir_left - 1)) {
1231                         --vir_left;
1232                         --update_column;
1233                         --phy_left;
1234                 }
1235 #endif
1236 
1237                 /* advance past any common chars at the right */
1238                 non_blanks = FALSE;
1239                 while ((vir_right[-1] == phy_right[-1]) &&
1240                        (vir_right >= vir_left)) {
1241                         --vir_right;
1242                         --phy_right;
1243 
1244                         /* Note if any nonblank in right match. */
1245                         if (vir_right[0] != ' ')
1246                                 non_blanks = TRUE;
1247                 }
1248 
1249 #if     DBCS
1250                 /* don't stop in the middle of a 2 byte char */
1251                 if (is2byte(vp->v_text, vir_right-1) || is2byte(pp->v_text, phy_right-1)) {
1252                         ++vir_right;
1253                         ++phy_right;
1254                 }
1255 #endif
1256         }
1257 
1258 #if     COLOR
1259         /* new line color? */
1260         if (((vp->v_rfcolor != vp->v_fcolor) ||
1261             (vp->v_rbcolor != vp->v_bcolor))) {
1262                 vp->v_fcolor = vp->v_rfcolor;
1263                 vp->v_bcolor = vp->v_rbcolor;
1264                 vp->v_flag &= ~VFCOL;
1265                 vir_left = &vp->v_text[0];
1266                 vir_right = &vp->v_text[term.t_ncol];
1267                 phy_left = &pp->v_text[0];
1268                 phy_right = &pp->v_text[term.t_ncol];
1269                 update_column = 0;
1270         }
1271 
1272         TTforg(vp->v_fcolor);
1273         TTbacg(vp->v_bcolor);
1274 #endif
1275 
1276         /* reverse video changes? */
1277         if ((vp->v_left != pp->v_left) || (vp->v_right != pp->v_right)) {
1278 
1279                 /* adjust leftmost edge */
1280                 if (vp->v_left < pp->v_left)
1281                         rev_left = vp->v_left;
1282                 else
1283                         rev_left = pp->v_left;
1284                 pp->v_left = vp->v_left;
1285                 if (rev_left < update_column) {
1286                         vir_left = &vp->v_text[rev_left];
1287                         phy_left = &pp->v_text[rev_left];
1288                         update_column = rev_left;
1289                 }
1290 
1291                 /* adjust rightmost edge */
1292                 if (vp->v_right > pp->v_right)
1293                         rev_right = vp->v_right;
1294                 else
1295                         rev_right = pp->v_right;
1296                 pp->v_right = vp->v_right;
1297                 if (&vp->v_text[rev_right] > vir_right) {
1298                         vir_right = &vp->v_text[rev_right];
1299                         phy_right = &pp->v_text[rev_right];
1300                 }
1301         } else {
1302                 rev_left = vp->v_left;
1303                 rev_right = vp->v_right;
1304         }
1305 
1306         /* if both lines are the same, no update needs to be done */
1307         if (!(pp->v_flag & VFNEW) && (vir_left > vir_right)) {
1308                 vp->v_flag &= ~VFCHG;   /* flag this line as changed */
1309                 return;
1310         }
1311 
1312         left_blank = vir_right;
1313 
1314         /* Erase to EOL ? */
1315         if (non_blanks == FALSE && eolexist == TRUE) {
1316                 while (left_blank!=vir_left && left_blank[-1]==' ')
1317                         --left_blank;
1318 
1319                 if (vir_right-left_blank <= 3)          /* Use only if erase is */
1320                         left_blank = vir_right;         /* fewer characters. */
1321         }
1322 
1323         /* move to the beginning of the text to update */
1324         movecursor(row, update_column);
1325 
1326         while (vir_left != left_blank) {                /* Ordinary. */
1327 
1328                 /* are we in a reverse video field? */
1329                 if (pp->v_left <= update_column && update_column < pp->v_right)
1330                         new_rev_state = TRUE;
1331                 else
1332                         new_rev_state = FALSE;
1333 
1334                 /* if moving in or out of rev video, change it */
1335                 if (new_rev_state != old_rev_state) {
1336                         TTrev(new_rev_state);
1337                         old_rev_state = new_rev_state;
1338 		}
1339 
1340 		/* output the next character! */
1341 		TTputc(*vir_left);
1342 		++ttcol;
1343 		++update_column;
1344 		*phy_left++ = *vir_left++;
1345 	}
1346 
1347 	if (left_blank != vir_right) {		/* Erase. */
1348 
1349                 /* are we in a reverse video field? */
1350                 if (pp->v_left <= update_column && update_column < pp->v_right)
1351                         new_rev_state = TRUE;
1352                 else
1353                         new_rev_state = FALSE;
1354 
1355                 /* if moving in or out of rev video, change it */
1356                 if (new_rev_state != old_rev_state) {
1357                         TTrev(new_rev_state);
1358                         old_rev_state = new_rev_state;
1359                 }
1360 
1361 #if	TERMCAP
1362 	/* TERMCAP does not tell us if the current terminal propagates
1363 	   the current attributes to the end of the line when an erase
1364 	   to end of line sequence is sent. Don't let TERMCAP use EEOL
1365 	   if in a reverse video line!  (ARG...Pain....Agony....)      */
1366 		if (new_rev_state == TRUE)
1367 			while (update_column++ < term.t_ncol)
1368 				TTputc(' ');
1369 		else
1370 			TTeeol();
1371 #else
1372 		TTeeol();
1373 #endif
1374 		while (vir_left != vir_right)
1375 			*phy_left++ = *vir_left++;
1376 	}
1377 
1378 	vp->v_flag &= ~VFCHG;		/* flag this line as updated */
1379 	vp->v_flag &= ~VFCOL;
1380 
1381 	/* Always leave in the default state */
1382 	if (old_rev_state == TRUE)
1383 		TTrev(FALSE);
1384 	return;
1385 }
1386 #endif
1387 
1388 /*
1389  * Redisplay the mode line for the window pointed to by the "wp". This is the
1390  * only routine that has any idea of how the modeline is formatted. You can
1391  * change the modeline format by hacking at this routine. Called by "update"
1392  * any time there is a dirty window.
1393  */
modeline(wp)1394 VOID PASCAL NEAR modeline(wp)
1395 
1396 EWINDOW *wp;	/* window to update modeline for */
1397 
1398 {
1399 	register char *cp;
1400 	register unsigned char c;
1401 	register int n;		/* cursor position count */
1402 	register BUFFER *bp;
1403 	register int i;		/* loop index */
1404 	register int lchar; 	/* character to draw line in buffer with */
1405 	register int firstm;	/* is this the first mode? */
1406 	char tline[NLINE];	/* buffer for part of mode line */
1407 	char time[6];		/* to hold current time */
1408 
1409 	/* don't bother if there is none! */
1410 	if (modeflag == FALSE)
1411 		return;
1412 
1413 	n = wp->w_toprow+wp->w_ntrows;		/* Location. */
1414 
1415 /*
1416 	Note that we assume that setting REVERSE will cause the terminal
1417 	driver to draw with the inverted relationship of fcolor and
1418 	bcolor, so that when we say to set the foreground color to "white"
1419 	and background color to "black", the fact that "reverse" is
1420 	enabled means that the terminal driver actually draws "black" on a
1421 	background of "white".  Makes sense, no?  This way, devices for
1422 	which the color controls are optional will still get the "reverse"
1423 	signals.
1424 */
1425 
1426 	vscreen[n]->v_flag |= VFCHG | VFCOL;	/* Redraw next time. */
1427 	vscreen[n]->v_left = 0;
1428 	vscreen[n]->v_right = term.t_ncol;
1429 #if	COLOR
1430 	vscreen[n]->v_rfcolor = 7;			/* black on */
1431 	vscreen[n]->v_rbcolor = 0;			/* white.....*/
1432 #endif
1433 	vtmove(n, 0);				/* Seek to right line. */
1434 	if (wp == curwp)			/* mark the current buffer */
1435 		lchar = '=';
1436 	else
1437 #if	REVSTA
1438 	if (revexist)
1439 		lchar = ' ';
1440 	else
1441 #endif
1442 		lchar = '-';
1443 
1444 	bp = wp->w_bufp;
1445 	if ((bp->b_flag&BFTRUNC) != 0)		/* "#" if truncated */
1446 		vtputc('#');
1447 	else
1448 		vtputc(lchar);
1449 
1450 	if ((bp->b_flag&BFCHG) != 0)		/* "*" if changed. */
1451 		vtputc('*');
1452 	else
1453 		vtputc(lchar);
1454 
1455 	if ((bp->b_flag&BFNAROW) != 0) {		/* "<>" if narrowed */
1456 		vtputc('<');
1457 		vtputc('>');
1458 	} else {
1459 		vtputc(lchar);
1460 		vtputc(lchar);
1461 	}
1462 
1463 	n  = 4;
1464 	strcpy(tline, " "); 			/* Buffer name. */
1465 #if     !WINDOW_MSWIN
1466 	strcat(tline, PROGNAME);
1467 	strcat(tline, " ");
1468 	strcat(tline, VERSION);
1469 	strcat(tline, " ");
1470 #endif
1471 	/* display the time on the bottom most modeline if active */
1472 	if (timeflag && wp->w_wndp == (EWINDOW *)NULL) {
1473 
1474 		/* get the current time/date string */
1475 		getdtime(time);
1476 		if (strcmp(time, "") != 0) {
1477 
1478 			/* append the hour/min string */
1479 			strcat(tline, "[");
1480 			strcat(tline, time);
1481 			strcat(tline, "] ");
1482 			strcpy(lasttime, time);
1483 		}
1484 	}
1485 
1486 	/* display the size of the undo stack on the current modeline */
1487 	if (dispundo && wp == curwp) {
1488 		strcat(tline, "{");
1489 		strcat(tline, long_asc(wp->w_bufp->undo_count));
1490 		strcat(tline, "} ");
1491 	}
1492 
1493 	/* are we horizontally scrolled? */
1494 	if (wp->w_fcol > 0) {
1495 		strcat(tline, "[<");
1496 		strcat(tline, int_asc(wp->w_fcol));
1497 		strcat(tline, "]");
1498 	}
1499 
1500 	/* display the point position in buffer if on current modeline */
1501 	if (posflag && wp == curwp) {
1502 
1503  		strcat(tline, "L:");
1504 	 	strcat(tline, long_asc(getlinenum(bp, wp->w_dotp)));
1505  		strcat(tline, " C:");
1506 	 	strcat(tline, int_asc(getccol(FALSE)));
1507  		strcat(tline, " ");
1508 	}
1509 
1510 	/* display the modes */
1511 	strcat(tline, "(");
1512 	firstm = TRUE;
1513 	for (i = 0; i < NUMMODES; i++)	/* add in the mode flags */
1514 		if (wp->w_bufp->b_mode & (1 << i)) {
1515 			if (firstm != TRUE)
1516 				strcat(tline, " ");
1517 			firstm = FALSE;
1518 			strcat(tline, modename[i]);
1519 		}
1520 	strcat(tline,") ");
1521 
1522 	cp = &tline[0];
1523 	while ((c = *cp++) != 0) {
1524 		vtputc(c);
1525 		++n;
1526 	}
1527 
1528 #if	0	/* display internal modes on modeline */
1529 	vtputc(lchar);
1530 	vtputc((wp->w_flag&WFCOLR) != 0  ? 'C' : lchar);
1531 	vtputc((wp->w_flag&WFMODE) != 0  ? 'M' : lchar);
1532 	vtputc((wp->w_flag&WFHARD) != 0  ? 'H' : lchar);
1533 	vtputc((wp->w_flag&WFEDIT) != 0  ? 'E' : lchar);
1534 	vtputc((wp->w_flag&WFMOVE) != 0  ? 'V' : lchar);
1535 	vtputc((wp->w_flag&WFFORCE) != 0 ? 'F' : lchar);
1536 	vtputc(lchar);
1537 	n += 8;
1538 #endif
1539 
1540 	vtputc(lchar);
1541 	vtputc(lchar);
1542 	vtputc(' ');
1543 	n += 3;
1544 	cp = &bp->b_bname[0];
1545 
1546 	while ((c = *cp++) != 0) {
1547 		vtputc(c);
1548 		++n;
1549 	}
1550 
1551 	vtputc(' ');
1552 	vtputc(lchar);
1553 	vtputc(lchar);
1554 	n += 3;
1555 
1556 	if (bp->b_fname[0] != 0) {	/* File name. */
1557 		vtputc(' ');
1558 		++n;
1559 		cp = TEXT34;
1560 /*                   "File: " */
1561 
1562 		while ((c = *cp++) != 0) {
1563 			vtputc(c);
1564 			++n;
1565 		}
1566 
1567 		cp = &bp->b_fname[0];
1568 
1569 		while ((c = *cp++) != 0) {
1570 			vtputc(c);
1571 			++n;
1572 	        }
1573 
1574 		vtputc(' ');
1575 		++n;
1576 	}
1577 
1578 	while (n < term.t_ncol) {	/* Pad to full width. */
1579 		vtputc(lchar);
1580 		++n;
1581 	}
1582 }
1583 
getdtime(ts)1584 VOID PASCAL NEAR getdtime(ts)	/* get the current display time string */
1585 
1586 char *ts;
1587 
1588 {
1589 	char buf[80];
1590 
1591 	strcpy(buf, timeset());
1592 	if (strcmp(buf, errorm) == 0) {
1593 		*ts = 0;
1594 		return;
1595 	}
1596 
1597 	buf[16] = 0;
1598 	strcpy(ts, &buf[11]);
1599 	return;
1600 }
1601 
upmode()1602 VOID PASCAL NEAR upmode()	/* update all the mode lines */
1603 
1604 {
1605 	register EWINDOW *wp;
1606 #if     WINDOW_MSWIN
1607     SCREEN  *sp;
1608 
1609     /* loop through all screens to update even partially hidden ones.
1610        Note that we process the "first" screen last */
1611     sp = first_screen;
1612     do {
1613         sp = sp->s_next_screen;
1614         if (sp == (SCREEN *)NULL) sp = first_screen;
1615         vtscreen (sp);
1616         wheadp = sp->s_first_window;
1617 #endif
1618 
1619 	wp = wheadp;
1620 	while (wp != NULL) {
1621 		wp->w_flag |= WFMODE;
1622 		wp = wp->w_wndp;
1623 	}
1624 #if     WINDOW_MSWIN
1625     } while (sp != first_screen);
1626 #endif
1627 }
1628 
upwind()1629 VOID PASCAL NEAR upwind()	/* force hard updates on all windows */
1630 
1631 {
1632 	register EWINDOW *wp;
1633 #if     WINDOW_MSWIN
1634     SCREEN  *sp;
1635 
1636     /* loop through all screens to update even partially hidden ones.
1637        Note that we process the "first" screen last */
1638     sp = first_screen;
1639     do {
1640         sp = sp->s_next_screen;
1641         if (sp == (SCREEN *)NULL) sp = first_screen;
1642         vtscreen (sp);
1643         wheadp = sp->s_first_window;
1644 #endif
1645 
1646 	wp = wheadp;
1647 	while (wp != NULL) {
1648 		wp->w_flag |= WFHARD|WFMODE;
1649 		wp = wp->w_wndp;
1650 	}
1651 #if     WINDOW_MSWIN
1652 	} while (sp != first_screen);
1653 #endif
1654 }
1655 
1656 /*
1657  * Send a command to the terminal to move the hardware cursor to row "row"
1658  * and column "col". The row and column arguments are origin 0. Optimize out
1659  * random calls. Update "ttrow" and "ttcol".
1660  */
movecursor(row,col)1661 VOID PASCAL NEAR movecursor(row, col)
1662 
1663 int row, col;
1664 
1665 {
1666 #if     WINDOW_MSWIN
1667 	/* emphasize move into message line to avoid confusion with
1668 	   another, larger, screen */
1669 	if (row >= term.t_nrow)
1670 		row = term.t_mrow;
1671 
1672 	/* a pending update could move the cursor somewhere else, so
1673 	   we make sure it can't happen */
1674 	if (defferupdate)
1675 		update (TRUE);
1676 
1677 	/* in MSWIN, the message line is a separate entity and a call to
1678 	   vtscreen after a movecursor calls might actually have "stolen" the
1679 	   cursor away from the message line! */
1680 	if (row!=ttrow || col!=ttcol || foulcursor) {
1681 		foulcursor = FALSE;
1682 #else
1683 	/* only move it if there is a difference */
1684 	if (row != ttrow || col != ttcol) {
1685 #endif
1686 		ttrow = row;
1687 		ttcol = col;
1688 		TTmove(row, col);
1689 	}
1690 }
1691 
1692 /*
1693  * Erase the message line. This is a special routine because the message line
1694  * is not considered to be part of the virtual screen. It always works
1695  * immediately; the terminal buffer is flushed via a call to the flusher.
1696  */
1697 
mlferase()1698 VOID PASCAL NEAR mlferase()
1699 
1700 {
1701 	register int save_discmd;
1702 
1703 	save_discmd = discmd;
1704 	discmd = TRUE;
1705 	mlerase();
1706 	discmd = save_discmd;;
1707 }
1708 
mlerase()1709 VOID PASCAL NEAR mlerase()
1710 
1711 {
1712 	int i;
1713 
1714 	movecursor(term.t_nrow, 0);
1715 	if (discmd == FALSE)
1716 		return;
1717 
1718 #if	COLOR
1719 	TTforg(gfcolor);
1720 	TTbacg(gbcolor);
1721 #endif
1722 
1723 	if (eolexist == TRUE)
1724 		TTeeol();
1725 	else {
1726 		for (i = 0; i < term.t_ncol - 1; i++)
1727 			TTputc(' ');
1728 
1729 		/* force the move! */
1730 /*		movecursor(term.t_nrow, 1);*/
1731 		movecursor(term.t_nrow, 0);
1732 	}
1733 	TTflush();
1734 	mpresf = FALSE;
1735 }
1736 
1737 /*
1738  * Write a message into the message line. Keep track of the physical cursor
1739  * position. A small class of printf like format items is handled. Assumes the
1740  * stack grows down; this assumption is made by the "+=" in the argument scan
1741  * loop. If  STACK_GROWS_UP  is set in estruct.h, then we'll assume that the
1742  * stack grows up and use "-=" instead of "+=". Set the "message line"
1743  *  flag TRUE.  Don't write beyond the end of the current terminal width.
1744  */
1745 
mlout(c)1746 VOID PASCAL NEAR mlout(c)
1747 
1748 int c;	/* character to write */
1749 
1750 {
1751 #if WINDOW_MSWIN
1752 	if (ttcol + 1 < NSTRING)
1753 #else
1754 	if (ttcol + 1 < term.t_ncol)
1755 #endif
1756 		TTputc(c);
1757 	if (c != '\b')
1758 		*lastptr++ = c;
1759 	else if (lastptr > &lastmesg[0])
1760 		--lastptr;
1761 }
1762 
1763 #if	VARARG
1764 #if	VARG
mlwrite(va_alist)1765 VOID CDECL NEAR mlwrite(va_alist)
1766 
1767 va_dcl		/* variable argument list
1768 			arg1 = format string
1769 			arg2+ = arguments in that string */
1770 
1771 {
1772 	register int c; 	/* current char in format string */
1773 	register char *fmt;	/* ptr to format string */
1774 	register va_list ap;	/* ptr to current data field */
1775 	int arg_int;		/* integer argument */
1776 	long arg_long;		/* long argument */
1777 	char *arg_str;		/* string argument */
1778 
1779 	/* if we are not currently echoing on the command line, abort this */
1780 	if (discmd == FALSE)
1781 		return;
1782 
1783 #if	COLOR
1784 	/* set up the proper colors for the command line */
1785 	TTforg(gfcolor);
1786 	TTbacg(gbcolor);
1787 #endif
1788 
1789 	/* point to the first argument */
1790 	va_start(ap);
1791 	fmt = va_arg(ap, char *);
1792 
1793 	/* if we can not erase to end-of-line, do it manually */
1794 	if (eolexist == FALSE) {
1795 		mlerase();
1796 		TTflush();
1797 	}
1798 
1799 	movecursor(term.t_nrow, 0);
1800  	lastptr = &lastmesg[0];		/* setup to record message */
1801 	while ((c = *fmt++) != 0) {
1802 		if (c != '%') {
1803 			mlout(c);
1804 			++ttcol;
1805 		} else {
1806 			c = *fmt++;
1807 			switch (c) {
1808 				case 'd':
1809 					arg_int = va_arg(ap, int);
1810 					mlputi(arg_int, 10);
1811 					break;
1812 
1813 				case 'o':
1814 					arg_int = va_arg(ap, int);
1815 					mlputi(arg_int, 8);
1816 					break;
1817 
1818 				case 'x':
1819 					arg_int = va_arg(ap, int);
1820 					mlputi(arg_int, 16);
1821 					break;
1822 
1823 				case 'D':
1824 					arg_long = va_arg(ap, long);
1825 					mlputli(arg_long, 10);
1826 					break;
1827 
1828 				case 's':
1829 					arg_str = va_arg(ap, char *);
1830 					mlputs(arg_str);
1831 					break;
1832 
1833 				case 'f':
1834 					arg_int = va_arg(ap, int);
1835 					mlputf(arg_int);
1836 					break;
1837 
1838 				default:
1839 					mlout(c);
1840 					++ttcol;
1841 			}
1842 		}
1843 	}
1844 
1845 	/* if we can, erase to the end of screen */
1846 	if (eolexist == TRUE)
1847 		TTeeol();
1848 	TTflush();
1849 	mpresf = TRUE;
1850 	*lastptr = 0;	/* terminate lastmesg[] */
1851 	va_end(ap);
1852 }
1853 #else
1854 #if PROTO
mlwrite(char * fmt,...)1855 VOID CDECL NEAR mlwrite(char *fmt, ...)
1856 /* char * fmt;*/
1857 #else
1858 VOID CDECL NEAR mlwrite()
1859 char *fmt;
1860 #endif
1861 
1862 		/* variable argument list
1863 			arg1 = format string
1864 			arg2+ = arguments in that string */
1865 
1866 {
1867 	register int c; 	/* current char in format string */
1868 	va_list ap;		/* ptr to current data field */
1869 	int arg_int;		/* integer argument */
1870 	long arg_long;		/* long argument */
1871 	char *arg_str;		/* string argument */
1872 
1873 	/* if we are not currently echoing on the command line, abort this */
1874 	if (discmd == FALSE)
1875 		return;
1876 
1877 #if	COLOR
1878 	/* set up the proper colors for the command line */
1879 	TTforg(gfcolor);
1880 	TTbacg(gbcolor);
1881 #endif
1882 
1883 	/* point to the first argument */
1884 	va_start(ap, fmt);
1885 
1886 	/* if we can not erase to end-of-line, do it manually */
1887 	if (eolexist == FALSE) {
1888 		mlerase();
1889 		TTflush();
1890 	}
1891 
1892 	movecursor(term.t_nrow, 0);
1893  	lastptr = &lastmesg[0];		/* setup to record message */
1894 	while ((c = *fmt++) != 0) {
1895 		if (c != '%') {
1896 			mlout(c);
1897 			++ttcol;
1898 		} else {
1899 			c = *fmt++;
1900 			switch (c) {
1901 				case 'd':
1902 					arg_int = va_arg(ap, int);
1903 					mlputi(arg_int, 10);
1904 					break;
1905 
1906 				case 'o':
1907 					arg_int = va_arg(ap, int);
1908 					mlputi(arg_int, 8);
1909 					break;
1910 
1911 				case 'x':
1912 					arg_int = va_arg(ap, int);
1913 					mlputi(arg_int, 16);
1914 					break;
1915 
1916 				case 'D':
1917 					arg_long = va_arg(ap, long);
1918 					mlputli(arg_long, 10);
1919 					break;
1920 
1921 				case 's':
1922 					arg_str = va_arg(ap, char *);
1923 					mlputs(arg_str);
1924 					break;
1925 
1926 				case 'f':
1927 					arg_int = va_arg(ap, int);
1928 					mlputf(arg_int);
1929 					break;
1930 
1931 				default:
1932 					mlout(c);
1933 					++ttcol;
1934 			}
1935 		}
1936 	}
1937 
1938 	/* if we can, erase to the end of screen */
1939 	if (eolexist == TRUE)
1940 		TTeeol();
1941 	TTflush();
1942 	mpresf = TRUE;
1943 	*lastptr = 0;	/* terminate lastmesg[] */
1944 	va_end(ap);
1945 }
1946 #endif
1947 #else
1948 
1949 #if	STACK_GROWS_UP
1950 #define	ADJUST(ptr, dtype)	ptr -= sizeof(dtype)
1951 #else
1952 #define	ADJUST(ptr, dtype)	ptr += sizeof(dtype)
1953 #endif
1954 
mlwrite(fmt)1955 VOID CDECL NEAR mlwrite(fmt)
1956 
1957 char *fmt;	/* format string for output */
1958 
1959 {
1960 	register int c; 	/* current char in format string */
1961 	register char *ap;	/* ptr to current data field */
1962 
1963 	/* if we are not currently echoing on the command line, abort this */
1964 	if (discmd == FALSE)
1965 		return;
1966 
1967 #if	COLOR
1968 	/* set up the proper colors for the command line */
1969 	TTforg(gfcolor);
1970 	TTbacg(gbcolor);
1971 #endif
1972 
1973 	/* point to the first argument */
1974 	ap = &fmt;
1975 	ADJUST(ap, char *);
1976 
1977 	/* if we can not erase to end-of-line, do it manually */
1978 	if (eolexist == FALSE) {
1979 		mlerase();
1980 		TTflush();
1981 	}
1982 
1983 	movecursor(term.t_nrow, 0);
1984  	lastptr = &lastmesg[0];		/* setup to record message */
1985 	while ((c = *fmt++) != 0) {
1986 		if (c != '%') {
1987 			mlout(c);
1988 			++ttcol;
1989 		} else {
1990 			c = *fmt++;
1991 			switch (c) {
1992 				case 'd':
1993 					mlputi(*(int *)ap, 10);
1994 			                ADJUST(ap, int);
1995 					break;
1996 
1997 				case 'o':
1998 					mlputi(*(int *)ap,  8);
1999 					ADJUST(ap, int);
2000 					break;
2001 
2002 				case 'x':
2003 					mlputi(*(int *)ap, 16);
2004 					ADJUST(ap, int);
2005 					break;
2006 
2007 				case 'D':
2008 					mlputli(*(long *)ap, 10);
2009 					ADJUST(ap, long);
2010 					break;
2011 
2012 				case 's':
2013 					mlputs(*(char **)ap);
2014 					ADJUST(ap, char *);
2015 					break;
2016 
2017 				case 'f':
2018 					mlputf(*(int *)ap);
2019 					ADJUST(ap, int);
2020 					break;
2021 
2022 				default:
2023 					mlout(c);
2024 					++ttcol;
2025 			}
2026 		}
2027 	}
2028 
2029 	/* if we can, erase to the end of screen */
2030 	if (eolexist == TRUE)
2031 		TTeeol();
2032 	TTflush();
2033 	mpresf = TRUE;
2034 	*lastptr = 0;	/* terminate lastmesg[] */
2035 }
2036 #endif
2037 /*	Force a string out to the message line regardless of the
2038 	current $discmd setting. This is needed when $debug is TRUE
2039 	and for the write-message and clear-message-line commands
2040 */
2041 
mlforce(s)2042 VOID PASCAL NEAR mlforce(s)
2043 
2044 char *s;	/* string to force out */
2045 
2046 {
2047 	register int oldcmd;	/* original command display flag */
2048 
2049 	oldcmd = discmd;	/* save the discmd value */
2050 	discmd = TRUE;		/* and turn display on */
2051 	mlwrite("%s", s);	/* write the string out */
2052 	discmd = oldcmd;	/* and restore the original setting */
2053 }
2054 
2055 #if     !WINDOW_MSWIN
2056 /* display a serious error message (like "out of memory"). This is
2057    replaced by a system-specific function when a multitasking system
2058    that does not like these kind of errors is used, so that the user can
2059    be offered to abort the application */
2060 
mlabort(s)2061 VOID PASCAL NEAR mlabort(s)
2062 char *s;
2063 {
2064     mlforce(s);
2065 }
2066 #endif
2067 
2068 /*
2069  * Write out a string. Update the physical cursor position. This assumes that
2070  * the characters in the string all have width "1"; if this is not the case
2071  * things will get screwed up a little.
2072  */
2073 
mlputs(s)2074 VOID PASCAL NEAR mlputs(s)
2075 
2076 char *s;
2077 
2078 {
2079 	register int c;
2080 
2081 	while ((c = *s++) != 0) {
2082 		mlout(c);
2083 		++ttcol;
2084 	}
2085 }
2086 
2087 /*
2088  * Write out an integer, in the specified radix. Update the physical cursor
2089  * position.
2090  */
mlputi(i,r)2091 VOID PASCAL NEAR mlputi(i, r)
2092 
2093 int i, r;
2094 
2095     {
2096     register int q;
2097     static char hexdigits[] = "0123456789ABCDEF";
2098 
2099     if (i < 0)
2100 	{
2101 	i = -i;
2102 	mlout('-');
2103 	}
2104 
2105     q = i/r;
2106 
2107     if (q != 0)
2108 	mlputi(q, r);
2109 
2110     mlout(hexdigits[i%r]);
2111     ++ttcol;
2112     }
2113 
2114 /*
2115  * do the same except as a long integer.
2116  */
mlputli(l,r)2117 VOID PASCAL NEAR mlputli(l, r)
2118 
2119 long l;
2120 int r;
2121 
2122     {
2123     register long q;
2124 
2125     if (l < 0)
2126 	{
2127 	l = -l;
2128 	mlout('-');
2129 	}
2130 
2131     q = l/r;
2132 
2133     if (q != 0)
2134 	mlputli(q, r);
2135 
2136     mlout((int)(l%r)+'0');
2137     ++ttcol;
2138     }
2139 
2140 /*
2141  *	write out a scaled integer with two decimal places
2142  */
2143 
mlputf(s)2144 VOID PASCAL NEAR mlputf(s)
2145 
2146 int s;	/* scaled integer to output */
2147 
2148 {
2149 	int i;	/* integer portion of number */
2150 	int f;	/* fractional portion of number */
2151 
2152 	/* break it up */
2153 	i = s / 100;
2154 	f = s % 100;
2155 
2156 	/* send out the integer portion */
2157 	mlputi(i, 10);
2158 	mlout('.');
2159 	mlout((f / 10) + '0');
2160 	mlout((f % 10) + '0');
2161 	ttcol += 3;
2162 }
2163 
2164 #if HANDLE_WINCH
winch_vtresize(rows,cols)2165 winch_vtresize(rows, cols)
2166      int rows, cols;
2167 {
2168   int i;
2169   register VIDEO *vp;
2170 
2171   for (i = 0; i < term.t_mrow; ++i) {
2172     free(vscreen[i]);
2173     free(pscreen[i]);
2174   }
2175   free(vscreen);
2176   free(pscreen);
2177 
2178   term.t_mrow=term.t_nrow=rows-1;
2179   term.t_mcol=term.t_ncol=cols;
2180 
2181   vscreen = (VIDEO **)room(term.t_mrow*sizeof(VIDEO *));
2182 
2183   if (vscreen == NULL)
2184     meexit(1);
2185 
2186   pscreen = (VIDEO **)room(term.t_mrow*sizeof(VIDEO *));
2187 
2188   if (pscreen == NULL)
2189     meexit(1);
2190 
2191   for (i = 0; i < term.t_mrow; ++i)
2192     {
2193       vp = (VIDEO *)room(sizeof(VIDEO)+term.t_mcol);
2194 
2195       if (vp == NULL)
2196 	meexit(1);
2197 
2198       vp->v_flag = 0;
2199       vp->v_left = FARRIGHT;
2200       vp->v_right = 0;
2201       vp->v_flag = VFNEW;
2202 #if	COLOR
2203       vp->v_rfcolor = 7;
2204       vp->v_rbcolor = 0;
2205 #endif
2206 #if	INSDEL
2207       vp->v_rline = i;
2208 #endif
2209       vscreen[i] = vp;
2210       vp = (VIDEO *)room(sizeof(VIDEO)+term.t_mcol);
2211 
2212       if (vp == NULL)
2213 	meexit(1);
2214 
2215       vp->v_flag = VFNEW;
2216       vp->v_left = FARRIGHT;
2217       vp->v_right = 0;
2218 #if	INSDEL
2219       vp->v_rline = i;	/* set requested line position */
2220 #endif
2221 
2222       pscreen[i] = vp;
2223     }
2224 }
2225 #endif
2226 
2227