3 * The functions in this file handle redisplay. There are two halves, the
4 * ones that update the virtual display screen, and the ones that make the
5 * physical display screen the same as the virtual display screen. These
6 * functions use hints that are left in the windows by the commands.
8 * modified by Petri Kutvonen
22 int v_flag
; /* Flags */
24 int v_fcolor
; /* current forground color */
25 int v_bcolor
; /* current background color */
26 int v_rfcolor
; /* requested forground color */
27 int v_rbcolor
; /* requested background color */
29 char v_text
[1]; /* Screen data. */
32 #define VFCHG 0x0001 /* Changed flag */
33 #define VFEXT 0x0002 /* extended (beyond column 80) */
34 #define VFREV 0x0004 /* reverse video status */
35 #define VFREQ 0x0008 /* reverse video request */
36 #define VFCOL 0x0010 /* color change requested */
38 static struct video
**vscreen
; /* Virtual screen. */
39 #if MEMMAP == 0 || SCROLLCODE
40 static struct video
**pscreen
; /* Physical screen. */
43 static int displaying
= TRUE
;
48 #include <sys/ioctl.h>
49 /* for window size changes */
50 int chg_width
, chg_height
;
53 static int reframe(struct window
*wp
);
54 static void updone(struct window
*wp
);
55 static void updall(struct window
*wp
);
56 static int scrolls(int inserts
);
57 static void scrscroll(int from
, int to
, int count
);
58 static int texttest(int vrow
, int prow
);
59 static int endofline(char *s
, int n
);
60 static void updext(void);
61 static int updateline(int row
, struct video
*vp1
, struct video
*vp2
);
62 static void modeline(struct window
*wp
);
63 static void mlputi(int i
, int r
);
64 static void mlputli(long l
, int r
);
65 static void mlputf(int s
);
66 static int newscreensize(int h
, int w
);
69 static void putline(int row
, int col
, char *buf
);
73 * Initialize the data structures used by the display code. The edge vectors
74 * used to access the screens are set up. The operating system's terminal I/O
75 * channel is set up. All the other things get initialized at compile time.
76 * The original window has "WFCHG" set, so that it will get completely
77 * redrawn on the first call to "update".
84 TTopen(); /* open the screen */
85 TTkopen(); /* open the keyboard */
87 vscreen
= (struct video
**) malloc(term
.t_mrow
* sizeof(struct video
*));
92 #if MEMMAP == 0 || SCROLLCODE
93 pscreen
= (struct video
**) malloc(term
.t_mrow
* sizeof(struct video
*));
99 for (i
= 0; i
< term
.t_mrow
; ++i
) {
100 vp
= (struct video
*)malloc(sizeof(struct video
) + term
.t_mcol
);
111 #if MEMMAP == 0 || SCROLLCODE
112 vp
= (struct video
*)malloc(sizeof(struct video
) + term
.t_mcol
);
124 /* free up all the dynamically allocated video structures */
129 for (i
= 0; i
< term
.t_mrow
; ++i
) {
131 #if MEMMAP == 0 || SCROLLCODE
136 #if MEMMAP == 0 || SCROLLCODE
143 * Clean up the virtual terminal system, in anticipation for a return to the
144 * operating system. Move down to the last line and clear it out (the next
145 * system prompt will be written in the line). Shut down the channel to the
151 movecursor(term
.t_nrow
, 0);
156 fwrite("\r", 1, 1, stdout
);
161 * Set the virtual cursor to the specified row and column on the virtual
162 * screen. There is no checking for nonsense values; this might be a good
163 * idea during the early stages.
165 void vtmove(int row
, int col
)
172 * Write a character to the virtual screen. The virtual row and
173 * column are updated. If we are not yet on left edge, don't print
174 * it yet. If the line is too long put a "$" in the last column.
176 * This routine only puts printing characters into the virtual
177 * terminal buffers. Only column overflow is checked.
179 static void vtputc(unsigned char c
)
181 struct video
*vp
; /* ptr to line being updated */
185 if (vtcol
>= term
.t_ncol
) {
187 vp
->v_text
[term
.t_ncol
- 1] = '$';
194 } while (((vtcol
+ taboff
) & tabmask
) != 0);
210 if (c
>= 0x80 && c
< 0xA0) {
211 static const char hex
[] = "0123456789abcdef";
219 vp
->v_text
[vtcol
] = c
;
224 * Erase from the end of the software cursor to the end of the line on which
225 * the software cursor is located.
227 static void vteeol(void)
229 /* struct video *vp; */
230 char *vcp
= vscreen
[vtrow
]->v_text
;
232 /* vp = vscreen[vtrow]; */
233 while (vtcol
< term
.t_ncol
)
234 /* vp->v_text[vtcol++] = ' '; */
240 * user routine to force a screen update
241 * always finishes complete update
243 int upscreen(int f
, int n
)
254 * Make sure that the display is right. This is a three part process. First,
255 * scan through all of the windows looking for dirty ones. Check the framing,
256 * and refresh the screen. Second, make sure that "currow" and "curcol" are
257 * correct for the current window. Third, make the virtual and physical
260 * int force; force update past type ahead?
262 int update(int force
)
266 #if TYPEAH && ! PKCODE
267 if (force
== FALSE
&& typahead())
271 if (force
== FALSE
&& kbdmode
== PLAY
)
279 /* first, propagate mode line changes to all instances of
280 a buffer displayed in more than one window */
283 if (wp
->w_flag
& WFMODE
) {
284 if (wp
->w_bufp
->b_nwnd
> 1) {
285 /* make sure all previous windows have this */
288 while (owp
!= NULL
) {
289 if (owp
->w_bufp
== wp
->w_bufp
)
290 owp
->w_flag
|= WFMODE
;
300 /* update any windows that need refreshing */
304 /* if the window has changed, service it */
305 reframe(wp
); /* check the framing */
307 if (wp
->w_flag
& (WFKILLS
| WFINS
)) {
309 (wp
->w_flag
& (WFINS
| WFKILLS
));
310 wp
->w_flag
&= ~(WFKILLS
| WFINS
);
313 if ((wp
->w_flag
& ~WFMODE
) == WFEDIT
)
314 updone(wp
); /* update EDITed line */
315 else if (wp
->w_flag
& ~WFMOVE
)
316 updall(wp
); /* update all lines */
318 if (scrflags
|| (wp
->w_flag
& WFMODE
))
320 if (wp
->w_flag
& WFMODE
)
322 modeline(wp
); /* update modeline */
326 /* on to the next window */
330 /* recalc the current hardware cursor location */
333 #if MEMMAP && ! SCROLLCODE
334 /* update the cursor and flush the buffers */
335 movecursor(currow
, curcol
- lbound
);
338 /* check for lines to de-extend */
341 /* if screen is garbage, re-plot it */
345 /* update the virtual screen to the physical screen */
348 /* update the cursor and flush the buffers */
349 movecursor(currow
, curcol
- lbound
);
353 while (chg_width
|| chg_height
)
354 newscreensize(chg_height
, chg_width
);
361 * check to see if the cursor is on in the window
362 * and re-frame it if needed or wanted
364 static int reframe(struct window
*wp
)
366 struct line
*lp
, *lp0
;
369 /* if not a requested reframe, check for a needed one */
370 if ((wp
->w_flag
& WFFORCE
) == 0) {
372 /* loop from one line above the window to one line after */
375 if (lp0
== wp
->w_bufp
->b_linep
)
381 for (; i
<= (int) (wp
->w_ntrows
); i
++)
384 for (i
= 0; i
< wp
->w_ntrows
; i
++)
387 /* if the line is in the window, no reframe */
388 if (lp
== wp
->w_dotp
) {
390 /* if not _quite_ in, we'll reframe gently */
391 if (i
< 0 || i
== wp
->w_ntrows
) {
392 /* if the terminal can't help, then
393 we're simply outside */
394 if (term
.t_scroll
== NULL
)
402 /* if we are at the end of the file, reframe */
403 if (lp
== wp
->w_bufp
->b_linep
)
406 /* on to the next line */
411 if (i
== -1) { /* we're just above the window */
412 i
= scrollcount
; /* put dot at first line */
414 } else if (i
== wp
->w_ntrows
) { /* we're just below the window */
415 i
= -scrollcount
; /* put dot at last line */
417 } else /* put dot where requested */
419 i
= wp
->w_force
; /* (is 0, unless reposition() was called) */
421 wp
->w_flag
|= WFMODE
;
423 /* how far back to reframe? */
424 if (i
> 0) { /* only one screen worth of lines max */
425 if (--i
>= wp
->w_ntrows
)
426 i
= wp
->w_ntrows
- 1;
427 } else if (i
< 0) { /* negative update???? */
432 i
= wp
->w_ntrows
/ 2;
434 /* backup to new line at top of window */
436 while (i
!= 0 && lback(lp
) != wp
->w_bufp
->b_linep
) {
441 /* and reset the current line at top of window */
443 wp
->w_flag
|= WFHARD
;
444 wp
->w_flag
&= ~WFFORCE
;
450 * update the current line to the virtual screen
452 * struct window *wp; window to update current line in
454 static void updone(struct window
*wp
)
456 struct line
*lp
; /* line to update */
457 int sline
; /* physical screen line to update */
460 /* search down the line we want */
462 sline
= wp
->w_toprow
;
463 while (lp
!= wp
->w_dotp
) {
468 /* and update the virtual line */
469 vscreen
[sline
]->v_flag
|= VFCHG
;
470 vscreen
[sline
]->v_flag
&= ~VFREQ
;
472 for (i
= 0; i
< llength(lp
); ++i
)
473 vtputc(lgetc(lp
, i
));
475 vscreen
[sline
]->v_rfcolor
= wp
->w_fcolor
;
476 vscreen
[sline
]->v_rbcolor
= wp
->w_bcolor
;
483 * update all the lines in a window on the virtual screen
485 * struct window *wp; window to update lines in
487 static void updall(struct window
*wp
)
489 struct line
*lp
; /* line to update */
490 int sline
; /* physical screen line to update */
493 /* search down the lines, updating them */
495 sline
= wp
->w_toprow
;
496 while (sline
< wp
->w_toprow
+ wp
->w_ntrows
) {
498 /* and update the virtual line */
499 vscreen
[sline
]->v_flag
|= VFCHG
;
500 vscreen
[sline
]->v_flag
&= ~VFREQ
;
502 if (lp
!= wp
->w_bufp
->b_linep
) {
503 /* if we are not at the end */
504 for (i
= 0; i
< llength(lp
); ++i
)
505 vtputc(lgetc(lp
, i
));
509 /* on to the next one */
511 vscreen
[sline
]->v_rfcolor
= wp
->w_fcolor
;
512 vscreen
[sline
]->v_rbcolor
= wp
->w_bcolor
;
522 * update the position of the hardware cursor and handle extended
523 * lines. This is the only update for simple moves.
531 /* find the current row */
533 currow
= curwp
->w_toprow
;
534 while (lp
!= curwp
->w_dotp
) {
539 /* find the current column */
542 while (i
< curwp
->w_doto
) {
546 else if (c
< 0x20 || c
== 0x7f)
548 else if (c
>= 0x80 && c
<= 0xa0)
554 /* if extended, flag so and update the virtual line image */
555 if (curcol
>= term
.t_ncol
- 1) {
556 vscreen
[currow
]->v_flag
|= (VFEXT
| VFCHG
);
564 * de-extend any line that derserves it
578 while (i
< wp
->w_toprow
+ wp
->w_ntrows
) {
579 if (vscreen
[i
]->v_flag
& VFEXT
) {
580 if ((wp
!= curwp
) || (lp
!= wp
->w_dotp
) ||
581 (curcol
< term
.t_ncol
- 1)) {
583 for (j
= 0; j
< llength(lp
); ++j
)
584 vtputc(lgetc(lp
, j
));
587 /* this line no longer is extended */
588 vscreen
[i
]->v_flag
&= ~VFEXT
;
589 vscreen
[i
]->v_flag
|= VFCHG
;
595 /* and onward to the next window */
602 * if the screen is garbage, clear the physical screen and
603 * the virtual screen and force a full update
610 for (i
= 0; i
< term
.t_nrow
; ++i
) {
611 vscreen
[i
]->v_flag
|= VFCHG
;
613 vscreen
[i
]->v_flag
&= ~VFREV
;
616 vscreen
[i
]->v_fcolor
= gfcolor
;
617 vscreen
[i
]->v_bcolor
= gbcolor
;
619 #if MEMMAP == 0 || SCROLLCODE
620 txt
= pscreen
[i
]->v_text
;
621 for (j
= 0; j
< term
.t_ncol
; ++j
)
626 movecursor(0, 0); /* Erase the screen. */
628 sgarbf
= FALSE
; /* Erase-page clears */
629 mpresf
= FALSE
; /* the message area. */
631 mlerase(); /* needs to be cleared if colored */
637 * update the physical screen from the virtual screen
639 * int force; forced update flag
641 int updupd(int force
)
647 if (scrflags
& WFKILLS
)
649 if (scrflags
& WFINS
)
654 for (i
= 0; i
< term
.t_nrow
; ++i
) {
657 /* for each line that needs to be updated */
658 if ((vp1
->v_flag
& VFCHG
) != 0) {
659 #if TYPEAH && ! PKCODE
660 if (force
== FALSE
&& typahead())
663 #if MEMMAP && ! SCROLLCODE
666 updateline(i
, vp1
, pscreen
[i
]);
676 * optimize out scrolls (line breaks, and newlines)
677 * arg. chooses between looking for inserts or deletes
679 static int scrolls(int inserts
)
680 { /* returns true if it does something */
681 struct video
*vpv
; /* virtual screen image */
682 struct video
*vpp
; /* physical screen image */
685 int first
, match
, count
, target
, end
;
686 int longmatch
, longcount
;
689 if (!term
.t_scroll
) /* no way to scroll */
696 for (i
= 0; i
< rows
; i
++) { /* find first wrong line */
697 if (!texttest(i
, i
)) {
704 return FALSE
; /* no text changes */
706 vpv
= vscreen
[first
];
707 vpp
= pscreen
[first
];
710 /* determine types of potential scrolls */
711 end
= endofline(vpv
->v_text
, cols
);
713 target
= first
; /* newlines */
714 else if (strncmp(vpp
->v_text
, vpv
->v_text
, end
) == 0)
715 target
= first
+ 1; /* broken line newlines */
722 /* find the matching shifted area */
727 for (i
= from
+ 1; i
< rows
- longcount
/* P.K. */ ; i
++) {
728 if (inserts
? texttest(i
, from
) : texttest(from
, i
)) {
731 for (j
= match
+ 1, k
= from
+ 1;
732 j
< rows
&& k
< rows
; j
++, k
++) {
733 if (inserts
? texttest(j
, k
) :
739 if (longcount
< count
) {
749 /* full kill case? */
750 if (match
> 0 && texttest(first
, match
- 1)) {
758 if (match
> 0 && count
> 2) { /* got a scroll */
759 /* move the count lines starting at target to match */
771 "scrolls: move the %d lines starting at %d to %d, first %d, scrolls %d",
772 count
, from
, to
, first
,
773 2 * count
>= abs(from
- to
));
777 if (2 * count
< abs(from
- to
))
779 scrscroll(from
, to
, count
);
780 for (i
= 0; i
< count
; i
++) {
781 vpp
= pscreen
[to
+ i
];
782 vpv
= vscreen
[to
+ i
];
783 strncpy(vpp
->v_text
, vpv
->v_text
, cols
);
784 vpp
->v_flag
= vpv
->v_flag
; /* XXX */
785 if (vpp
->v_flag
& VFREV
) {
786 vpp
->v_flag
&= ~VFREV
;
787 vpp
->v_flag
|= ~VFREQ
;
790 vscreen
[to
+ i
]->v_flag
&= ~VFCHG
;
797 from
= target
+ count
;
801 for (i
= from
; i
< to
; i
++) {
803 txt
= pscreen
[i
]->v_text
;
804 for (j
= 0; j
< term
.t_ncol
; ++j
)
806 vscreen
[i
]->v_flag
|= VFCHG
;
814 /* move the "count" lines starting at "from" to "to" */
815 static void scrscroll(int from
, int to
, int count
)
818 (*term
.t_scroll
) (from
, to
, count
);
822 * return TRUE on text match
824 * int vrow, prow; virtual, physical rows
826 static int texttest(int vrow
, int prow
)
828 struct video
*vpv
= vscreen
[vrow
]; /* virtual screen image */
829 struct video
*vpp
= pscreen
[prow
]; /* physical screen image */
831 return !memcmp(vpv
->v_text
, vpp
->v_text
, term
.t_ncol
);
835 * return the index of the first blank of trailing whitespace
837 static int endofline(char *s
, int n
)
840 for (i
= n
- 1; i
>= 0; i
--)
846 #endif /* SCROLLCODE */
850 * update the extended line which the cursor is currently
851 * on at a column greater than the terminal width. The line
852 * will be scrolled right or left to let the user see where
855 static void updext(void)
857 int rcursor
; /* real cursor location */
858 struct line
*lp
; /* pointer to current line */
859 int j
; /* index into line */
861 /* calculate what column the real cursor will end up in */
862 rcursor
= ((curcol
- term
.t_ncol
) % term
.t_scrsiz
) + term
.t_margin
;
863 taboff
= lbound
= curcol
- rcursor
+ 1;
865 /* scan through the line outputing characters to the virtual screen */
866 /* once we reach the left edge */
867 vtmove(currow
, -lbound
); /* start scanning offscreen */
868 lp
= curwp
->w_dotp
; /* line to output */
869 for (j
= 0; j
< llength(lp
); ++j
) /* until the end-of-line */
870 vtputc(lgetc(lp
, j
));
872 /* truncate the virtual line, restore tab offset */
876 /* and put a '$' in column 1 */
877 vscreen
[currow
]->v_text
[0] = '$';
881 * Update a single line. This does not know how to use insert or delete
882 * character sequences; we are using VT52 functionality. Update the physical
883 * row and column variables. It does try an exploit erase to end of line. The
884 * RAINBOW version of this routine uses fast video.
887 /* UPDATELINE specific code for the IBM-PC and other compatables */
889 static int updateline(int row
, struct video
*vp1
, struct video
*vp2
)
896 cp1
= &vp1
->v_text
[0];
897 cp2
= &vp2
->v_text
[0];
907 scwrite(row
, vp1
->v_text
, vp1
->v_rfcolor
, vp1
->v_rbcolor
);
908 vp1
->v_fcolor
= vp1
->v_rfcolor
;
909 vp1
->v_bcolor
= vp1
->v_rbcolor
;
911 if (vp1
->v_flag
& VFREQ
)
912 scwrite(row
, vp1
->v_text
, 0, 7);
914 scwrite(row
, vp1
->v_text
, 7, 0);
916 vp1
->v_flag
&= ~(VFCHG
| VFCOL
); /* flag this line as changed */
925 * int row; row of screen to update
926 * struct video *vp1; virtual screen image
927 * struct video *vp2; physical screen image
929 static int updateline(int row
, struct video
*vp1
, struct video
*vp2
)
932 /* UPDATELINE specific code for the DEC rainbow 100 micro */
938 /* since we don't know how to make the rainbow do this, turn it off */
939 flags
&= (~VFREV
& ~VFREQ
);
941 cp1
= &vp1
->v_text
[0]; /* Use fast video. */
942 cp2
= &vp2
->v_text
[0];
943 putline(row
+ 1, 1, cp1
);
954 /* UPDATELINE code for all other versions */
961 int nbflag
; /* non-blanks to the right flag? */
962 int rev
; /* reverse video flag */
963 int req
; /* reverse video request flag */
966 /* set up pointers to virtual and physical lines */
967 cp1
= &vp1
->v_text
[0];
968 cp2
= &vp2
->v_text
[0];
971 TTforg(vp1
->v_rfcolor
);
972 TTbacg(vp1
->v_rbcolor
);
976 /* if we need to change the reverse video status of the
977 current line, we need to re-write the entire line */
978 rev
= (vp1
->v_flag
& VFREV
) == VFREV
;
979 req
= (vp1
->v_flag
& VFREQ
) == VFREQ
;
982 || (vp1
->v_fcolor
!= vp1
->v_rfcolor
)
983 || (vp1
->v_bcolor
!= vp1
->v_rbcolor
)
986 movecursor(row
, 0); /* Go to start of line. */
987 /* set rev video if needed */
991 /* scan through the line and dump it to the screen and
992 the virtual screen array */
993 cp3
= &vp1
->v_text
[term
.t_ncol
];
999 /* turn rev video off */
1001 (*term
.t_rev
) (FALSE
);
1003 /* update the needed flags */
1004 vp1
->v_flag
&= ~VFCHG
;
1006 vp1
->v_flag
|= VFREV
;
1008 vp1
->v_flag
&= ~VFREV
;
1010 vp1
->v_fcolor
= vp1
->v_rfcolor
;
1011 vp1
->v_bcolor
= vp1
->v_rbcolor
;
1017 /* advance past any common chars at the left */
1018 while (cp1
!= &vp1
->v_text
[term
.t_ncol
] && cp1
[0] == cp2
[0]) {
1023 /* This can still happen, even though we only call this routine on changed
1024 * lines. A hard update is always done when a line splits, a massive
1025 * change is done, or a buffer is displayed twice. This optimizes out most
1026 * of the excess updating. A lot of computes are used, but these tend to
1027 * be hard operations that do a lot of update, so I don't really care.
1029 /* if both lines are the same, no update needs to be done */
1030 if (cp1
== &vp1
->v_text
[term
.t_ncol
]) {
1031 vp1
->v_flag
&= ~VFCHG
; /* flag this line is changed */
1035 /* find out if there is a match on the right */
1037 cp3
= &vp1
->v_text
[term
.t_ncol
];
1038 cp4
= &vp2
->v_text
[term
.t_ncol
];
1040 while (cp3
[-1] == cp4
[-1]) {
1043 if (cp3
[0] != ' ') /* Note if any nonblank */
1044 nbflag
= TRUE
; /* in right match. */
1049 /* Erase to EOL ? */
1050 if (nbflag
== FALSE
&& eolexist
== TRUE
&& (req
!= TRUE
)) {
1051 while (cp5
!= cp1
&& cp5
[-1] == ' ')
1054 if (cp3
- cp5
<= 3) /* Use only if erase is */
1055 cp5
= cp3
; /* fewer characters. */
1058 movecursor(row
, cp1
- &vp1
->v_text
[0]); /* Go to start of line. */
1063 while (cp1
!= cp5
) { /* Ordinary. */
1069 if (cp5
!= cp3
) { /* Erase. */
1077 vp1
->v_flag
&= ~VFCHG
; /* flag this line as updated */
1084 * Redisplay the mode line for the window pointed to by the "wp". This is the
1085 * only routine that has any idea of how the modeline is formatted. You can
1086 * change the modeline format by hacking at this routine. Called by "update"
1087 * any time there is a dirty window.
1089 static void modeline(struct window
*wp
)
1093 int n
; /* cursor position count */
1095 int i
; /* loop index */
1096 int lchar
; /* character to draw line in buffer with */
1097 int firstm
; /* is this the first mode? */
1098 char tline
[NLINE
]; /* buffer for part of mode line */
1100 n
= wp
->w_toprow
+ wp
->w_ntrows
; /* Location. */
1101 vscreen
[n
]->v_flag
|= VFCHG
| VFREQ
| VFCOL
; /* Redraw next time. */
1103 vscreen
[n
]->v_rfcolor
= 0; /* black on */
1104 vscreen
[n
]->v_rbcolor
= 7; /* white..... */
1106 vtmove(n
, 0); /* Seek to right line. */
1107 if (wp
== curwp
) /* mark the current buffer */
1123 if ((bp
->b_flag
& BFTRUNC
) != 0)
1129 if ((bp
->b_flag
& BFCHG
) != 0) /* "*" if changed. */
1137 strcat(tline
, PROGRAM_NAME_LONG
);
1139 strcat(tline
, VERSION
);
1140 strcat(tline
, ": ");
1142 while ((c
= *cp
++) != 0) {
1147 cp
= &bp
->b_bname
[0];
1148 while ((c
= *cp
++) != 0) {
1153 strcpy(tline
, " (");
1155 /* display the modes */
1158 if ((bp
->b_flag
& BFTRUNC
) != 0) {
1160 strcat(tline
, "Truncated");
1162 for (i
= 0; i
< NUMMODES
; i
++) /* add in the mode flags */
1163 if (wp
->w_bufp
->b_mode
& (1 << i
)) {
1167 strcat(tline
, mode2name
[i
]);
1169 strcat(tline
, ") ");
1172 while ((c
= *cp
++) != 0) {
1179 vtputc((wp
->w_flag
& WFCOLR
) != 0 ? 'C' : lchar
);
1180 vtputc((wp
->w_flag
& WFMODE
) != 0 ? 'M' : lchar
);
1181 vtputc((wp
->w_flag
& WFHARD
) != 0 ? 'H' : lchar
);
1182 vtputc((wp
->w_flag
& WFEDIT
) != 0 ? 'E' : lchar
);
1183 vtputc((wp
->w_flag
& WFMOVE
) != 0 ? 'V' : lchar
);
1184 vtputc((wp
->w_flag
& WFFORCE
) != 0 ? 'F' : lchar
);
1190 if (bp
->b_fname
[0] != 0 && strcmp(bp
->b_bname
, bp
->b_fname
) != 0)
1192 if (bp
->b_fname
[0] != 0) /* File name. */
1198 while ((c
= *cp
++) != 0) {
1204 cp
= &bp
->b_fname
[0];
1206 while ((c
= *cp
++) != 0) {
1215 while (n
< term
.t_ncol
) { /* Pad to full width. */
1220 { /* determine if top line, bottom line, or both are visible */
1221 struct line
*lp
= wp
->w_linep
;
1222 int rows
= wp
->w_ntrows
;
1225 vtcol
= n
- 7; /* strlen(" top ") plus a couple */
1228 if (lp
== wp
->w_bufp
->b_linep
) {
1233 if (lback(wp
->w_linep
) == wp
->w_bufp
->b_linep
) {
1235 if (wp
->w_linep
== wp
->w_bufp
->b_linep
)
1245 int numlines
, predlines
, ratio
;
1247 lp
= lforw(bp
->b_linep
);
1250 while (lp
!= bp
->b_linep
) {
1251 if (lp
== wp
->w_linep
) {
1252 predlines
= numlines
;
1257 if (wp
->w_dotp
== bp
->b_linep
) {
1263 (100L * predlines
) / numlines
;
1266 sprintf(tline
, " %2d%% ", ratio
);
1272 while ((c
= *cp
++) != 0) {
1280 { /* update all the mode lines */
1284 while (wp
!= NULL
) {
1285 wp
->w_flag
|= WFMODE
;
1291 * Send a command to the terminal to move the hardware cursor to row "row"
1292 * and column "col". The row and column arguments are origin 0. Optimize out
1293 * random calls. Update "ttrow" and "ttcol".
1295 void movecursor(int row
, int col
)
1297 if (row
!= ttrow
|| col
!= ttcol
) {
1305 * Erase the message line. This is a special routine because the message line
1306 * is not considered to be part of the virtual screen. It always works
1307 * immediately; the terminal buffer is flushed via a call to the flusher.
1313 movecursor(term
.t_nrow
, 0);
1314 if (discmd
== FALSE
)
1321 if (eolexist
== TRUE
)
1324 for (i
= 0; i
< term
.t_ncol
- 1; i
++)
1326 movecursor(term
.t_nrow
, 1); /* force the move! */
1327 movecursor(term
.t_nrow
, 0);
1334 * Write a message into the message line. Keep track of the physical cursor
1335 * position. A small class of printf like format items is handled. Assumes the
1336 * stack grows down; this assumption is made by the "++" in the argument scan
1337 * loop. Set the "message line" flag TRUE.
1339 * char *fmt; format string for output
1340 * char *arg; pointer to first argument to print
1342 void mlwrite(const char *fmt
, ...)
1344 int c
; /* current char in format string */
1347 /* if we are not currently echoing on the command line, abort this */
1348 if (discmd
== FALSE
) {
1349 movecursor(term
.t_nrow
, 0);
1353 /* set up the proper colors for the command line */
1358 /* if we can not erase to end-of-line, do it manually */
1359 if (eolexist
== FALSE
) {
1364 movecursor(term
.t_nrow
, 0);
1366 while ((c
= *fmt
++) != 0) {
1374 mlputi(va_arg(ap
, int), 10);
1378 mlputi(va_arg(ap
, int), 8);
1382 mlputi(va_arg(ap
, int), 16);
1386 mlputli(va_arg(ap
, long), 10);
1390 mlputs(va_arg(ap
, char *));
1394 mlputf(va_arg(ap
, int));
1405 /* if we can, erase to the end of screen */
1406 if (eolexist
== TRUE
)
1413 * Force a string out to the message line regardless of the
1414 * current $discmd setting. This is needed when $debug is TRUE
1415 * and for the write-message and clear-message-line commands
1417 * char *s; string to force out
1419 void mlforce(char *s
)
1421 int oldcmd
; /* original command display flag */
1423 oldcmd
= discmd
; /* save the discmd value */
1424 discmd
= TRUE
; /* and turn display on */
1425 mlwrite(s
); /* write the string out */
1426 discmd
= oldcmd
; /* and restore the original setting */
1430 * Write out a string. Update the physical cursor position. This assumes that
1431 * the characters in the string all have width "1"; if this is not the case
1432 * things will get screwed up a little.
1434 void mlputs(char *s
)
1438 while ((c
= *s
++) != 0) {
1445 * Write out an integer, in the specified radix. Update the physical cursor
1448 static void mlputi(int i
, int r
)
1451 static char hexdigits
[] = "0123456789ABCDEF";
1463 TTputc(hexdigits
[i
% r
]);
1468 * do the same except as a long integer.
1470 static void mlputli(long l
, int r
)
1484 TTputc((int) (l
% r
) + '0');
1489 * write out a scaled integer with two decimal places
1491 * int s; scaled integer to output
1493 static void mlputf(int s
)
1495 int i
; /* integer portion of number */
1496 int f
; /* fractional portion of number */
1502 /* send out the integer portion */
1505 TTputc((f
/ 10) + '0');
1506 TTputc((f
% 10) + '0');
1512 static void putline(int row
, int col
, char *buf
)
1517 if (col
+ n
- 1 > term
.t_ncol
)
1518 n
= term
.t_ncol
- col
+ 1;
1519 Put_Data(row
, col
, n
, buf
);
1523 /* Get terminal size from system.
1524 Store number of lines into *heightp and width into *widthp.
1525 If zero or a negative number is stored, the value is not valid. */
1527 void getscreensize(int *widthp
, int *heightp
)
1530 struct winsize size
;
1533 if (ioctl(0, TIOCGWINSZ
, &size
) < 0)
1535 *widthp
= size
.ws_col
;
1536 *heightp
= size
.ws_row
;
1544 void sizesignal(int signr
)
1547 int old_errno
= errno
;
1549 getscreensize(&w
, &h
);
1551 if (h
&& w
&& (h
- 1 != term
.t_nrow
|| w
!= term
.t_ncol
))
1552 newscreensize(h
, w
);
1554 signal(SIGWINCH
, sizesignal
);
1558 static int newscreensize(int h
, int w
)
1560 /* do the change later */
1566 chg_width
= chg_height
= 0;
1567 if (h
- 1 < term
.t_mrow
)
1569 if (w
< term
.t_mcol
)