MicroEmacs (3 of 7)
Curt Jutzi
jutz at pogo.UUCP
Fri Mar 21 03:13:59 AEST 1986
*** REPLACE THIS LINE WITH YOUR MESSAGE ***
{
buf[width] = 0; /* End of string. */
while (num >= 10) { /* Conditional digits. */
buf[--width] = (num%10) + '0';
num /= 10;
}
buf[--width] = num + '0'; /* Always 1 digit. */
while (width != 0) /* Pad with blanks. */
buf[--width] = ' ';
}
/*
* The argument "text" points to
* a string. Append this line to the
* buffer list buffer. Handcraft the EOL
* on the end. Return TRUE if it worked and
* FALSE if you ran out of room.
*/
addline(text)
char *text;
{
register LINE *lp;
register int i;
register int ntext;
ntext = strlen(text);
if ((lp=lalloc(ntext)) == NULL)
return (FALSE);
for (i=0; i<ntext; ++i)
lputc(lp, i, text[i]);
blistp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
lp->l_bp = blistp->b_linep->l_bp;
blistp->b_linep->l_bp = lp;
lp->l_fp = blistp->b_linep;
if (blistp->b_dotp == blistp->b_linep) /* If "." is at the end */
blistp->b_dotp = lp; /* move it to new line */
return (TRUE);
}
/*
* Look through the list of
* buffers. Return TRUE if there
* are any changed buffers. Buffers
* that hold magic internal stuff are
* not considered; who cares if the
* list of buffer names is hacked.
* Return FALSE if no buffers
* have been changed.
*/
anycb()
{
register BUFFER *bp;
bp = bheadp;
while (bp != NULL) {
if ((bp->b_flag&BFTEMP)==0 && (bp->b_flag&BFCHG)!=0)
return (TRUE);
bp = bp->b_bufp;
}
return (FALSE);
}
/*
* Find a buffer, by name. Return a pointer
* to the BUFFER structure associated with it. If
* the named buffer is found, but is a TEMP buffer (like
* the buffer list) conplain. If the buffer is not found
* and the "cflag" is TRUE, create it. The "bflag" is
* the settings for the flags in in buffer.
*/
BUFFER *
bfind(bname, cflag, bflag)
register char *bname;
{
register BUFFER *bp;
register LINE *lp;
bp = bheadp;
while (bp != NULL) {
if (strcmp(bname, bp->b_bname) == 0) {
if ((bp->b_flag&BFTEMP) != 0) {
mlwrite("Cannot select builtin buffer");
return (NULL);
}
return (bp);
}
bp = bp->b_bufp;
}
if (cflag != FALSE) {
if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
return (NULL);
if ((lp=lalloc(0)) == NULL) {
free((char *) bp);
return (NULL);
}
bp->b_bufp = bheadp;
bheadp = bp;
bp->b_dotp = lp;
bp->b_doto = 0;
bp->b_markp = NULL;
bp->b_marko = 0;
bp->b_flag = bflag;
bp->b_nwnd = 0;
bp->b_linep = lp;
strcpy(bp->b_fname, "");
strcpy(bp->b_bname, bname);
lp->l_fp = lp;
lp->l_bp = lp;
}
return (bp);
}
/*
* This routine blows away all of the text
* in a buffer. If the buffer is marked as changed
* then we ask if it is ok to blow it away; this is
* to save the user the grief of losing text. The
* window chain is nearly always wrong if this gets
* called; the caller must arrange for the updates
* that are required. Return TRUE if everything
* looks good.
*/
bclear(bp)
register BUFFER *bp;
{
register LINE *lp;
register int s;
if ((bp->b_flag&BFTEMP) == 0 /* Not scratch buffer. */
&& (bp->b_flag&BFCHG) != 0 /* Something changed */
&& (s=mlyesno("Discard changes")) != TRUE)
return (s);
bp->b_flag &= ~BFCHG; /* Not changed */
while ((lp=lforw(bp->b_linep)) != bp->b_linep)
lfree(lp);
bp->b_dotp = bp->b_linep; /* Fix "." */
bp->b_doto = 0;
bp->b_markp = NULL; /* Invalidate "mark" */
bp->b_marko = 0;
return (TRUE);
}
/* This routine takes a line of text and a buffer pointer
* and places the line of text into the buffer and appends
* a CR-LF to the end of the text string
*
*/
addbufftext(text,bp)
char *text;
BUFFER *bp;
{
register int ntext;
register LINE *lp;
register int i;
ntext = strlen(text);
if ((lp=lalloc(ntext)) == NULL)
return (FALSE);
for (i=0; i<ntext; ++i)
if (text[i] == '\n')
newline();
else
lputc(lp, i, text[i]);
bp->b_linep->l_bp->l_fp = lp; /* Hook onto the end */
lp->l_bp = bp->b_linep->l_bp;
bp->b_linep->l_bp = lp;
lp->l_fp = bp->b_linep;
if (bp->b_dotp == bp->b_linep) /* If "." is at the end */
bp->b_dotp = lp; /* move it to new line */
return (TRUE);
}
/*
*
* VT52 MODULE
*
*/
/*
* The routines in this file
* provide support for VT52 style terminals
* over a serial line. The serial I/O services are
* provided by routines in "termio.c". It compiles
* into nothing if not a VT52 style device. The
* bell on the VT52 is terrible, so the "beep"
* routine is conditionalized on defining BEL.
*/
#include <stdio.h>
#include "ed.h"
#if VT52
#define NROW 24 /* Screen size. */
#define NCOL 80 /* Edit if you want to. */
#define BIAS 0x20 /* Origin 0 coordinate bias. */
#define ESC 0x1B /* ESC character. */
#define BEL 0x07 /* ascii bell character */
extern int ttopen(); /* Forward references. */
extern int ttgetc();
extern int ttputc();
extern int ttflush();
extern int ttclose();
extern int vt52move();
extern int vt52eeol();
extern int vt52eeop();
extern int vt52beep();
extern int vt52open();
/*
* Dispatch table. All the
* hard fields just point into the
* terminal I/O code.
*/
TERM term = {
NROW-1,
NCOL,
vt52open,
ttclose,
ttgetc,
ttputc,
ttflush,
vt52move,
vt52eeol,
vt52eeop,
vt52beep
};
vt52move(row, col)
{
ttputc(ESC);
ttputc('Y');
ttputc(row+BIAS);
ttputc(col+BIAS);
}
vt52eeol()
{
ttputc(ESC);
ttputc('K');
}
vt52eeop()
{
ttputc(ESC);
ttputc('J');
}
vt52beep()
{
#ifdef BEL
ttputc(BEL);
ttflush();
#endif
}
#endif
vt52open()
{
#if V7
register char *cp;
char *getenv();
if ((cp = getenv("TERM")) == NULL) {
puts("Shell variable TERM not defined!");
exit(1);
}
if (strcmp(cp, "vt52") != 0 && strcmp(cp, "z19") != 0) {
puts("Terminal type not 'vt52'or 'z19' !");
exit(1);
}
#endif
ttopen();
}
/*
*
* WORD.C MODULE
*
*/
/*
* The routines in this file implement commands that work word at a time.
* There are all sorts of word mode commands. If I do any sentence and/or
* paragraph mode commands, they are likely to be put in this file.
*/
#include <stdio.h>
#include "ed.h"
/* Word wrap on n-spaces. Back-over whatever precedes the point on the current
* line and stop on the first word-break or the beginning of the line. If we
* reach the beginning of the line, jump back to the end of the word and start
* a new line. Otherwise, break the line at the word-break, eat it, and jump
* back to the end of the word.
* NOTE: This function may leaving trailing blanks.
* Returns TRUE on success, FALSE on errors.
*/
wrapword(n)
int n;
{
register int cnt, oldp;
oldp = curwp->w_dotp;
cnt = -1;
do {
cnt++;
if (! backchar(NULL, 1))
return(FALSE);
}
while (! inword());
if (! backword(NULL, 1))
return(FALSE);
if (oldp == (int) (curwp->w_dotp && curwp->w_doto)) {
if (! backdel(NULL, 1))
return(FALSE);
if (! newline(NULL, 1))
return(FALSE);
}
return(forwword(NULL, 1) && forwchar(NULL, cnt));
}
/*
* Move the cursor backward by "n" words. All of the details of motion are
* performed by the "backchar" and "forwchar" routines. Error if you try to
* move beyond the buffers.
*/
backword(f, n)
{
if (n < 0)
return (forwword(f, -n));
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (forwchar(FALSE, 1));
}
/*
* Move the cursor forward by the specified number of words. All of the motion
* is done by "forwchar". Error if you try and move beyond the buffer's end.
*/
forwword(f, n)
{
if (n < 0)
return (backword(f, -n));
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move,
* convert any characters to upper case. Error if you try and move beyond the
* end of the buffer. Bound to "M-U".
*/
upperword(f, n)
{
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='a' && c<='z') {
c -= 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move
* convert characters to lower case. Error if you try and move over the end of
* the buffer. Bound to "M-L".
*/
lowerword(f, n)
{
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='A' && c<='Z') {
c += 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
return (TRUE);
}
/*
* Move the cursor forward by the specified number of words. As you move
* convert the first character of the word to upper case, and subsequent
* characters to lower case. Error if you try and move past the end of the
* buffer. Bound to "M-C".
*/
capword(f, n)
{
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
if (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='a' && c<='z') {
c -= 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='A' && c<='Z') {
c += 'a'-'A';
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
}
}
}
return (TRUE);
}
/*
* Kill forward by "n" words. Remember the location of dot. Move forward by
* the right number of words. Put dot back where it was and issue the kill
* command for the right number of characters. Bound to "M-D".
*/
delfword(f, n)
{
register int size;
register LINE *dotp;
register int doto;
if (n < 0)
return (FALSE);
dotp = curwp->w_dotp;
doto = curwp->w_doto;
size = 0;
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
while (inword() != FALSE) {
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
}
curwp->w_dotp = dotp;
curwp->w_doto = doto;
return (ldelete(size, TRUE));
}
/*
* Kill backwards by "n" words. Move backwards by the desired number of words,
* counting the characters. When dot is finally moved to its resting place,
* fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
*/
delbword(f, n)
{
register int size;
if (n < 0)
return (FALSE);
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
size = 0;
while (n--) {
while (inword() == FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
while (inword() != FALSE) {
if (backchar(FALSE, 1) == FALSE)
return (FALSE);
++size;
}
}
if (forwchar(FALSE, 1) == FALSE)
return (FALSE);
return (ldelete(size, TRUE));
}
/*
* Return TRUE if the character at dot is a character that is considered to be
* part of a word. The word character list is hard coded. Should be setable.
*/
inword()
{
register int c;
if (curwp->w_doto == llength(curwp->w_dotp))
return (FALSE);
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (c>='a' && c<='z')
return (TRUE);
if (c>='A' && c<='Z')
return (TRUE);
if (c>='0' && c<='9')
return (TRUE);
if (c=='$' || c=='_') /* For identifiers */
return (TRUE);
return (FALSE);
}
/*
*
* DISPLAY.C MODULE
*
*
*/
/*
* 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.
*
* REVISION HISTORY:
*
* ? Steve Wilhite, 1-Dec-85
* - massive cleanup on code.
*/
#include <stdio.h>
#include "ed.h"
#define WFDEBUG 0 /* Window flag debug. */
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;
(*term.t_open)();
vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
if (vscreen == NULL)
exit(1);
pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
if (pscreen == NULL)
exit(1);
for (i = 0; i < term.t_nrow; ++i)
{
vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
if (vp == NULL)
exit(1);
vscreen[i] = vp;
vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_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(term.t_nrow, 0);
(*term.t_eeol)();
(*term.t_close)();
}
/*
* 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)
int c;
{
register VIDEO *vp;
vp = vscreen[vtrow];
if (vtcol >= term.t_ncol)
vp->v_text[term.t_ncol - 1] = '$';
else if (c == '\t')
{
do
{
vtputc(' ');
}
while ((vtcol&0x07) != 0);
}
else if (c < 0x20 || c == 0x7F)
{
vtputc('^');
vtputc(c ^ 0x40);
}
else
vp->v_text[vtcol++] = c;
}
/*
* 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. If 'c' is a ctl char it is put directly into
* the buffer as is. Tabs are sent as tabs also.
*/
vtputcl(c)
int c;
{
register VIDEO *vp;
vp = vscreen[vtrow];
if (vtcol >= term.t_ncol)
vp->v_text[term.t_ncol - 1] = '$';
else if (c == '\t')
{
do
{
vtputc(' ');
}
while ((vtcol&0x07) != 0);
}
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 < term.t_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;
wp = wheadp;
while (wp != NULL)
{
/* Look at any window with update flags set on. */
if (wp->w_flag != 0)
{
/* If not force reframe, check the framing. */
if ((wp->w_flag & WFFORCE) == 0)
{
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 != 0 && 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)) != 0)
{
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 ~WFDEBUG
if ((wp->w_flag&WFMODE) != 0)
modeline(wp);
wp->w_flag = 0;
wp->w_force = 0;
#endif
}
#if WFDEBUG
modeline(wp);
wp->w_flag = 0;
wp->w_force = 0;
#endif
wp = wp->w_wndp;
}
/* 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 = 0;
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 >= term.t_ncol) /* Long line. */
curcol = term.t_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 != FALSE)
{
for (i = 0; i < term.t_nrow; ++i)
{
vscreen[i]->v_flag |= VFCHG;
vp1 = pscreen[i];
for (j = 0; j < term.t_ncol; ++j)
vp1->v_text[j] = ' ';
}
movecursor(0, 0); /* Erase the screen. */
(*term.t_eeop)();
sgarbf = FALSE; /* Erase-page clears */
mpresf = FALSE; /* 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 < term.t_nrow; ++i)
{
vp1 = vscreen[i];
if ((vp1->v_flag&VFCHG) != 0)
{
vp1->v_flag &= ~VFCHG;
vp2 = pscreen[i];
updateline(i, &vp1->v_text[0], &vp2->v_text[0]);
}
}
/* Finally, update the hardware cursor and flush out buffers. */
movecursor(currow, curcol);
(*term.t_flush)();
}
/*
* 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. The
* RAINBOW version of this routine uses fast video.
*/
updateline(row, vline, pline)
char vline[];
char pline[];
{
#if RAINBOW
register char *cp1;
register char *cp2;
register int nch;
cp1 = &vline[0]; /* Use fast video. */
cp2 = &pline[0];
putline(row+1, 1, cp1);
nch = term.t_ncol;
do
{
*cp2 = *cp1;
++cp2;
++cp1;
}
while (--nch);
#else
register char *cp1;
register char *cp2;
register char *cp3;
register char *cp4;
register char *cp5;
register int nbflag;
cp1 = &vline[0]; /* Compute left match. */
cp2 = &pline[0];
while (cp1!=&vline[term.t_ncol] && cp1[0]==cp2[0])
{
++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[term.t_ncol]) /* All equal. */
return;
nbflag = FALSE;
cp3 = &vline[term.t_ncol]; /* Compute right match. */
cp4 = &pline[term.t_ncol];
More information about the Comp.sources.unix
mailing list