v08i009: A Micro-Emacs variant that resembles GNU Emacs
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Wed Jan 28 04:14:51 AEST 1987
Submitted by: Bob Larson <seismo!usc-oberon!blarson>
Mod.sources: Volume 8, Issue 9
Archive-name: micrognu/Part02
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# basic.c
# buffer.c
# cinfo.c
# echo.c
# extend.c
# file.c
# match.c
# This archive created: Sat Nov 15 14:59:46 1986
export PATH; PATH=/bin:$PATH
if test -f 'basic.c'
then
echo shar: will not over-write existing file "'basic.c'"
else
cat << \SHAR_EOF > 'basic.c'
/*
* Basic cursor motion commands.
*
* The routines in this file are the basic
* command functions for moving the cursor around on
* the screen, setting mark, and swapping dot with
* mark. Only moves between lines, which might make the
* current buffer framing bad, are hard.
*/
#include "def.h"
/*
* Go to beginning of line.
*/
/*ARGSUSED*/
gotobol(f, n, k) {
curwp->w_doto = 0;
return (TRUE);
}
/*
* Move cursor backwards. Do the
* right thing if the count is less than
* 0. Error if you try to move back from
* the beginning of the buffer.
*/
/*ARGSUSED*/
backchar(f, n, k) register int n; {
register LINE *lp;
if (n < 0)
return (forwchar(f, -n, k));
while (n--) {
if (curwp->w_doto == 0) {
if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) {
if (k != KRANDOM)
ewprintf("Beginning of buffer");
return (FALSE);
}
curwp->w_dotp = lp;
curwp->w_doto = llength(lp);
curwp->w_flag |= WFMOVE;
} else
curwp->w_doto--;
}
return (TRUE);
}
/*
* Go to end of line.
*/
/*ARGSUSED*/
gotoeol(f, n, k) {
curwp->w_doto = llength(curwp->w_dotp);
return (TRUE);
}
/*
* Move cursor forwards. Do the
* right thing if the count is less than
* 0. Error if you try to move forward
* from the end of the buffer.
*/
/*ARGSUSED*/
forwchar(f, n, k) register int n; {
if (n < 0)
return (backchar(f, -n, k));
while (n--) {
if (curwp->w_doto == llength(curwp->w_dotp)) {
if (curwp->w_dotp == curbp->b_linep) {
if (k != KRANDOM)
ewprintf("End of buffer");
return (FALSE);
}
curwp->w_dotp = lforw(curwp->w_dotp);
curwp->w_doto = 0;
curwp->w_flag |= WFMOVE;
} else
curwp->w_doto++;
}
return (TRUE);
}
/*
* Go to the beginning of the
* buffer. Setting WFHARD is conservative,
* but almost always the case.
*/
gotobob(f, n, k) {
(VOID) setmark(f, n, k) ;
curwp->w_dotp = lforw(curbp->b_linep);
curwp->w_doto = 0;
curwp->w_flag |= WFHARD;
return (TRUE);
}
/*
* Go to the end of the buffer.
* Setting WFHARD is conservative, but
* almost always the case.
*/
gotoeob(f, n, k) {
(VOID) setmark(f, n, k) ;
curwp->w_dotp = curbp->b_linep;
curwp->w_doto = 0;
curwp->w_flag |= WFHARD;
return (TRUE);
}
/*
* Move forward by full lines.
* If the number of lines to move is less
* than zero, call the backward line function to
* actually do it. The last command controls how
* the goal column is set.
*/
/*ARGSUSED*/
forwline(f, n, k) {
register LINE *dlp;
if (n < 0)
return (backline(f, -n, KRANDOM));
if ((lastflag&CFCPCN) == 0) /* Fix goal. */
setgoal();
thisflag |= CFCPCN;
dlp = curwp->w_dotp;
while (n-- && dlp!=curbp->b_linep)
dlp = lforw(dlp);
curwp->w_dotp = dlp;
curwp->w_doto = getgoal(dlp);
curwp->w_flag |= WFMOVE;
return (TRUE);
}
/*
* This function is like "forwline", but
* goes backwards. The scheme is exactly the same.
* Check for arguments that are less than zero and
* call your alternate. Figure out the new line and
* call "movedot" to perform the motion.
*/
/*ARGSUSED*/
backline(f, n, k) {
register LINE *dlp;
if (n < 0)
return (forwline(f, -n, KRANDOM));
if ((lastflag&CFCPCN) == 0) /* Fix goal. */
setgoal();
thisflag |= CFCPCN;
dlp = curwp->w_dotp;
while (n-- && lback(dlp)!=curbp->b_linep)
dlp = lback(dlp);
curwp->w_dotp = dlp;
curwp->w_doto = getgoal(dlp);
curwp->w_flag |= WFMOVE;
return (TRUE);
}
/*
* Set the current goal column,
* which is saved in the external variable "curgoal",
* to the current cursor column. The column is never off
* the edge of the screen; it's more like display then
* show position.
*/
setgoal() {
curgoal = getcolpos() - 1; /* Get the position. */
if (curgoal >= ncol) /* Chop to tty width. */
curgoal = ncol-1;
}
/*
* This routine looks at a line (pointed
* to by the LINE pointer "dlp") and the current
* vertical motion goal column (set by the "setgoal"
* routine above) and returns the best offset to use
* when a vertical motion is made into the line.
*/
getgoal(dlp) register LINE *dlp; {
register int c;
register int col;
register int newcol;
register int dbo;
col = 0;
dbo = 0;
while (dbo != llength(dlp)) {
c = lgetc(dlp, dbo);
newcol = col;
if (c == '\t')
newcol |= 0x07;
else if (ISCTRL(c) != FALSE)
++newcol;
++newcol;
if (newcol > curgoal)
break;
col = newcol;
++dbo;
}
return (dbo);
}
/*
* Scroll forward by a specified number
* of lines, or by a full page if no argument.
* The "2" is the window overlap (this is the default
* value from ITS EMACS). Because the top line in
* the window is zapped, we have to do a hard
* update and get it back.
*/
/*ARGSUSED*/
forwpage(f, n, k) register int n; {
register LINE *lp;
if (f == FALSE) {
n = curwp->w_ntrows - 2; /* Default scroll. */
if (n <= 0) /* Forget the overlap */
n = 1; /* if tiny window. */
} else if (n < 0)
return (backpage(f, -n, KRANDOM));
#ifdef CVMVAS
else /* Convert from pages */
n *= curwp->w_ntrows; /* to lines. */
#endif
lp = curwp->w_linep;
while (n-- && lp!=curbp->b_linep)
lp = lforw(lp);
curwp->w_linep = lp;
curwp->w_dotp = lp;
curwp->w_doto = 0;
curwp->w_flag |= WFHARD;
return (TRUE);
}
/*
* This command is like "forwpage",
* but it goes backwards. The "2", like above,
* is the overlap between the two windows. The
* value is from the ITS EMACS manual. The
* hard update is done because the top line in
* the window is zapped.
*/
/*ARGSUSED*/
backpage(f, n, k) register int n; {
register LINE *lp;
if (f == FALSE) {
n = curwp->w_ntrows - 2; /* Default scroll. */
if (n <= 0) /* Don't blow up if the */
n = 1; /* window is tiny. */
} else if (n < 0)
return (forwpage(f, -n, KRANDOM));
#ifdef CVMVAS
else /* Convert from pages */
n *= curwp->w_ntrows; /* to lines. */
#endif
lp = curwp->w_linep;
while (n-- && lback(lp)!=curbp->b_linep)
lp = lback(lp);
curwp->w_linep = lp;
curwp->w_dotp = lp;
curwp->w_doto = 0;
curwp->w_flag |= WFHARD;
return (TRUE);
}
/*
* Page the other window. Check to make sure it exists, then
* nextwind, forwpage and prevwind.
*/
pagenext(f, n, k) {
if (wheadp->w_wndp == NULL) {
ewprintf("No other window");
return FALSE;
}
(VOID) nextwind(f, n, k);
(VOID) forwpage(f, n, k);
(VOID) prevwind(f, n, k);
return TRUE;
}
/*
* Set the mark in the current window
* to the value of dot. A message is written to
* the echo line unless we are running in a keyboard
* macro, when it would be silly.
*/
/*ARGSUSED*/
setmark(f, n, k) {
isetmark();
if (kbdmop == NULL)
ewprintf("Mark set");
return (TRUE);
}
/*
* Internal set mark routine, used by other functions (daveb).
*/
isetmark()
{
curwp->w_markp = curwp->w_dotp;
curwp->w_marko = curwp->w_doto;
}
/*
* Swap the values of "dot" and "mark" in
* the current window. This is pretty easy, because
* all of the hard work gets done by the standard routine
* that moves the mark about. The only possible
* error is "no mark".
*/
/*ARGSUSED*/
swapmark(f, n, k) {
register LINE *odotp;
register int odoto;
if (curwp->w_markp == NULL) {
ewprintf("No mark in this window");
return (FALSE);
}
odotp = curwp->w_dotp;
odoto = curwp->w_doto;
curwp->w_dotp = curwp->w_markp;
curwp->w_doto = curwp->w_marko;
curwp->w_markp = odotp;
curwp->w_marko = odoto;
curwp->w_flag |= WFMOVE;
return (TRUE);
}
/*
* Go to a specific line, mostly for
* looking up errors in C programs, which give the
* error a line number. If an argument is present, then
* it is the line number, else prompt for a line number
* to use.
*/
/*ARGSUSED*/
gotoline(f, n, k) register int n; {
register LINE *clp;
register int s;
char buf[32];
if (f == FALSE) {
if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
return (s);
n = atoi(buf);
}
clp = lforw(curbp->b_linep); /* "clp" is first line */
while (n > 1) {
if (lforw(clp) == curbp->b_linep) break;
clp = lforw(clp);
--n;
}
curwp->w_dotp = clp;
curwp->w_doto = 0;
curwp->w_flag |= WFMOVE;
return (TRUE);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'buffer.c'
then
echo shar: will not over-write existing file "'buffer.c'"
else
cat << \SHAR_EOF > 'buffer.c'
/*
* Buffer handling.
*/
#include "def.h"
/*
* Attach a buffer to a window. The
* values of dot and mark come from the buffer
* if the use count is 0. Otherwise, they come
* from some other window.
*/
/*ARGSUSED*/
usebuffer(f, n, k) {
register BUFFER *bp;
register int s;
char bufn[NBUFN];
/* Get buffer to use from user */
if (curbp->b_altb != NULL)
s=eread("Switch to buffer: (default %s) ", bufn, NBUFN,
EFNEW|EFBUF,
#ifdef VARARGS
curbp->b_altb->b_bname
#else
&(curbp->b_altb->b_bname), (char *) NULL
#endif
) ;
else
s=eread("Switch to buffer: ", bufn, NBUFN, EFNEW|EFBUF
#ifndef VARARGS
,(char *) NULL
#endif
);
if (s == ABORT) return (s);
if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb ;
else if ((bp=bfind(bufn, TRUE)) == NULL) return (FALSE);
/* and put it in current window */
curbp = bp;
return showbuffer(bp, curwp, WFFORCE|WFHARD);
}
/*
* pop to buffer asked for by the user.
*/
/*ARGSUSED*/
poptobuffer(f, n, k) {
register BUFFER *bp;
register WINDOW *wp;
register int s;
char bufn[NBUFN];
/* Get buffer to use from user */
if (curbp->b_altb != NULL)
s=eread("Switch to buffer in other window: (default %s) ",
bufn, NBUFN, EFNEW|EFBUF,
#ifdef VARARGS
curbp->b_altb->b_bname
#else
&(curbp->b_altb->b_bname) ,(char *) NULL
#endif
) ;
else
s=eread("Switch to buffer in other window: ", bufn, NBUFN,
EFNEW|EFBUF
#ifndef VARARGS
, (char *) NULL
#endif
) ;
if (s == ABORT) return (s);
if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb ;
else if ((bp=bfind(bufn, TRUE)) == NULL) return (FALSE);
/* and put it in a new window */
if ((wp = popbuf(bp)) == NULL) return FALSE;
curbp = bp;
curwp = wp;
return TRUE;
}
/*
* Dispose of a buffer, by name.
* Ask for the name. Look it up (don't get too
* upset if it isn't there at all!). Clear the buffer (ask
* if the buffer has been changed). Then free the header
* line and the buffer header. Bound to "C-X K".
*/
/*ARGSUSED*/
killbuffer(f, n, k) {
register BUFFER *bp;
register BUFFER *bp1;
register BUFFER *bp2;
register WINDOW *wp;
register int s;
char bufn[NBUFN];
if ((s=eread("Kill buffer: (default %s) ", bufn, NBUFN, EFNEW|EFBUF,
#ifdef VARARGS
curbp->b_bname
#else
&(curbp->b_bname)
#endif
)) == ABORT) return (s);
else if (s == FALSE) bp = curbp ;
else if ((bp=bfind(bufn, FALSE)) == NULL) return FALSE;
if (bp->b_nwnd != 0) {
if ((bp1 = bp->b_altb) == NULL) return FALSE;
if (bclear(bp) != TRUE) return TRUE;
for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp) {
/* Special case - could use showbuf, but don't */
if (wp->w_bufp == bp) {
--bp->b_nwnd;
++bp1->b_nwnd;
wp->w_bufp = bp1 ;
wp->w_dotp = bp1->b_dotp;
wp->w_doto = bp1->b_doto;
wp->w_markp = bp1->b_markp;
wp->w_marko = bp1->b_marko;
wp->w_linep = bp1->b_linep;
wp->w_flag |= WFMODE|WFFORCE|WFHARD;
}
}
}
else if (bclear(bp) != TRUE) return TRUE;
if (bp == curbp) curbp = bp->b_altb;
free((char *) bp->b_linep); /* Release header line. */
bp1 = NULL; /* Find the header. */
bp2 = bheadp;
while (bp2 != bp) {
if (bp2->b_altb == bp)
bp2->b_altb = (bp->b_altb == bp2) ? NULL : bp->b_altb;
bp1 = bp2;
bp2 = bp2->b_bufp;
}
bp2 = bp2->b_bufp; /* Next one in chain. */
if (bp1 == NULL) /* Unlink it. */
bheadp = bp2;
else
bp1->b_bufp = bp2;
while (bp2 != NULL) { /* Finish with altb's */
if (bp2->b_altb == bp)
bp2->b_altb = (bp->b_altb == bp2) ? NULL : bp->b_altb;
bp2 = bp2->b_bufp;
}
free(bp->b_bname); /* Release name block */
free((char *) bp); /* Release buffer block */
return (TRUE);
}
/*
* Save some buffers - just call anycb with the arg flag.
*/
/*ARGSUSED*/
savebuffers(f, n, k) {
if (anycb(f) == ABORT) return ABORT;
return TRUE;
}
/*
* Display the buffer list. This is done
* in two parts. The "makelist" routine figures out
* the text, and puts it in a buffer. "popbuf"
* then pops the data onto the screen. Bound to
* "C-X C-B".
*/
/*ARGSUSED*/
listbuffers(f, n, k) {
register BUFFER *bp;
register WINDOW *wp;
BUFFER *makelist();
WINDOW *popb();
if ((bp=makelist()) == NULL || (wp=popbuf(bp)) == NULL)
return FALSE;
wp->w_dotp = bp->b_dotp; /* fix up if window already on screen */
wp->w_doto = bp->b_doto;
return TRUE;
}
/*
* This routine rebuilds the text for the
* list buffers command. Return TRUE if
* everything works. Return FALSE if there
* is an error (if there is no memory).
*/
BUFFER *
makelist() {
register char *cp1;
register char *cp2;
register int c;
register BUFFER *bp;
register LINE *lp;
register RSIZE nbytes;
BUFFER *blp;
char b[6+1];
char line[128];
if ((blp = bfind("*Buffer List*", TRUE)) == NULL) return NULL;
if (bclear(blp) != TRUE) return NULL;
blp->b_flag &= ~BFCHG; /* Blow away old. */
(VOID) strcpy(line, " MR Buffer");
cp1 = line + 10;
while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
(VOID) strcpy(cp1, "Size File");
if (addline(blp, line) == FALSE) return NULL;
(VOID) strcpy(line, " -- ------");
cp1 = line + 10;
while(cp1 < line + 4 + NBUFN + 1) *cp1++ = ' ';
(VOID) strcpy(cp1, "---- ----");
if (addline(blp, line) == FALSE) return NULL;
bp = bheadp; /* For all buffers */
while (bp != NULL) {
cp1 = &line[0]; /* Start at left edge */
*cp1++ = (bp == curbp) ? '.' : ' ';
*cp1++ = ((bp->b_flag&BFCHG) != 0) ? '*' : ' ';
*cp1++ = ' '; /* Gap. */
*cp1++ = ' ';
cp2 = &bp->b_bname[0]; /* Buffer name */
while ((c = *cp2++) != 0)
*cp1++ = c;
while (cp1 < &line[4+NBUFN+1])
*cp1++ = ' ';
nbytes = 0; /* Count bytes in buf. */
if (bp != blp) {
lp = lforw(bp->b_linep);
while (lp != bp->b_linep) {
nbytes += llength(lp)+1;
lp = lforw(lp);
}
}
(VOID) itor(b, 6, nbytes); /* 6 digit buffer size. */
cp2 = &b[0];
while ((c = *cp2++) != 0)
*cp1++ = c;
*cp1++ = ' '; /* Gap.. */
cp2 = &bp->b_fname[0]; /* File name */
if (*cp2 != 0) {
while ((c = *cp2++) != 0) {
if (cp1 < &line[128-1])
*cp1++ = c;
}
}
*cp1 = 0; /* Add to the buffer. */
if (addline(blp, line) == FALSE)
return NULL;
bp = bp->b_bufp;
}
blp->b_dotp = lforw(blp->b_linep); /* put dot at beginning of buffer */
blp->b_doto = 0;
return blp; /* All done */
}
/*
* Used above.
*/
static itor(buf, width, num)
register char buf[]; register int width; register RSIZE num; {
register RSIZE r;
if (num / 10 == 0) {
buf[0] = (num % 10) + '0';
for (r = 1; r < width; buf[r++] = ' ')
;
buf[width] = '\0';
return 1;
} else {
buf[r = itor(buf, width, num / (RSIZE)10)] =
(num % (RSIZE)10) + '0';
return r + 1;
}
}
/*
* The argument "text" points to
* a string. Append this line to the
* buffer. Handcraft the EOL
* on the end. Return TRUE if it worked and
* FALSE if you ran out of room.
*/
addline(bp, text) register BUFFER *bp; char *text; {
register LINE *lp;
register int i;
register int ntext;
ntext = strlen(text);
if ((lp=lalloc((RSIZE) ntext)) == NULL)
return (FALSE);
for (i=0; i<ntext; ++i)
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 */
if (bp->b_markp == bp->b_linep) /* ditto for mark */
bp->b_markp = lp;
return (TRUE);
}
/*
* Look through the list of buffers, giving the user
* a chance to save them. Return TRUE if there are
* any changed buffers afterwards. Buffers that don't
* have an associated file don't count. Return FALSE
* if there are no changed buffers.
*/
anycb(f) {
register BUFFER *bp;
register int s = FALSE, save = FALSE;
char prompt[NFILEN + 11];
for (bp = bheadp; bp != NULL; bp = bp->b_bufp) {
if (*(bp->b_fname) != '\0'
&& (bp->b_flag&BFCHG) != 0) {
(VOID) strcpy(prompt, "Save file ");
(VOID) strcpy(prompt + 10, bp->b_fname);
if ((f == TRUE || (save = eyorn(prompt)) == TRUE)
&& writeout(bp, bp->b_fname) == TRUE) {
bp->b_flag &= ~BFCHG;
upmodes(bp);
} else s = TRUE;
if (save == ABORT) return (save);
save = TRUE;
}
}
if (save == FALSE && kbdmop == NULL)
ewprintf("(No files need saving)");
return s;
}
/*
* Search for a buffer, by name.
* If not found, and the "cflag" is TRUE,
* create a buffer and put it in the list of
* all buffers. Return pointer to the BUFFER
* block for the buffer.
*/
BUFFER *
bfind(bname, cflag) register char *bname; {
register BUFFER *bp;
char *malloc();
register LINE *lp;
bp = bheadp;
while (bp != NULL) {
if (strcmp(bname, bp->b_bname) == 0)
return (bp);
bp = bp->b_bufp;
}
if (cflag!=TRUE) return NULL;
/*NOSTRICT*/
if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) {
ewprintf("Can't get %d bytes", sizeof(BUFFER));
return NULL;
}
if ((bp->b_bname=malloc(strlen(bname)+1)) == NULL) {
ewprintf("Can't get %d bytes", strlen(bname)+1);
free((char *) bp);
return NULL;
}
if ((lp=lalloc((RSIZE) 0)) == NULL) {
free(bp->b_bname);
free((char *) bp);
return NULL;
}
bp->b_altb = bp->b_bufp = NULL;
bp->b_dotp = lp;
bp->b_doto = 0;
bp->b_markp = NULL;
bp->b_marko = 0;
bp->b_flag = 0;
bp->b_nwnd = 0;
bp->b_linep = lp;
(VOID) strcpy(bp->b_fname, "");
(VOID) strcpy(bp->b_bname, bname);
lp->l_fp = lp;
lp->l_bp = lp;
bp->b_bufp = bheadp;
bheadp = bp;
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&BFCHG) != 0 /* Changed. */
&& (s=eyesno("Buffer modified; kill anyway")) != 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);
}
/*
* Display the given buffer in the given window. Flags indicated
* action on redisplay.
*/
showbuffer(bp, wp, flags) register BUFFER *bp; register WINDOW *wp; {
register BUFFER *obp;
register WINDOW *owp;
if (wp->w_bufp == bp) { /* Easy case! */
wp->w_flag |= flags;
return TRUE ;
}
/* First, dettach the old buffer from the window */
if ((bp->b_altb = obp = wp->w_bufp) != NULL) {
if (--obp->b_nwnd == 0) {
obp->b_dotp = wp->w_dotp;
obp->b_doto = wp->w_doto;
obp->b_markp = wp->w_markp;
obp->b_marko = wp->w_marko;
}
}
/* Now, attach the new buffer to the window */
wp->w_bufp = bp;
if (bp->b_nwnd++ == 0) { /* First use. */
wp->w_dotp = bp->b_dotp;
wp->w_doto = bp->b_doto;
wp->w_markp = bp->b_markp;
wp->w_marko = bp->b_marko;
} else
/* already on screen, steal values from other window */
for (owp = wheadp; owp != NULL; owp = wp->w_wndp)
if (wp->w_bufp == bp && owp != wp) {
wp->w_dotp = owp->w_dotp;
wp->w_doto = owp->w_doto;
wp->w_markp = owp->w_markp;
wp->w_marko = owp->w_marko;
break;
}
wp->w_flag |= WFMODE|flags;
return TRUE;
}
/*
* Pop the buffer we got passed onto the screen.
* Returns a status.
*/
WINDOW *
popbuf(bp) register BUFFER *bp; {
register WINDOW *wp;
if (bp->b_nwnd == 0) { /* Not on screen yet. */
if ((wp=wpopup()) == NULL) return NULL;
} else
for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
if (wp->w_bufp == bp) {
wp->w_flag |= WFHARD|WFFORCE;
return wp ;
}
if (showbuffer(bp, wp, WFHARD) != TRUE) return NULL;
return wp;
}
/*
* Insert another buffer at dot. Very useful.
*/
bufferinsert(f, n, k)
{
register BUFFER *bp;
register LINE *clp;
register int clo;
register int nline;
int s;
char bufn[NBUFN];
/* Get buffer to use from user */
if (curbp->b_altb != NULL)
s=eread("Insert buffer: (default %s) ", bufn, NBUFN,
EFNEW|EFBUF, &(curbp->b_altb->b_bname),
(char *) NULL) ;
else
s=eread("Insert buffer: ", bufn, NBUFN, EFNEW|EFBUF,
(char *) NULL) ;
if (s == ABORT) return (s);
if (s == FALSE && curbp->b_altb != NULL) bp = curbp->b_altb;
else if ((bp=bfind(bufn, FALSE)) == NULL) return (FALSE);
if (bp==curbp) {
ewprintf("Cannot insert buffer into self");
return (FALSE);
}
/* insert the buffer */
nline = 0;
for (clp = lforw(bp->b_linep); clp != bp->b_linep; clp = lforw(clp)) {
for (clo = 0; clo < llength(clp); clo++)
if (linsert((RSIZE)1, lgetc(clp, clo)) == FALSE)
return (FALSE);
if (newline(FALSE, 1, KRANDOM) == FALSE) /* fake newline */
return (FALSE);
nline++;
}
if (kbdmop==NULL) {
if (nline == 1)
ewprintf("[Inserted 1 line]");
else
ewprintf("[Inserted %d lines]", nline);
}
clp = curwp->w_linep; /* cosmetic adjustment */
if (curwp->w_dotp == clp) { /* for offscreen insert */
while (nline-- && lback(clp)!=curbp->b_linep)
clp = lback(clp);
curwp->w_linep = clp; /* adjust framing. */
curwp->w_flag |= WFHARD;
}
return (TRUE);
}
/*
* Turn off the dirty bit on this buffer.
*/
/*ARGSUSED*/
notmodified(f, n, k)
{
register WINDOW *wp;
curbp->b_flag &= ~BFCHG;
wp = wheadp; /* Update mode lines. */
while (wp != NULL) {
if (wp->w_bufp == curbp)
wp->w_flag |= WFMODE;
wp = wp->w_wndp;
}
ewprintf("Modification-flag cleared");
return (TRUE);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'cinfo.c'
then
echo shar: will not over-write existing file "'cinfo.c'"
else
cat << \SHAR_EOF > 'cinfo.c'
/*
* Character class tables.
* Do it yourself character classification
* macros, that understand the multinational character set,
* and let me ask some questions the standard macros (in
* ctype.h) don't let you ask.
*/
#include "def.h"
/*
* This table, indexed by a character drawn
* from the 256 member character set, is used by my
* own character type macros to answer questions about the
* type of a character. It handles the full multinational
* character set, and lets me ask some questions that the
* standard "ctype" macros cannot ask.
*/
char cinfo[256] = {
_C, _C, _C, _C, /* 0x0X */
_C, _C, _C, _C,
_C, _C, _C, _C,
_C, _C, _C, _C,
_C, _C, _C, _C, /* 0x1X */
_C, _C, _C, _C,
_C, _C, _C, _C,
_C, _C, _C, _C,
0, _P, 0, 0, /* 0x2X */
_W, _W, 0, _W,
0, 0, 0, 0,
0, 0, _P, 0,
_W, _W, _W, _W, /* 0x3X */
_W, _W, _W, _W,
_W, _W, 0, 0,
0, 0, 0, _P,
0, _U|_W, _U|_W, _U|_W, /* 0x4X */
_U|_W, _U|_W, _U|_W, _U|_W,
_U|_W, _U|_W, _U|_W, _U|_W,
_U|_W, _U|_W, _U|_W, _U|_W,
_U|_W, _U|_W, _U|_W, _U|_W, /* 0x5X */
_U|_W, _U|_W, _U|_W, _U|_W,
_U|_W, _U|_W, _U|_W, 0,
0, 0, 0, 0,
0, _L|_W, _L|_W, _L|_W, /* 0x6X */
_L|_W, _L|_W, _L|_W, _L|_W,
_L|_W, _L|_W, _L|_W, _L|_W,
_L|_W, _L|_W, _L|_W, _L|_W,
_L|_W, _L|_W, _L|_W, _L|_W, /* 0x7X */
_L|_W, _L|_W, _L|_W, _L|_W,
_L|_W, _L|_W, _L|_W, 0,
0, 0, 0, _C,
0, 0, 0, 0, /* 0x8X */
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, /* 0x9X */
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, /* 0xAX */
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0, /* 0xBX */
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
_U|_W, _U|_W, _U|_W, _U|_W, /* 0xCX */
_U|_W, _U|_W, _U|_W, _U|_W,
_U|_W, _U|_W, _U|_W, _U|_W,
_U|_W, _U|_W, _U|_W, _U|_W,
0, _U|_W, _U|_W, _U|_W, /* 0xDX */
_U|_W, _U|_W, _U|_W, _U|_W,
_U|_W, _U|_W, _U|_W, _U|_W,
_U|_W, _U|_W, 0, _W,
_L|_W, _L|_W, _L|_W, _L|_W, /* 0xEX */
_L|_W, _L|_W, _L|_W, _L|_W,
_L|_W, _L|_W, _L|_W, _L|_W,
_L|_W, _L|_W, _L|_W, _L|_W,
0, _L|_W, _L|_W, _L|_W, /* 0xFX */
_L|_W, _L|_W, _L|_W, _L|_W,
_L|_W, _L|_W, _L|_W, _L|_W,
_L|_W, _L|_W, 0, 0
};
SHAR_EOF
fi # end of overwriting check
if test -f 'echo.c'
then
echo shar: will not over-write existing file "'echo.c'"
else
cat << \SHAR_EOF > 'echo.c'
/*
* Echo line reading and writing.
*
* Common routines for reading
* and writing characters in the echo line area
* of the display screen. Used by the entire
* known universe.
*/
#include "def.h"
#ifdef VARARGS
# include <varargs.h>
static veread();
#endif
static eformat();
int epresf = FALSE; /* Stuff in echo line flag. */
/*
* Erase the echo line.
*/
eerase() {
ttcolor(CTEXT);
ttmove(nrow-1, 0);
tteeol();
ttflush();
epresf = FALSE;
}
/*
* Ask "yes" or "no" question.
* Return ABORT if the user answers the question
* with the abort ("^G") character. Return FALSE
* for "no" and TRUE for "yes". No formatting
* services are available. No newline required.
*/
eyorn(sp) char *sp; {
register KEY s;
if (kbdmop == NULL) ewprintf("%s? (y or n) ", sp);
for (;;) {
s = getkey(0);
if (s == 'y' || s == 'Y') return (TRUE);
if (s == 'n' || s == 'N') return (FALSE);
if (s == (KCTRL|'G') || s == (KCTLX|KCTRL|'G')
|| s == (KMETA|KCTRL|'G')) {
(VOID) ctrlg(FALSE, 1, KRANDOM);
return ABORT;
}
if (kbdmop == NULL)
ewprintf("Please answer y or n. %s? (y or n) ", sp);
}
}
/*
* Like eyorn, but for more important question. User must type either all of
* "yes" or "no", and the trainling newline.
*/
eyesno(sp) char *sp; {
register int s;
char buf[64];
s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
for (;;) {
if (s == ABORT) return ABORT;
if (s != FALSE) {
if ((buf[0] == 'y' || buf[0] == 'Y')
&& (buf[1] == 'e' || buf[1] == 'E')
&& (buf[2] == 's' || buf[2] == 'S')) return TRUE;
if ((buf[0] == 'n' || buf[0] == 'N')
&& (buf[1] == 'o' || buf[0] == 'O')) return FALSE;
}
s = ereply("Please answer yes or no. %s? (yes or no) ",
buf, sizeof(buf), sp);
}
}
/*
* Write out a prompt, and read back a
* reply. The prompt is now written out with full "ewprintf"
* formatting, although the arguments are in a rather strange
* place. This is always a new message, there is no auto
* completion, and the return is echoed as such.
*/
#ifdef VARARGS
ereply(va_alist)
va_dcl
{
register int i;
va_list pvar;
register char *fp, *buf;
register int nbuf;
va_start(pvar);
fp = va_arg(pvar, char *);
buf = va_arg(pvar, char *);
nbuf = va_arg(pvar, int);
i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
va_end(pvar);
return i;
}
#else
/* VARARGS3 */
ereply(fp, buf, nbuf, arg) char *fp, *buf; int nbuf; long arg; {
return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
}
#endif
/*
* This is the general "read input from the
* echo line" routine. The basic idea is that the prompt
* string "prompt" is written to the echo line, and a one
* line reply is read back into the supplied "buf" (with
* maximum length "len"). The "flag" contains EFNEW (a
* new prompt), an EFFUNC (autocomplete), or EFCR (echo
* the carriage return as CR).
*/
/* VARARGS4 */
#ifdef VARARGS
eread(va_alist)
va_dcl
{
va_list pvar;
char *fp, *buf;
int nbuf, flag, i;
va_start(pvar);
fp = va_arg(pvar, char *);
buf = va_arg(pvar, char *);
nbuf = va_arg(pvar, int);
flag = va_arg(pvar, int);
i = veread(fp, buf, nbuf, flag, &pvar);
va_end(pvar);
return i;
}
#endif
#ifdef VARARGS
static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap; {
#else
eread(fp, buf, nbuf, flag, ap) char *fp; char *buf; char *ap; {
#endif
register int cpos;
register int i;
register KEY c;
cpos = 0;
if (kbdmop != NULL) { /* In a macro. */
while ((c = *kbdmop++) != '\0')
buf[cpos++] = (char) c;
buf[cpos] = '\0';
goto done;
}
if ((flag&EFNEW)!=0 || ttrow!=nrow-1) {
ttcolor(CTEXT);
ttmove(nrow-1, 0);
epresf = TRUE;
} else
eputc(' ');
eformat(fp, ap);
tteeol();
ttflush();
for (;;) {
c = getkey(KQUOTE|KNOMAC);
if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
cpos += complete(flag, c, buf, cpos);
continue;
}
switch (c) {
case 0x0D: /* Return, done. */
if ((flag&EFFUNC) != 0) {
if ((i = complete(flag, c, buf, cpos)) == 0)
continue;
if (i > 0) cpos += i;
}
buf[cpos] = '\0';
if ((flag&EFCR) != 0) {
ttputc(0x0D);
ttflush();
}
if (kbdmip != NULL) {
if (kbdmip+cpos+1 > &kbdm[NKBDM-3]) {
ewprintf("Keyboard macro overflow");
ttflush();
return FALSE;
}
for (i = 0; i <= cpos; ++i)
*kbdmip++ = (KEY) buf[i];
}
goto done;
case CCHR('G'): /* Bell, abort. */
eputc(CCHR('G'));
(VOID) ctrlg(FALSE, 0, KRANDOM);
ttflush();
return (ABORT);
case 0x7F: /* Rubout, erase. */
if (cpos != 0) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
if (ISCTRL(buf[--cpos]) != FALSE) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
}
ttflush();
}
break;
case CCHR('X'): /* C-X */
case CCHR('U'): /* C-U, kill line. */
while (cpos != 0) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
if (ISCTRL(buf[--cpos]) != FALSE) {
ttputc('\b');
ttputc(' ');
ttputc('\b');
--ttcol;
}
}
ttflush();
break;
case CCHR('Q'): /* C-Q, quote next */
c = getkey(KQUOTE|KNOMAC) ;
default: /* All the rest. */
if (cpos < nbuf-1) {
buf[cpos++] = (char) c;
eputc((char) c);
ttflush();
}
}
}
done:
if (buf[0] == '\0')
return (FALSE);
return (TRUE);
}
/*
* do completion on a list of objects.
*/
complete(flags, c, buf, cpos) register char *buf; register int cpos; {
register LIST *lh, *lh2;
#ifndef MANX
register /* too many registers mess Manx up */
#endif
int i, nxtra;
int nhits, bxtra;
int wflag = FALSE;
int msglen, nshown;
char *msg;
if ((flags&EFFUNC) != 0) lh = &(symbol[0]->s_list);
else if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
else panic("broken complete call: flags");
if (c == ' ') wflag = TRUE;
else if (c != '\t' && c != 0x0D) panic("broken complete call: c");
nhits = 0;
nxtra = HUGE;
while (lh != NULL) {
for (i=0; i<cpos; ++i) {
if (buf[i] != lh->l_name[i])
break;
}
if (i == cpos) {
if (nhits == 0)
lh2 = lh;
++nhits;
if (lh->l_name[i] == '\0') nxtra = -1;
else {
bxtra = getxtra(lh, lh2, cpos, wflag);
if (bxtra < nxtra) nxtra = bxtra;
lh2 = lh;
}
}
lh = lh->l_next;
}
if (nhits == 0)
msg = " [No match]";
else if (nhits > 1 && nxtra == 0)
msg = " [Ambiguous]";
else { /* Got a match, do it to it */
/*
* Being lazy - ought to check length, but all things
* autocompleted have known types/lengths.
*/
if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1;
for (i = 0; i < nxtra; ++i) {
buf[cpos] = lh2->l_name[cpos];
eputc(buf[cpos++]);
}
ttflush();
if (nxtra < 0 && c != 0x0D) return 0;
return nxtra;
}
/* Set up backspaces, etc., being mindful of echo line limit */
msglen = strlen(msg);
nshown = (ttcol + msglen + 2 > ncol) ?
ncol - ttcol - 2 : msglen;
eputs(msg);
ttcol -= (i = nshown); /* update ttcol! */
while (i--) /* move back before msg */
ttputc('\b');
ttflush(); /* display to user */
i = nshown;
while (i--) /* blank out on next flush */
eputc(' ');
ttcol -= (i = nshown); /* update ttcol on BS's */
while (i--)
ttputc('\b'); /* update ttcol again! */
return 0;
}
/*
* The "lp1" and "lp2" point to list structures. The
* "cpos" is a horizontal position in the name.
* Return the longest block of characters that can be
* autocompleted at this point. Sometimes the two
* symbols are the same, but this is normal.
*/
getxtra(lp1, lp2, cpos, wflag) register LIST *lp1, *lp2; register int wflag; {
register int i;
i = cpos;
for (;;) {
if (lp1->l_name[i] != lp2->l_name[i]) break;
if (lp1->l_name[i] == '\0') break;
++i;
if (wflag && !ISWORD(lp1->l_name[i-1])) break;
}
return (i - cpos);
}
/*
* Special "printf" for the echo line.
* Each call to "ewprintf" starts a new line in the
* echo area, and ends with an erase to end of the
* echo line. The formatting is done by a call
* to the standard formatting routine.
*/
#ifdef VARARGS
ewprintf(va_alist)
va_dcl
{
va_list pvar;
register char *fp;
va_start(pvar);
fp = va_arg(pvar, char *);
#else
/* VARARGS1 */
ewprintf(fp, arg) char *fp; {
#endif
ttcolor(CTEXT);
ttmove(nrow-1, 0);
#ifdef VARARGS
eformat(fp, &pvar);
va_end(pvar);
#else
eformat(fp, (char *)&arg);
#endif
tteeol();
ttflush();
epresf = TRUE;
}
/*
* Printf style formatting. This is
* called by both "ewprintf" and "ereply" to provide
* formatting services to their clients. The move to the
* start of the echo line, and the erase to the end of
* the echo line, is done by the caller.
* Note: %c works, and prints the "name" of the key. However
* the key must be cast to an int to avoid tripping over
* various oddities in C argument passing.
*/
static eformat(fp, ap) register char *fp;
#ifdef VARARGS
register va_list *ap;
#else
register char *ap;
#endif
{
register int c;
char kname[NKNAME];
while ((c = *fp++) != '\0') {
if (c != '%')
eputc(c);
else {
c = *fp++;
switch (c) {
case 'c':
#ifdef VARARGS
keyname(kname, va_arg(*ap, int));
#else
/*NOSTRICT*/
keyname(kname, *(int *)ap);
ap += sizeof(int);
#endif
eputs(kname);
break;
case 'd':
#ifdef VARARGS
eputi(va_arg(*ap, int), 10);
#else
/*NOSTRICT*/
eputi(*(int *)ap, 10);
ap += sizeof(int);
#endif
break;
case 'o':
#ifdef VARARGS
eputi(va_arg(*ap, int), 8);
#else
/*NOSTRICT*/
eputi(*(int *)ap, 8);
ap += sizeof(int);
#endif
break;
case 's':
#ifdef VARARGS
eputs(va_arg(*ap, char *));
#else
/*NOSTRICT*/
eputs(*(char **)ap);
ap += sizeof(char *);
#endif
break;
case 'l':/* explicit longword */
c = *fp++;
switch(c) {
case 'd':
#ifdef VARARGS
eputl((long)va_arg(*ap, long), 10L);
#else
/*NOSTRICT*/
eputl(*(long *)ap, 10L);
ap += sizeof(long);
#endif
break;
default:
eputc(c);
break;
}
break;
default:
eputc(c);
}
}
}
}
/*
* Put integer, in radix "r".
*/
static eputi(i, r) register int i; register int r; {
register int q;
if ((q=i/r) != 0)
eputi(q, r);
eputc(i%r+'0');
}
/*
* Put long, in radix "r".
*/
static eputl(l, r) register long l; register long r; {
register long q;
if ((q=l/r) != 0)
eputl(q, r);
eputc((int)(l%r)+'0');
}
/*
* Put string.
*/
eputs(s) register char *s; {
register int c;
while ((c = *s++) != '\0')
eputc(c);
}
/*
* Put character. Watch for
* control characters, and for the line
* getting too long.
*/
static eputc(c) register char c; {
if (ttcol+2 < ncol) {
if (ISCTRL(c) != FALSE) {
eputc('^');
c ^= 0x40;
}
ttputc(c);
++ttcol;
}
}
SHAR_EOF
fi # end of overwriting check
if test -f 'extend.c'
then
echo shar: will not over-write existing file "'extend.c'"
else
cat << \SHAR_EOF > 'extend.c'
/*
* Extended (M-X) commands.
*/
#include "def.h"
/*
* This function modifies the keyboard
* binding table, by adjusting the entries in the
* big "bindings" array. Most of the grief deals with the
* prompting for additional arguments.
*/
/*ARGSUSED*/
bindtokey(f, n, k) {
register int s;
register SYMBOL *sp;
int c;
char xname[NXNAME];
if (kbdmop == NULL)
ewprintf("Set key globally: ") ;
c = (int) getkey(0);
if ((s=eread("Set key %c to command: ", xname, NXNAME, EFNEW|EFFUNC,
#ifdef VARARGS
c
#else
(char *) &c, (char *) NULL
#endif
)) != TRUE)
return (s);
if ((sp=symlookup(xname)) == NULL) {
ewprintf("[No match]");
return (FALSE);
}
binding[(KEY) c] = sp; /* rebind new. */
return (TRUE);
}
/*
* User function to unbind keys. Just call the unbind we already have.
*/
/*ARGSUSED*/
unsetkey(f, n, k) {
register KEY key;
if (kbdmop == NULL) ewprintf("Unset key globally: ") ;
key = getkey(0);
if (key == (KCTRL|'G') || key == (KCTLX|KCTRL|'G')
|| key == (KMETA|KCTRL|'G')) {
(VOID) ctrlg(FALSE, 1, KRANDOM);
return ABORT;
}
binding[key] = NULL;
return TRUE;
}
/*
* Extended command. Call the message line
* routine to read in the command name and apply autocompletion
* to it. When it comes back, look the name up in the symbol table
* and run the command if it is found and has the right type.
* Print an error if there is anything wrong.
*/
/*ARGSUSED*/
extend(f, n, k) {
register SYMBOL *sp;
register int s;
char xname[NXNAME];
if (f == FALSE)
s = eread("M-x ", xname, NXNAME, EFNEW|EFFUNC
#ifndef VARARGS
, (char *) NULL
#endif
) ;
else
s = eread("%d M-x ", xname, NXNAME, EFNEW|EFFUNC,
#ifdef VARARGS
n
#else
(char *) &n, (char *) NULL
#endif
) ;
if (s != TRUE) return (s);
if ((sp=symlookup(xname)) != NULL)
return ((*sp->s_funcp)(f, n, KRANDOM));
ewprintf("[No match]");
return FALSE;
}
/*
* Read a key from the keyboard, and look it
* up in the binding table. Display the name of the function
* currently bound to the key. Say that the key is not bound
* if it is indeed not bound, or if the type is not a
* "builtin". This is a bit of overkill, because this is the
* only kind of function there is.
*/
/*ARGSUSED*/
desckey(f, n, k) {
register SYMBOL *sp;
register KEY c;
if (kbdmop == NULL) ewprintf("Describe key briefly: ");
c = getkey(0);
if (kbdmop != NULL) return TRUE;
if ((sp=binding[c]) == NULL)
ewprintf("%c is undefined", (int) c);
else
ewprintf("%c runs the command %s", (int) c, sp->s_name);
return (TRUE);
}
/*
* This function creates a table, listing all
* of the command keys and their current bindings, and stores
* the table in the standard pop-op buffer (the one used by the
* directory list command, the buffer list command, etc.). This
* lets MicroEMACS produce it's own wall chart. The bindings to
* "ins-self" are only displayed if there is an argument.
*/
/*ARGSUSED*/
wallchart(f, n, k) {
register int key;
register SYMBOL *sp;
register char *cp1;
register char *cp2;
BUFFER *bp;
char buf[64];
bp = bfind("*Help*", TRUE);
if (bclear(bp) != TRUE) /* Clear it out. */
return TRUE;
for (key=0; key<NKEYS; ++key) { /* For all keys. */
sp = binding[key];
if (sp != NULL
&& (f!=FALSE
|| strcmp(sp->s_name, "self-insert-command")!=0)) {
keyname(buf, key);
cp1 = &buf[0]; /* Find end. */
while (*cp1 != 0)
++cp1;
while (cp1 < &buf[32]) /* Goto column 32. */
*cp1++ = ' ';
cp2 = sp->s_name; /* Add function name. */
while (*cp1++ = *cp2++)
;
if (addline(bp, buf) == FALSE)
return (FALSE);
}
}
return popbuf(bp) == NULL ? FALSE : TRUE;
}
#ifdef STARTUP
/*
* Define the commands needed to do startup-file processing.
* This code is mostly a kludge just so we can get startup-file processing.
*
* If you're serious about having this code, you should rewrite it.
* To wit:
* It has lots of funny things in it to make the startup-file look
* like a GNU startup file; mostly dealing with parens and semicolons.
* This should all vanish.
*
* It uses the same buffer as keyboard macros. The fix is easy (make
* a new function "execmacro" that takes a pointer to char and
* does what ctlxe does on it. Make ctlxe and excline both call it.)
* but would slow down the non-micro version.
*
* We define eval-expression because it's easy. It's pretty useless,
* since it duplicates the functionality of execute-extended-command.
* All of this is just to support startup files, and should be turned
* off for micros.
*/
/*
* evalexpr - get one line from the user, and run it. Identical in function
* to extend, but easy.
*/
/*ARGSUSED*/
evalexpr(f, n, k) {
register int s;
char exbuf[NKBDM];
if ((s = ereply("Eval: ", exbuf, NKBDM)) != TRUE)
return s;
return excline(exbuf);
}
/*
* evalbuffer - evaluate the current buffer as line commands. Useful
* for testing startup files.
*/
/*ARGSUSED*/
evalbuffer(f, n, k) {
register LINE *lp;
register BUFFER *bp = curbp;
register int s;
static char excbuf[NKBDM];
char *strncpy();
for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
if (llength(lp) >= NKBDM + 1) return FALSE ;
(VOID) strncpy(excbuf, ltext(lp), NKBDM);
if ((s = excline(excbuf)) != TRUE) return s;
}
return TRUE;
}
/*
* evalfile - go get a file and evaluate it as line commands. You can
* go get your own startup file if need be.
*/
/*ARGSUSED*/
evalfile(f, n, k) {
register int s;
char fname[NFILEN];
if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
return s;
return load(fname);
}
/*
* load - go load the file name we got passed.
*/
load(fname) char *fname; {
register int s;
char excbuf[NKBDM];
if (ffropen(fname) == FIOERR)
return FALSE;
while ((s = ffgetline(excbuf, NKBDM)) == FIOSUC)
if (excline(excbuf) != TRUE) break;
(VOID) ffclose();
return s == FIOEOF;
}
/*
* excline - run a line from a load file or eval-expression.
*/
excline(line) register char *line; {
register char *funcp, *argp = NULL;
char *skipwhite(), *parsetoken(), *backquote();
int status;
/* Don't know if it works; don't care - mwm */
if (kbdmip != NULL || kbdmop != NULL) {
ewprintf("Not now!") ;
return FALSE;
}
funcp = skipwhite(line);
if (*funcp == '\0') return TRUE; /* No error on blank lines */
line = parsetoken(funcp);
if (*line != '\0') {
*line++ = '\0';
line = skipwhite(line);
if ((*line >= '0' && *line <= '9') || *line == '-') {
argp = line;
line = parsetoken(line);
}
}
kbdmip = &kbdm[0];
if (argp != NULL) {
*kbdmip++ = (KEY) (KCTRL|'U');
*kbdmip++ = (KEY) atoi(argp);
}
*kbdmip++ = (KEY) (KMETA|'X');
/* Pack in function */
while (*funcp != '\0')
if (kbdmip+1 <= &kbdm[NKBDM-3]) *kbdmip++ = (KEY) *funcp++;
else {
ewprintf("eval-expression macro overflow");
ttflush();
return FALSE;
}
*kbdmip++ = '\0'; /* done with function */
/* Pack away all the args now... */
while (*line != '\0') {
argp = skipwhite(line);
if (*argp == '\0') break ;
line = parsetoken(argp) ;
/* Slightly bogus for strings. But they should be SHORT! */
if (kbdmip+(line-argp)+1 > &kbdm[NKBDM-3]) {
ewprintf("eval-expression macro overflow");
ttflush();
return FALSE;
}
if (*line != '\0') *line++ = '\0';
if (*argp != '"') {
if (*argp == '\'') ++argp;
while (*argp != '\0')
*kbdmip++ = (KEY) *argp++;
*kbdmip++ = '\0';
}
else { /* Quoted strings special again */
++argp;
while (*argp != '"' && *argp != '\0')
if (*argp != '\\') *kbdmip++ = (KEY) *argp++;
else argp = backquote(++argp, TRUE);
/* Quotes strings are gotkey'ed, so no trailing null */
}
}
*kbdmip++ = (KEY) (KCTLX|')');
*kbdmip++ = '\0';
kbdmip = NULL;
status = ctlxe(FALSE, 1, KRANDOM);
kbdm[0] = (KCTLX|')');
return status;
}
/*
* a pair of utility functions for the above
*/
char *
skipwhite(s) register char *s; {
while ((*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
&& *s != '\0')
if (*s == ';') *s = '\0' ;
else s++;
return s;
}
char *
parsetoken(s) register char *s; {
if (*s != '"')
while (*s != ' ' && *s != '\t' && *s != '(' && *s != ')'
&& *s != '\0') {
if (*s == ';') *s = '\0';
else s++;
}
else /* Strings get special treatment */
do {
/* Beware: You can \ out the end of the string! */
if (*s == '\\') ++s;
if (ISLOWER(*s)) *s = TOUPPER(*s);
} while (*++s != '"' && *s != '\0');
return s;
}
/*
* Put a backquoted string element into the keyboard macro. Return pointer
* to char following backquoted stuff.
*/
char *
backquote(in, flag) char *in; {
switch (*in++) {
case 'T': *kbdmip++ = (KEY) (KCTRL|'I');
break;
case 'N': *kbdmip++ = (KEY) (KCTRL|'J');
break;
case 'R': *kbdmip++ = (KEY) (KCTRL|'M');
break;
case '^': *kbdmip = (KEY) (KCTRL|*in++);
if (flag != FALSE && *kbdmip == (KEY) (KCTRL|'X')) {
if (*in == '\\') in = backquote(++in, FALSE);
else *kbdmip++ = (KEY) *in++;
kbdmip[-1] |= (KEY) KCTLX;
} else ++kbdmip;
break;
case 'E':
if (flag != TRUE) *kbdmip++ = (KEY) (KCTRL|'[');
else if (*in != '\\') *kbdmip++ = (KEY) (KMETA|*in++);
else {
in = backquote(++in, FALSE);
kbdmip[-1] |= (KEY) KMETA;
}
break;
}
return in;
}
#endif STARTUP
SHAR_EOF
fi # end of overwriting check
if test -f 'file.c'
then
echo shar: will not over-write existing file "'file.c'"
else
cat << \SHAR_EOF > 'file.c'
/*
* File commands.
*/
#include "def.h"
BUFFER *findbuffer();
/*
* insert a file into the current buffer. Real easy - just call the
* insertfile routine with the file name.
*/
/*ARGSUSED*/
fileinsert(f, n, k) {
register int s;
char fname[NFILEN];
if ((s=ereply("Insert file: ", fname, NFILEN)) != TRUE)
return (s);
adjustcase(fname);
return (insertfile(fname, (char *) NULL)); /* don't set buffer name */
}
/*
* Select a file for editing.
* Look around to see if you can find the
* fine in another buffer; if you can find it
* just switch to the buffer. If you cannot find
* the file, create a new buffer, read in the
* text, and switch to the new buffer.
*/
/*ARGSUSED*/
filevisit(f, n, k) {
register BUFFER *bp;
int s;
char fname[NFILEN];
if ((s=ereply("Find file: ", fname, NFILEN)) != TRUE)
return (s);
if ((bp = findbuffer(fname, &s)) == NULL) return s;
curbp = bp;
if (showbuffer(bp, curwp, WFHARD) != TRUE) return FALSE;
if (bp->b_fname[0] == 0)
return (readin(fname)); /* Read it in. */
return TRUE;
}
/*
* Pop to a file in the other window. Same as last function, just
* popbuf instead of showbuffer.
*/
/*ARGSUSED*/
poptofile(f, n, k) {
register BUFFER *bp;
register WINDOW *wp;
int s;
char fname[NFILEN];
if ((s=ereply("Find file in other window: ", fname, NFILEN)) != TRUE)
return (s);
if ((bp = findbuffer(fname, &s)) == NULL) return s;
if ((wp = popbuf(bp)) == NULL) return FALSE;
curbp = bp;
curwp = wp;
if (bp->b_fname[0] == 0)
return (readin(fname)); /* Read it in. */
return TRUE;
}
/*
* given a file name, either find the buffer it uses, or create a new
* empty buffer to put it in.
*/
BUFFER *
findbuffer(fname, s) char *fname; int *s; {
register BUFFER *bp;
char bname[NBUFN];
adjustcase(fname);
for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
if (strcmp(bp->b_fname, fname) == 0) {
return bp;
}
}
makename(bname, fname); /* New buffer name. */
while ((bp=bfind(bname, FALSE)) != NULL) {
*s = ereply("Buffer name: ", bname, NBUFN);
if (*s == ABORT) /* ^G to just quit */
return NULL;
if (*s == FALSE) { /* CR to clobber it */
bp->b_fname[0] = '\0';
break;
}
}
if (bp == NULL) bp = bfind(bname, TRUE);
*s = FALSE;
return bp;
}
/*
* Read the file "fname" into the current buffer.
* Make all of the text in the buffer go away, after checking
* for unsaved changes. This is called by the "read" command, the
* "visit" command, and the mainline (for "uemacs file").
*/
readin(fname) char *fname; {
register int status;
register WINDOW *wp;
if (bclear(curbp) != TRUE) /* Might be old. */
return TRUE;
status = insertfile(fname, fname) ;
curbp->b_flag &= ~BFCHG; /* No change. */
for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
if (wp->w_bufp == curbp) {
wp->w_linep = lforw(curbp->b_linep);
wp->w_dotp = lforw(curbp->b_linep);
wp->w_doto = 0;
wp->w_markp = NULL;
wp->w_marko = 0;
}
}
return status;
}
/*
* insert a file in the current buffer, after dot. Set mark
* at the end of the text inserted, point at the beginning.
* Return a standard status. Print a summary (lines read,
* error message) out as well. If the
* BACKUP conditional is set, then this routine also does the read
* end of backup processing. The BFBAK flag, if set in a buffer,
* says that a backup should be taken. It is set when a file is
* read in, but not on a new file (you don't need to make a backup
* copy of nothing).
*
* Warning: Adds a trainling nl to files that don't end in one!
* Need to fix, but later (I suspect that it will require a change
* in the fileio files for all systems involved).
*/
insertfile(fname, newname) char fname[], newname[]; {
register LINE *lp1;
register LINE *lp2;
LINE *olp; /* Line we started at */
int opos; /* and offset into it */
register WINDOW *wp;
register int i;
register int nbytes;
int s, nline;
BUFFER *bp;
char line[NLINE];
bp = curbp; /* Cheap. */
if (newname != (char *) NULL)
(VOID) strcpy(bp->b_fname, newname);
if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
goto out;
if (s == FIOFNF) { /* File not found. */
if (kbdmop == NULL)
if (newname != NULL)
ewprintf("(New file)");
else ewprintf("(File not found)");
goto out;
}
opos = curwp->w_doto;
/* Open a new line, at point, and start inserting after it */
(VOID) lnewline();
olp = lback(curwp->w_dotp);
nline = 0; /* Don't count fake line at end */
while ((s=ffgetline(line, NLINE)) == FIOSUC) {
nbytes = strlen(line);
if ((lp1=lalloc((RSIZE) nbytes)) == NULL) {
s = FIOERR; /* Keep message on the */
break; /* display. */
}
lp2 = lback(curwp->w_dotp);
lp2->l_fp = lp1;
lp1->l_fp = curwp->w_dotp;
lp1->l_bp = lp2;
curwp->w_dotp->l_bp = lp1;
for (i=0; i<nbytes; ++i)
lputc(lp1, i, line[i]);
++nline;
}
(VOID) ffclose(); /* Ignore errors. */
if (s==FIOEOF && kbdmop==NULL) { /* Don't zap an error. */
if (nline == 1)
ewprintf("(Read 1 line)");
else
ewprintf("(Read %d lines)", nline);
}
/* Set mark at the end of the text */
curwp->w_markp = curwp->w_dotp;
curwp->w_marko = curwp->w_doto;
/* Now, delete the results of the lnewline we started with */
curwp->w_dotp = olp;
curwp->w_doto = opos;
(VOID) ldelnewline();
curwp->w_doto = opos; /* and dot is right */
#ifdef BACKUP
if (newname != NULL)
bp->b_flag |= BFCHG | BFBAK; /* Need a backup. */
else bp->b_flag |= BFCHG;
#else
bp->b_flag |= BFCHG;
#endif
/* if the insert was at the end of buffer, set lp1 to the end of
* buffer line, and lp2 to the beginning of the newly inserted
* text. (Otherwise lp2 is set to NULL.) This is
* used below to set pointers in other windows correctly if they
* are also at the end of buffer.
*/
lp1 = bp->b_linep;
if (curwp->w_markp == lp1)
lp2 = curwp->w_dotp;
else {
out: lp2 = NULL;
}
for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
if (wp->w_bufp == curbp) {
wp->w_flag |= WFMODE|WFEDIT;
if (wp != curwp && lp2 != NULL) {
if (wp->w_dotp == lp1)
wp->w_dotp = lp2;
if (wp->w_markp == lp1)
wp->w_markp = lp2;
if (wp->w_linep == lp1)
wp->w_linep = lp2;
}
}
}
if (s == FIOERR) /* False if error. */
return (FALSE);
return (TRUE);
}
/*
* Take a file name, and from it
* fabricate a buffer name. This routine knows
* about the syntax of file names on the target system.
* BDC1 left scan delimiter.
* BDC2 optional second left scan delimiter.
* BDC3 optional right scan delimiter.
*/
makename(bname, fname) char bname[]; char fname[]; {
register char *cp1;
register char *cp2;
cp1 = &fname[0];
while (*cp1 != 0)
++cp1;
#ifdef BDC2
while (cp1!=&fname[0] && cp1[-1]!=BDC1 && cp1[-1]!=BDC2)
--cp1;
#else
while (cp1!=&fname[0] && cp1[-1]!=BDC1)
--cp1;
#endif
cp2 = &bname[0];
#ifdef BDC3
while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=BDC3)
*cp2++ = *cp1++;
#else
while (cp2!=&bname[NBUFN-1] && *cp1!=0)
*cp2++ = *cp1++;
#endif
*cp2 = 0;
}
/*
* Ask for a file name, and write the
* contents of the current buffer to that file.
* Update the remembered file name and clear the
* buffer changed flag. This handling of file names
* is different from the earlier versions, and
* is more compatable with Gosling EMACS than
* with ITS EMACS.
*/
/*ARGSUSED*/
filewrite(f, n, k) {
register int s;
char fname[NFILEN];
if ((s=ereply("Write file: ", fname, NFILEN)) != TRUE)
return (s);
adjustcase(fname);
if ((s=writeout(curbp, fname)) == TRUE) {
(VOID) strcpy(curbp->b_fname, fname);
#ifdef BACKUP
curbp->b_flag &= ~(BFBAK | BFCHG);
#else
curbp->b_flag &= ~BFCHG;
#endif
upmodes(curbp);
}
return (s);
}
/*
* Save the contents of the current buffer back into
* its associated file. Do nothing if there have been no changes
* (is this a bug, or a feature). Error if there is no remembered
* file name. If this is the first write since the read or visit,
* then a backup copy of the file is made.
*/
/*ARGSUSED*/
filesave(f, n, k) {
register int s;
if ((curbp->b_flag&BFCHG) == 0) { /* Return, no changes. */
if (kbdmop == NULL) ewprintf("(No changes need to be saved)");
return (TRUE);
}
if (curbp->b_fname[0] == 0) { /* Must have a name. */
ewprintf("No file name");
return (FALSE);
}
#ifdef BACKUP
if ((curbp->b_flag&BFBAK) != 0) {
s = fbackupfile(curbp->b_fname);
if (s == ABORT) /* Hard error. */
return FALSE;
if (s == FALSE /* Softer error. */
&& (s=eyesno("Backup error, save anyway")) != TRUE)
return (s);
}
#endif
if ((s=writeout(curbp, curbp->b_fname)) == TRUE) {
#ifdef BACKUP
curbp->b_flag &= ~(BFCHG | BFBAK);
#else
curbp->b_flag &= ~BFCHG;
#endif
upmodes(curbp);
}
return (s);
}
/*
* This function performs the details of file
* writing; writing the file in buffer bp to
* file fn. Uses the file management routines
* in the "fileio.c" package. Most of the grief
* is checking of some sort.
*/
writeout(bp, fn) register BUFFER *bp; char *fn; {
register int s;
register LINE *lp;
if ((s=ffwopen(fn)) != FIOSUC) /* Open writes message. */
return (FALSE);
lp = lforw(bp->b_linep); /* First line. */
while (lp != bp->b_linep) {
if ((s=ffputline(&(ltext(lp))[0], llength(lp))) != FIOSUC)
break;
lp = lforw(lp);
}
if (s == FIOSUC) { /* No write error. */
s = ffclose();
if (s==FIOSUC && kbdmop==NULL)
ewprintf("Wrote %s", fn);
} else /* Ignore close error */
(VOID) ffclose(); /* if a write error. */
if (s != FIOSUC) /* Some sort of error. */
return (FALSE);
return (TRUE);
}
/*
* Tag all windows for bp (all windows if bp NULL) as needing their
* mode line updated.
*/
upmodes(bp) register BUFFER *bp; {
register WINDOW *wp;
for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
if (bp == NULL || curwp->w_bufp == bp) wp->w_flag |= WFMODE;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'match.c'
then
echo shar: will not over-write existing file "'match.c'"
else
cat << \SHAR_EOF > 'match.c'
/*
* Name: MicroEMACS
* Limited parenthesis matching routines
* Version: Gnu30
* Last edit: 13-Jul-86
* Created: 19-May-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
*
* The hacks in this file implement automatic matching
* of (), [], {}, and other characters. It would be
* better to have a full-blown syntax table, but there's
* enough overhead in the editor as it is.
*
* Since I often edit Scribe code, I've made it possible to
* blink arbitrary characters -- just bind delimiter characters
* to "blink-matching-paren-hack"
*/
#include "def.h"
/* Balance table. When balance() encounters a character
* that is to be matched, it first searches this table
* for a balancing left-side character. If the character
* is not in the table, the character is balanced by itself.
* This is to allow delimiters in Scribe documents to be matched.
*/
static struct balance {
char left, right;
} bal[] = {
{ '(', ')' },
{ '[', ']' },
{ '{', '}' },
{ '<', '>' },
{ '\0','\0'}
};
/*
* Fake the GNU "blink-matching-paren" variable.
* If the argument exists, nonzero means show,
* zero means don't. If it doesn't exist,
* pretend it's nonzero.
*/
blinkparen(f, n, k)
{
register char *command;
register SYMBOL *sp;
if (f == FALSE)
n = 1;
command = (n == 0) ? "self-insert-command" :
"blink-matching-paren-hack";
if ((sp=symlookup(command)) == NULL) {
ewprintf("blinkparen: no binding for %s",command);
return (FALSE);
}
binding[(KEY) ')'] = sp; /* rebind paren */
return (TRUE);
}
/*
* Self-insert character, then show matching character,
* if any. Bound to "blink-matching-paren-command".
*/
showmatch(f, n, k)
{
register int i, s;
if (k == KRANDOM)
return(FALSE);
for (i = 0; i < n; i++) {
if ((s = selfinsert(f, 1, k)) != TRUE)
return(s);
if (balance(k) != TRUE) /* unbalanced -- warn user */
ttbeep();
}
return (TRUE);
}
/*
* Search for and display a matching character.
*
* This routine does the real work of searching backward
* for a balancing character. If such a balancing character
* is found, it uses displaymatch() to display the match.
*/
static balance(k)
int k;
{
register LINE *clp;
register int cbo;
int c;
int i;
int rbal, lbal;
int depth;
rbal = k & KCHAR;
if ((k&KCTRL)!=0 && rbal>='@' && rbal<='_') /* ASCII-ify. */
rbal -= '@';
/* See if there is a matching character -- default to the same */
lbal = rbal;
for (i = 0; bal[i].right != '\0'; i++)
if (bal[i].right == rbal) {
lbal = bal[i].left;
break;
}
/* Move behind the inserted character. We are always guaranteed */
/* that there is at least one character on the line, since one was */
/* just self-inserted by blinkparen. */
clp = curwp->w_dotp;
cbo = curwp->w_doto - 1;
depth = 0; /* init nesting depth */
for (;;) {
if (cbo == 0) { /* beginning of line */
clp = lback(clp);
if (clp == curbp->b_linep)
return (FALSE);
cbo = llength(clp)+1;
}
if (--cbo == llength(clp)) /* end of line */
c = '\n';
else
c = lgetc(clp,cbo); /* somewhere in middle */
/* Check for a matching character. If still in a nested */
/* level, pop out of it and continue search. This check */
/* is done before the nesting check so single-character */
/* matches will work too. */
if (c == lbal) {
if (depth == 0) {
displaymatch(clp,cbo);
return (TRUE);
}
else
depth--;
}
/* Check for another level of nesting. */
if (c == rbal)
depth++;
}
}
/*
* Display matching character.
* Matching characters that are not in the current window
* are displayed in the echo line. If in the current
* window, move dot to the matching character,
* sit there a while, then move back.
*/
static displaymatch(clp, cbo)
register LINE *clp;
register int cbo;
{
register LINE *tlp;
register int tbo;
register int cp;
register int bufo;
register int c;
int inwindow;
char buf[NLINE];
/* Figure out if matching char is in current window by */
/* searching from the top of the window to dot. */
inwindow = FALSE;
for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp))
if (tlp == clp)
inwindow = TRUE;
if (inwindow == TRUE) {
tlp = curwp->w_dotp; /* save current position */
tbo = curwp->w_doto;
curwp->w_dotp = clp; /* move to new position */
curwp->w_doto = cbo;
curwp->w_flag |= WFMOVE;
update(); /* show match */
sleep(1); /* wait a bit */
curwp->w_dotp = tlp; /* return to old position */
curwp->w_doto = tbo;
curwp->w_flag |= WFMOVE;
update();
}
else { /* match not in this window so display line in echo area */
bufo = 0;
for (cp = 0; cp < llength(clp); cp++) { /* expand tabs */
c = lgetc(clp,cp);
if (c != '\t')
buf[bufo++] = c;
else
do {
buf[bufo++] = ' ';
} while (bufo & 7);
}
buf[bufo++] = '\0';
ewprintf("Matches %s",buf);
}
return (TRUE);
}
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Mod.sources
mailing list