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