home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD2.mdf
/
c
/
newemacs
/
display.c
< prev
next >
Wrap
Text File
|
1979-12-31
|
16KB
|
757 lines
/*
* The functions in this file
* handle redisplay. There are two halves,
* the ones that update the virtual display
* screen, and the ones that make the physical
* display screen the same as the virtual
* display screen. These functions use hints
* that are left in the windows by the
* commands.
*/
#include <stdio.h>
#include "ed.h"
typedef struct VIDEO {
short v_flag; /* Flags */
char v_text[1]; /* Screen data. */
} VIDEO;
#define VFCHG 0x0001 /* Changed. */
int sgarbf = TRUE; /* TRUE if screen is garbage */
int mpresf = FALSE; /* TRUE if message in last line */
int vtrow = 0; /* Row location of SW cursor */
int vtcol = 0; /* Column location of SW cursor */
int ttrow = HUGE; /* Row location of HW cursor */
int ttcol = HUGE; /* Column location of HW cursor */
VIDEO **vscreen; /* Virtual screen. */
VIDEO **pscreen; /* Physical screen. */
/*
* Initialize the data structures used
* by the display code. The edge vectors used
* to access the screens are set up. The operating
* system's terminal I/O channel is set up. All the
* other things get initialized at compile time.
* The original window has "WFCHG" set, so that it
* will get completely redrawn on the first
* call to "update".
*/
vtinit()
{
register int i;
register VIDEO *vp;
scr_setup();
vscreen = (VIDEO **) malloc(NROW*sizeof(VIDEO *));
if (vscreen == NULL)
exit(1);
pscreen = (VIDEO **) malloc(NROW*sizeof(VIDEO *));
if (pscreen == NULL)
exit(1);
for (i=0; i<NROW; ++i) {
vp = (VIDEO *) malloc(sizeof(VIDEO)+NCOL);
if (vp == NULL)
exit(1);
vscreen[i] = vp;
vp = (VIDEO *) malloc(sizeof(VIDEO)+NCOL);
if (vp == NULL)
exit(1);
pscreen[i] = vp;
}
}
/*
* Clean up the virtual terminal
* system, in anticipation for a return to the
* operating system. Move down to the last line and
* clear it out (the next system prompt will be
* written in the line). Shut down the channel
* to the terminal.
*/
vttidy()
{
movecursor(NROW, 0);
scr_clrl();
}
/*
* Set the virtual cursor to
* the specified row and column on the
* virtual screen. There is no checking for
* nonsense values; this might be a good
* idea during the early stages.
*/
vtmove(row, col)
{
vtrow = row;
vtcol = col;
}
/*
* Write a character to the
* virtual screen. The virtual row and
* column are updated. If the line is too
* long put a "$" in the last column.
* This routine only puts printing characters
* into the virtual terminal buffers.
* Only column overflow is checked.
*/
vtputc(c)
register int c;
{
register VIDEO *vp;
vp = vscreen[vtrow];
if (vtcol >= NCOL)
vp->v_text[NCOL-1] = '$';
else if (c == '\t') {
do {
vtputc(' ');
} while (vtcol&0x07);
} else if (c<0x20 || c==0x7F) {
vtputc('^');
vtputc(c ^ 0x40);
} else
vp->v_text[vtcol++] = c;
}
/*
* Erase from the end of the
* software cursor to the end of the
* line on which the software cursor is
* located.
*/
vteeol()
{
register VIDEO *vp;
vp = vscreen[vtrow];
while (vtcol < NCOL) vp->v_text[vtcol++] = ' ';
}
/*
* Make sure that the display is
* right. This is a three part process. First,
* scan through all of the windows looking for dirty
* ones. Check the framing, and refresh the screen.
* Second, make sure that "currow" and "curcol" are
* correct for the current window. Third, make the
* virtual and physical screens the same.
*/
update()
{
register LINE *lp;
register WINDOW *wp;
register VIDEO *vp1;
register VIDEO *vp2;
register int i;
register int j;
register int c;
for (wp = wheadp; wp; wp = wp->w_wndp) {
/* Look at any window with update flags set on. */
if (wp->w_flag) {
/* If not force reframe, check the framing. */
if (!(wp->w_flag&WFFORCE)) {
lp = wp->w_linep;
for (i=0; i<wp->w_ntrows; ++i) {
if (lp == wp->w_dotp) goto out;
if (lp == wp->w_bufp->b_linep) break;
lp = lforw(lp);
}
}
/* Not acceptable, better compute a new value */
/* for the line at the top of the window. Then */
/* set the "WFHARD" flag to force full redraw. */
i = wp->w_force;
if (i > 0) {
--i;
if (i >= wp->w_ntrows) i = wp->w_ntrows-1;
} else if (i < 0) {
i += wp->w_ntrows;
if (i < 0) i = 0;
} else i = wp->w_ntrows/2;
lp = wp->w_dotp;
while (i && lback(lp)!=wp->w_bufp->b_linep) {
--i;
lp = lback(lp);
}
wp->w_linep = lp;
wp->w_flag |= WFHARD; /* Force full. */
out:
/* Try to use reduced update. Mode line update */
/* has its own special flag. The fast update is */
/* used if the only thing to do is within the */
/* line editing. */
lp = wp->w_linep;
i = wp->w_toprow;
if ((wp->w_flag&~WFMODE) == WFEDIT) {
while (lp != wp->w_dotp) {
++i;
lp = lforw(lp);
}
vscreen[i]->v_flag |= VFCHG;
vtmove(i, 0);
for (j=0; j<llength(lp); ++j) vtputc(lgetc(lp, j));
vteeol();
} else if (wp->w_flag&(WFEDIT|WFHARD)) {
while (i < wp->w_toprow+wp->w_ntrows) {
vscreen[i]->v_flag |= VFCHG;
vtmove(i, 0);
if (lp != wp->w_bufp->b_linep) {
for (j=0; j<llength(lp); ++j)
vtputc(lgetc(lp, j));
lp = lforw(lp);
}
vteeol();
++i;
}
}
if (wp->w_flag&(WFFORCE|WFHARD|WFMODE)) modeline(wp);
wp->w_flag = wp->w_force = 0;
}
}
/* Always recompute the row and column number of the hardware */
/* cursor. This is the only update for simple moves. */
lp = curwp->w_linep;
currow = curwp->w_toprow;
while (lp != curwp->w_dotp) {
++currow;
lp = lforw(lp);
}
curcol = i = 0;
while (i < curwp->w_doto) {
c = lgetc(lp, i++);
if (c == '\t') curcol |= 0x07;
else if (c<0x20 || c==0x7F) ++curcol;
++curcol;
}
if (curcol >= NCOL) /* Long line. */
curcol = NCOL-1;
/* Special hacking if the screen is garbage. Clear the hardware */
/* screen, and update your copy to agree with it. Set all the */
/* virtual screen change bits, to force a full update. */
if (sgarbf) {
for (i=0; i<NROW; ++i) {
vscreen[i]->v_flag |= VFCHG;
vp1 = pscreen[i];
for (j=0; j<NCOL; ++j) vp1->v_text[j] = ' ';
}
movecursor(0, 0); /* Erase the screen. */
scr_cls();
mpresf = sgarbf = FALSE; /* Erase-page clears */
/* the message area. */
}
/* Make sure that the physical and virtual displays agree. */
/* Unlike before, the "updateline" code is only called with a */
/* line that has been updated for sure. */
for (i=0; i<NROW; ++i) {
vp1 = vscreen[i];
if (vp1->v_flag&VFCHG) {
vp1->v_flag &= ~VFCHG;
vp2 = pscreen[i];
updateline(i, vp1->v_text, vp2->v_text);
}
}
/* Finally, update the hardware cursor and flush out buffers. */
movecursor(currow, curcol);
}
/*
* Update a single line. This
* does not know how to use insert
* or delete character sequences; we are
* using VT52 functionality. Update the physical
* row and column variables. It does try an
* exploit erase to end of line.
*/
updateline(row, vline, pline)
char vline[];
char pline[];
{
register char *cp1;
register char *cp2;
register char *cp3;
register char *cp4;
register char *cp5;
register int nbflag;
cp1 = vline; /* Compute left match. */
cp2 = pline;
while (cp1!=vline+NCOL && *cp1==*cp2) {
++cp1;
++cp2;
}
/* This can still happen, even though we only call this routine */
/* on changed lines. A hard update is always done when a line */
/* splits, a massive change is done, or a buffer is displayed */
/* twice. This optimizes out most of the excess updating. A lot */
/* of computes are used, but these tend to be hard operations */
/* that do a lot of update, so I don't really care. */
if (cp1 == vline+NCOL) /* All equal. */
return;
nbflag = FALSE;
cp3 = vline+NCOL; /* Compute right match. */
cp4 = pline+NCOL;
while (cp3[-1] == cp4[-1]) {
--cp3;
--cp4;
if (*cp3 != ' ') /* Note if any nonblank */
nbflag = TRUE; /* in right match. */
}
cp5 = cp3;
if (nbflag == FALSE) { /* Erase to EOL ? */
while (cp5!=cp1 && cp5[-1]==' ') --cp5;
if (cp3-cp5 <= 3) /* Use only if erase is */
cp5 = cp3; /* fewer characters. */
}
movecursor(row, cp1-vline); /* Go to start of line. */
while (cp1 != cp5) { /* Ordinary. */
scr_co(*cp1);
++ttcol;
*cp2++ = *cp1++;
}
if (cp5 != cp3) { /* Erase. */
scr_clrl();
while (cp1 != cp3) *cp2++ = *cp1++;
}
}
/*
* Redisplay the mode line for
* the window pointed to by the "wp".
* This is the only routine that has any idea
* of how the modeline is formatted. You can
* change the modeline format by hacking at
* this routine. Called by "update" any time
* there is a dirty window.
*/
modeline(wp)
register WINDOW *wp;
{
register char *cp;
register int c;
register int n;
register BUFFER *bp;
register int ratio;
static int old_ratio = -1;
ratio = percent();
if (wp->w_flag&WFMODE==0 && ratio==old_ratio) return;
old_ratio = ratio;
n = wp->w_toprow+wp->w_ntrows; /* Location. */
vscreen[n]->v_flag |= VFCHG; /* Redraw next time. */
vtmove(n, 0); /* Seek to right line. */
vtputc('-');
bp = wp->w_bufp;
if (bp->b_flag&BFCHG) /* "*" if changed. */
vtputc('*');
else
vtputc('-');
n = 2;
cp = " MicroEMACS -- "; /* Buffer name. */
while (c = *cp++) {
vtputc(c);
++n;
}
cp = bp->b_bname;
while (c = *cp++) {
vtputc(c);
++n;
}
vtputc(' ');
++n;
if (*bp->b_fname) { /* File name. */
cp = "-- File: ";
while (c = *cp++) {
vtputc(c);
++n;
}
cp = bp->b_fname;
while (c = *cp++) {
vtputc(c);
++n;
}
vtputc(' ');
++n;
}
/* Display the percentage position within file. */
vtputc('('); n++;
if (ratio >= 100) {
vtputc('1');
vtputc('0');
vtputc('0');
n += 3;
}
else {
vtputc((ratio > 9) ? '0'+ratio/10 : ' ');
vtputc('0'+ratio%10);
n += 2;
}
vtputc('%');
vtputc(')');
vtputc(' ');
n += 3;
vtputc('-');
vtputc('-');
n += 2;
/* tell the user if he is in INSert or OVRwrite mode for the
current buffer */
cp ="INS";
if (curbp->b_flag & BFOVRWRITE)
cp = "OVR";
while( c=*cp++)
{
vtputc(c);
n++;
}
while (n < NCOL) { /* Pad to full width. */
vtputc('-');
++n;
}
}
/*
* Compute percent of file we are at
*/
percent()
{
register LINE *clp;
register long nch;
register int cbo;
register long nbc;
register int ratio;
register int cac;
clp = lforw(curbp->b_linep); /* Grovel the data. */
cbo = 0;
nch = 0;
for (;;) {
if (clp==curwp->w_dotp && cbo==curwp->w_doto) {
nbc = nch;
if (cbo == llength(clp))
cac = '\n';
else
cac = lgetc(clp, cbo);
}
if (cbo == llength(clp)) {
if (clp == curbp->b_linep)
break;
clp = lforw(clp);
cbo = 0;
} else
++cbo;
++nch;
}
ratio = 0; /* Ratio before dot. */
if (nch)
ratio = (100L*nbc) / nch;
return ratio;
}
/*
* Send a command to the terminal
* to move the hardware cursor to row "row"
* and column "col". The row and column arguments
* are origin 0. Optimize out random calls.
* Update "ttrow" and "ttcol".
*/
movecursor(row, col)
{
if (row!=ttrow || col!=ttcol) {
ttrow = row;
ttcol = col;
scr_rowcol(row, col);
}
}
/*
* Erase the message line.
* This is a special routine because
* the message line is not considered to be
* part of the virtual screen. It always works
* immediately; the terminal buffer is flushed
* via a call to the flusher.
*/
mlerase()
{
movecursor(NROW, 0);
scr_clrl();
mpresf = FALSE;
}
/*
* Ask a yes or no question in
* the message line. Return either TRUE,
* FALSE, or ABORT. The ABORT status is returned
* if the user bumps out of the question with
* a ^G. Used any time a confirmation is
* required.
*/
mlyesno(prompt)
char *prompt;
{
register int s;
char buf[64];
for (;;) {
strcpy(buf, prompt);
strcat(buf, " [y/n]? ");
s = mlreply(buf, buf, sizeof(buf));
if (s == ABORT)
return (ABORT);
if (s) {
if (*buf=='y' || *buf=='Y')
return (TRUE);
if (*buf=='n' || *buf=='N')
return (FALSE);
}
}
}
/*
* Write a prompt into the message
* line, then read back a response. Keep
* track of the physical position of the cursor.
* If we are in a keyboard macro throw the prompt
* away, and return the remembered response. This
* lets macros run at full speed. The reply is
* always terminated by a carriage return. Handle
* erase, kill, and abort keys.
*/
mlreply(prompt, buf, nbuf)
char *prompt;
char *buf;
{
register int cpos;
register int i;
register int c;
cpos = 0;
if (kbdmop != NULL) {
while ((c = *kbdmop++) != '\0')
buf[cpos++] = c;
buf[cpos] = 0;
return (!!*buf);
}
mlwrite(prompt);
for (;;) {
c = scr_ci();
switch (c) {
case 0x0D: /* Return, end of line */
buf[cpos++] = 0;
if (kbdmip != NULL) {
if (kbdmip+cpos > kbdm+NKBDM-3) {
ctrlg(FALSE, 0);
return (ABORT);
}
for (i=0; i<cpos; ++i)
*kbdmip++ = buf[i];
}
scr_co('\r');
ttcol = 0;
return !!*buf;
case 0x07: /* Bell, abort */
scr_co('^');
scr_co('G');
ttcol += 2;
ctrlg(FALSE, 0);
return (ABORT);
case 0x7F: /* Rubout, erase */
case 0x08: /* Backspace, erase */
if (cpos) {
scr_co('\b');
scr_co(' ');
scr_co('\b');
--ttcol;
if (buf[--cpos] < 0x20) {
scr_co('\b');
scr_co(' ');
scr_co('\b');
--ttcol;
}
}
break;
case 0x15: /* C-U, kill */
while (cpos) {
scr_co('\b');
scr_co(' ');
scr_co('\b');
--ttcol;
if (buf[--cpos] < 0x20) {
scr_co('\b');
scr_co(' ');
scr_co('\b');
--ttcol;
}
}
break;
default:
if (cpos < nbuf-1) {
buf[cpos++] = c;
if (c < ' ') {
scr_co('^');
++ttcol;
c ^= 0x40;
}
scr_co(c);
++ttcol;
}
}
}
}
/*
* Write a message into the message
* line. Keep track of the physical cursor
* position. A small class of printf like format
* items is handled. Assumes the stack grows
* down; this assumption is made by the "++"
* in the argument scan loop. Set the "message
* line" flag TRUE.
*/
mlwrite(fmt, arg)
char *fmt;
{
register int c;
register char *ap;
movecursor(NROW, 0);
ap = (char *) &arg;
while (c = *fmt++) {
if (c != '%') {
scr_co(c);
++ttcol;
} else {
c = *fmt++;
switch (c) {
case 'd':
mlputi(*(int *)ap, 10);
ap += sizeof(int);
break;
case 'o':
mlputi(*(int *)ap, 8);
ap += sizeof(int);
break;
case 'x':
mlputi(*(int *)ap, 16);
ap += sizeof(int);
break;
case 'D':
mlputli(*(long *)ap, 10);
ap += sizeof(long);
break;
case 's':
mlputs(*(char **)ap);
ap += sizeof(char *);
break;
default:
scr_co(c);
++ttcol;
}
}
}
scr_clrl();
mpresf = TRUE;
}
/*
* Write out a string.
* Update the physical cursor position.
* This assumes that the characters in the
* string all have width "1"; if this is
* not the case things will get screwed up
* a little.
*/
mlputs(s)
register char *s;
{
register int c;
while (c = *s++) {
scr_co(c);
++ttcol;
}
}
/*
* Write out an integer, in
* the specified radix. Update the physical
* cursor position. This will not handle any
* negative numbers; maybe it should.
*/
mlputi(i, r)
{
register int q;
static char hexdigits[] = "0123456789ABCDEF";
if (i < 0) {
i = -i;
scr_co('-');
}
q = i/r;
if (q)
mlputi(q, r);
scr_co(hexdigits[i%r]);
++ttcol;
}
/*
* do the same except as a long integer.
*/
mlputli(l, r)
long l;
{
register long q;
if (l < 0) {
l = -l;
scr_co('-');
}
q = l/r;
if (q)
mlputli(q, r);
scr_co((int)(l%r)+'0');
++ttcol;
}