v08i010: A Micro-Emacs variant that resembles GNU Emacs
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Wed Jan 28 04:16:38 AEST 1987
Submitted by: Bob Larson <seismo!usc-oberon!blarson>
Mod.sources: Volume 8, Issue 10
Archive-name: micrognu/Part03
#! /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:
# line.c
# main.c
# paragraph.c
# random.c
# region.c
# prefix.c
# version.c
# word.c
# This archive created: Sat Nov 15 15:02:19 1986
export PATH; PATH=/bin:$PATH
if test -f 'line.c'
then
echo shar: will not over-write existing file "'line.c'"
else
cat << \SHAR_EOF > 'line.c'
/*
* Text line handling.
* The functions in this file
* are a general set of line management
* utilities. They are the only routines that
* touch the text. They also touch the buffer
* and window structures, to make sure that the
* necessary updating gets done. There are routines
* in this file that handle the kill buffer too.
* It isn't here for any good reason.
*
* Note that this code only updates the dot and
* mark values in the window list. Since all the code
* acts on the current window, the buffer that we
* are editing must be being displayed, which means
* that "b_nwnd" is non zero, which means that the
* dot and mark values in the buffer headers are
* nonsense.
*/
#include "def.h"
#define NBLOCK 16 /* Line block chunk size */
#ifndef KBLOCK
#define KBLOCK 256 /* Kill buffer block size. */
#endif
static char *kbufp = NULL; /* Kill buffer data. */
static RSIZE kused = 0; /* # of bytes used in KB. */
static RSIZE ksize = 0; /* # of bytes allocated in KB. */
static RSIZE kstart = 0; /* # of first used byte in KB. */
char *malloc();
/*
* This routine allocates a block
* of memory large enough to hold a LINE
* containing "used" characters. The block is
* always rounded up a bit. Return a pointer
* to the new block, or NULL if there isn't
* any memory left. Print a message in the
* message line if no space.
*/
LINE *
lalloc(used) register RSIZE used; {
register LINE *lp;
register int size;
/*NOSTRICT*/
size = (NBLOCK-1+used) & ~(NBLOCK-1);
if (size == 0) /* Assume that an empty */
size = NBLOCK; /* line is for type-in. */
/*NOSTRICT*/
if ((lp=(LINE *)malloc(sizeof(LINE)+size)) == NULL) {
ewprintf("Can't get %d bytes", sizeof(LINE) + size);
return (NULL);
}
lp->l_size = size;
/*NOSTRICT*/
lp->l_used = used;
return (lp);
}
/*
* Delete line "lp". Fix all of the
* links that might point at it (they are
* moved to offset 0 of the next line.
* Unlink the line from whatever buffer it
* might be in. Release the memory. The
* buffers are updated too; the magic conditions
* described in the above comments don't hold
* here.
*/
lfree(lp) register LINE *lp; {
register BUFFER *bp;
register WINDOW *wp;
wp = wheadp;
while (wp != NULL) {
if (wp->w_linep == lp)
wp->w_linep = lp->l_fp;
if (wp->w_dotp == lp) {
wp->w_dotp = lp->l_fp;
wp->w_doto = 0;
}
if (wp->w_markp == lp) {
wp->w_markp = lp->l_fp;
wp->w_marko = 0;
}
wp = wp->w_wndp;
}
bp = bheadp;
while (bp != NULL) {
if (bp->b_nwnd == 0) {
if (bp->b_dotp == lp) {
bp->b_dotp = lp->l_fp;
bp->b_doto = 0;
}
if (bp->b_markp == lp) {
bp->b_markp = lp->l_fp;
bp->b_marko = 0;
}
}
bp = bp->b_bufp;
}
lp->l_bp->l_fp = lp->l_fp;
lp->l_fp->l_bp = lp->l_bp;
free((char *) lp);
}
/*
* This routine gets called when
* a character is changed in place in the
* current buffer. It updates all of the required
* flags in the buffer and window system. The flag
* used is passed as an argument; if the buffer is being
* displayed in more than 1 window we change EDIT to
* HARD. Set MODE if the mode line needs to be
* updated (the "*" has to be set).
*/
lchange(flag) register int flag; {
register WINDOW *wp;
if (curbp->b_nwnd != 1) /* Ensure hard. */
flag = WFHARD;
if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
flag |= WFMODE; /* update mode lines. */
curbp->b_flag |= BFCHG;
}
wp = wheadp;
while (wp != NULL) {
if (wp->w_bufp == curbp)
wp->w_flag |= flag;
wp = wp->w_wndp;
}
}
/*
* Insert "n" copies of the character "c"
* at the current location of dot. In the easy case
* all that happens is the text is stored in the line.
* In the hard case, the line has to be reallocated.
* When the window list is updated, take special
* care; I screwed it up once. You always update dot
* in the current window. You update mark, and a
* dot in another window, if it is greater than
* the place where you did the insert. Return TRUE
* if all is well, and FALSE on errors.
*/
linsert(n, c) RSIZE n; {
register char *cp1;
register char *cp2;
register LINE *lp1;
register LINE *lp2;
register LINE *lp3;
register int doto;
register RSIZE i;
register WINDOW *wp;
lchange(WFEDIT);
lp1 = curwp->w_dotp; /* Current line */
if (lp1 == curbp->b_linep) { /* At the end: special */
if (curwp->w_doto != 0) {
ewprintf("bug: linsert");
return (FALSE);
}
if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
return (FALSE);
lp3 = lp1->l_bp; /* Previous line */
lp3->l_fp = lp2; /* Link in */
lp2->l_fp = lp1;
lp1->l_bp = lp2;
lp2->l_bp = lp3;
for (i=0; i<n; ++i)
lp2->l_text[i] = c;
wp = wheadp; /* Update windows */
while (wp != NULL) {
if (wp->w_linep == lp1)
wp->w_linep = lp2;
if (wp->w_dotp == lp1)
wp->w_dotp = lp2;
if (wp->w_markp == lp1)
wp->w_markp = lp2;
wp = wp->w_wndp;
}
/*NOSTRICT*/
curwp->w_doto = n;
return (TRUE);
}
doto = curwp->w_doto; /* Save for later. */
/*NOSTRICT (2) */
if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
if ((lp2=lalloc((RSIZE) (lp1->l_used+n))) == NULL)
return (FALSE);
cp1 = &lp1->l_text[0];
cp2 = &lp2->l_text[0];
while (cp1 != &lp1->l_text[doto])
*cp2++ = *cp1++;
/*NOSTRICT*/
cp2 += n;
while (cp1 != &lp1->l_text[lp1->l_used])
*cp2++ = *cp1++;
lp1->l_bp->l_fp = lp2;
lp2->l_fp = lp1->l_fp;
lp1->l_fp->l_bp = lp2;
lp2->l_bp = lp1->l_bp;
free((char *) lp1);
} else { /* Easy: in place */
lp2 = lp1; /* Pretend new line */
/*NOSTRICT*/
lp2->l_used += n;
cp2 = &lp1->l_text[lp1->l_used];
cp1 = cp2-n;
while (cp1 != &lp1->l_text[doto])
*--cp2 = *--cp1;
}
for (i=0; i<n; ++i) /* Add the characters */
lp2->l_text[doto+i] = c;
wp = wheadp; /* Update windows */
while (wp != NULL) {
if (wp->w_linep == lp1)
wp->w_linep = lp2;
if (wp->w_dotp == lp1) {
wp->w_dotp = lp2;
if (wp==curwp || wp->w_doto>doto)
/*NOSTRICT*/
wp->w_doto += n;
}
if (wp->w_markp == lp1) {
wp->w_markp = lp2;
if (wp->w_marko > doto)
/*NOSTRICT*/
wp->w_marko += n;
}
wp = wp->w_wndp;
}
return (TRUE);
}
/*
* Insert a newline into the buffer
* at the current location of dot in the current
* window. The funny ass-backwards way it does things
* is not a botch; it just makes the last line in
* the file not a special case. Return TRUE if everything
* works out and FALSE on error (memory allocation
* failure). The update of dot and mark is a bit
* easier then in the above case, because the split
* forces more updating.
*/
lnewline() {
register char *cp1;
register char *cp2;
register LINE *lp1;
register LINE *lp2;
register int doto;
register WINDOW *wp;
lchange(WFHARD);
lp1 = curwp->w_dotp; /* Get the address and */
doto = curwp->w_doto; /* offset of "." */
if ((lp2=lalloc((RSIZE) doto)) == NULL) /* New first half line */
return (FALSE);
cp1 = &lp1->l_text[0]; /* Shuffle text around */
cp2 = &lp2->l_text[0];
while (cp1 != &lp1->l_text[doto])
*cp2++ = *cp1++;
cp2 = &lp1->l_text[0];
while (cp1 != &lp1->l_text[lp1->l_used])
*cp2++ = *cp1++;
lp1->l_used -= doto;
lp2->l_bp = lp1->l_bp;
lp1->l_bp = lp2;
lp2->l_bp->l_fp = lp2;
lp2->l_fp = lp1;
wp = wheadp; /* Windows */
while (wp != NULL) {
if (wp->w_linep == lp1)
wp->w_linep = lp2;
if (wp->w_dotp == lp1) {
if (wp->w_doto < doto)
wp->w_dotp = lp2;
else
wp->w_doto -= doto;
}
if (wp->w_markp == lp1) {
if (wp->w_marko < doto)
wp->w_markp = lp2;
else
wp->w_marko -= doto;
}
wp = wp->w_wndp;
}
return (TRUE);
}
/*
* This function deletes "n" bytes,
* starting at dot. It understands how do deal
* with end of lines, etc. It returns TRUE if all
* of the characters were deleted, and FALSE if
* they were not (because dot ran into the end of
* the buffer. The "kflag" indicates either no insertion,
* or direction of insertion into the kill buffer.
*/
ldelete(n, kflag) RSIZE n; {
register char *cp1;
register char *cp2;
register LINE *dotp;
register int doto;
register RSIZE chunk;
register WINDOW *wp;
/*
* HACK - doesn't matter, and fixes back-over-nl bug for empty
* kill buffers.
*/
if (kused == kstart) kflag = KFORW;
while (n != 0) {
dotp = curwp->w_dotp;
doto = curwp->w_doto;
if (dotp == curbp->b_linep) /* Hit end of buffer. */
return (FALSE);
chunk = dotp->l_used-doto; /* Size of chunk. */
if (chunk > n)
chunk = n;
if (chunk == 0) { /* End of line, merge. */
lchange(WFHARD);
if (ldelnewline() == FALSE
|| (kflag!=KNONE && kinsert('\n', kflag)==FALSE))
return (FALSE);
--n;
continue;
}
lchange(WFEDIT);
cp1 = &dotp->l_text[doto]; /* Scrunch text. */
cp2 = cp1 + chunk;
if (kflag == KFORW) {
while (ksize - kused < chunk)
if (kgrow(FALSE) == FALSE) return FALSE;
bcopy(cp1, &(kbufp[kused]), (int) chunk);
kused += chunk;
} else if (kflag == KBACK) {
while (kstart < chunk)
if (kgrow(TRUE) == FALSE) return FALSE;
bcopy(cp1, &(kbufp[kstart-chunk]), (int) chunk);
kstart -= chunk;
} else if (kflag != KNONE) panic("broken ldelete call");
while (cp2 != &dotp->l_text[dotp->l_used])
*cp1++ = *cp2++;
dotp->l_used -= (int) chunk;
wp = wheadp; /* Fix windows */
while (wp != NULL) {
if (wp->w_dotp==dotp && wp->w_doto>=doto) {
/*NOSTRICT*/
wp->w_doto -= chunk;
if (wp->w_doto < doto)
wp->w_doto = doto;
}
if (wp->w_markp==dotp && wp->w_marko>=doto) {
/*NOSTRICT*/
wp->w_marko -= chunk;
if (wp->w_marko < doto)
wp->w_marko = doto;
}
wp = wp->w_wndp;
}
n -= chunk;
}
return (TRUE);
}
/*
* Delete a newline. Join the current line
* with the next line. If the next line is the magic
* header line always return TRUE; merging the last line
* with the header line can be thought of as always being a
* successful operation, even if nothing is done, and this makes
* the kill buffer work "right". Easy cases can be done by
* shuffling data around. Hard cases require that lines be moved
* about in memory. Return FALSE on error and TRUE if all
* looks ok.
*/
ldelnewline() {
register char *cp1;
register char *cp2;
register LINE *lp1;
register LINE *lp2;
register LINE *lp3;
register WINDOW *wp;
lp1 = curwp->w_dotp;
lp2 = lp1->l_fp;
if (lp2 == curbp->b_linep) { /* At the buffer end. */
if (lp1->l_used == 0) /* Blank line. */
lfree(lp1);
return (TRUE);
}
if (lp2->l_used <= lp1->l_size-lp1->l_used) {
cp1 = &lp1->l_text[lp1->l_used];
cp2 = &lp2->l_text[0];
while (cp2 != &lp2->l_text[lp2->l_used])
*cp1++ = *cp2++;
wp = wheadp;
while (wp != NULL) {
if (wp->w_linep == lp2)
wp->w_linep = lp1;
if (wp->w_dotp == lp2) {
wp->w_dotp = lp1;
wp->w_doto += lp1->l_used;
}
if (wp->w_markp == lp2) {
wp->w_markp = lp1;
wp->w_marko += lp1->l_used;
}
wp = wp->w_wndp;
}
lp1->l_used += lp2->l_used;
lp1->l_fp = lp2->l_fp;
lp2->l_fp->l_bp = lp1;
free((char *) lp2);
return (TRUE);
}
if ((lp3=lalloc((RSIZE) (lp1->l_used+lp2->l_used))) == NULL)
return (FALSE);
cp1 = &lp1->l_text[0];
cp2 = &lp3->l_text[0];
while (cp1 != &lp1->l_text[lp1->l_used])
*cp2++ = *cp1++;
cp1 = &lp2->l_text[0];
while (cp1 != &lp2->l_text[lp2->l_used])
*cp2++ = *cp1++;
lp1->l_bp->l_fp = lp3;
lp3->l_fp = lp2->l_fp;
lp2->l_fp->l_bp = lp3;
lp3->l_bp = lp1->l_bp;
wp = wheadp;
while (wp != NULL) {
if (wp->w_linep==lp1 || wp->w_linep==lp2)
wp->w_linep = lp3;
if (wp->w_dotp == lp1)
wp->w_dotp = lp3;
else if (wp->w_dotp == lp2) {
wp->w_dotp = lp3;
wp->w_doto += lp1->l_used;
}
if (wp->w_markp == lp1)
wp->w_markp = lp3;
else if (wp->w_markp == lp2) {
wp->w_markp = lp3;
wp->w_marko += lp1->l_used;
}
wp = wp->w_wndp;
}
free((char *) lp1);
free((char *) lp2);
return (TRUE);
}
/*
* Replace plen characters before dot with argument string.
* Control-J characters in st are interpreted as newlines.
* There is a casehack disable flag (normally it likes to match
* case of replacement to what was there).
*/
lreplace(plen, st, f)
register RSIZE plen; /* length to remove */
char *st; /* replacement string */
int f; /* case hack disable */
{
register RSIZE rlen; /* replacement length */
register int rtype; /* capitalization */
register int c; /* used for random characters */
register int doto; /* offset into line */
/*
* Find the capitalization of the word that was found.
* f says use exact case of replacement string (same thing that
* happens with lowercase found), so bypass check.
*/
/*NOSTRICT*/
(VOID) backchar(TRUE, (int) plen, KRANDOM);
rtype = _L;
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISUPPER(c)!=FALSE && f==FALSE) {
rtype = _U|_L;
if (curwp->w_doto+1 < llength(curwp->w_dotp)) {
c = lgetc(curwp->w_dotp, curwp->w_doto+1);
if (ISUPPER(c) != FALSE) {
rtype = _U;
}
}
}
/*
* make the string lengths match (either pad the line
* so that it will fit, or scrunch out the excess).
* be careful with dot's offset.
*/
rlen = strlen(st);
doto = curwp->w_doto;
if (plen > rlen)
(VOID) ldelete((RSIZE) (plen-rlen), KNONE);
else if (plen < rlen) {
if (linsert((RSIZE) (rlen-plen), ' ') == FALSE)
return (FALSE);
}
curwp->w_doto = doto;
/*
* do the replacement: If was capital, then place first
* char as if upper, and subsequent chars as if lower.
* If inserting upper, check replacement for case.
*/
while ((c = *st++&0xff) != '\0') {
if ((rtype&_U)!=0 && ISLOWER(c)!=0)
c = TOUPPER(c);
if (rtype == (_U|_L))
rtype = _L;
if (c == SEOL) {
if (curwp->w_doto == llength(curwp->w_dotp))
(VOID) forwchar(FALSE, 1, KRANDOM);
else {
if (ldelete((RSIZE) 1, KNONE) != FALSE)
(VOID) lnewline();
}
} else if (curwp->w_dotp == curbp->b_linep) {
(VOID) linsert((RSIZE) 1, c);
} else if (curwp->w_doto == llength(curwp->w_dotp)) {
if (ldelete((RSIZE) 1, KNONE) != FALSE)
(VOID) linsert((RSIZE) 1, c);
} else
lputc(curwp->w_dotp, curwp->w_doto++, c);
}
lchange(WFHARD);
return (TRUE);
}
/*
* Delete all of the text
* saved in the kill buffer. Called by commands
* when a new kill context is being created. The kill
* buffer array is released, just in case the buffer has
* grown to immense size. No errors.
*/
kdelete() {
if (kbufp != NULL) {
free((char *) kbufp);
kbufp = NULL;
kstart = kused = ksize = 0;
}
}
/*
* Insert a character to the kill buffer,
* enlarging the buffer if there isn't any room. Always
* grow the buffer in chunks, on the assumption that if you
* put something in the kill buffer you are going to put
* more stuff there too later. Return TRUE if all is
* well, and FALSE on errors. Print a message on
* errors. Dir says whether to put it at back or front.
*/
kinsert(c, dir) {
if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
return FALSE;
if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE)
return FALSE;
if (dir == KFORW) kbufp[kused++] = c;
else if (dir == KBACK) kbufp[--kstart] = c;
else panic("broken kinsert call"); /* Oh shit! */
return (TRUE);
}
/*
* kgrow - just get more kill buffer for the callee. back is true if
* we are trying to get space at the beginning of the kill buffer.
*/
kgrow(back) {
register int nstart;
register char *nbufp;
if ((nbufp=malloc((int)(ksize+KBLOCK))) == NULL) {
ewprintf("Can't get %ld bytes", (long)(ksize+KBLOCK));
return (FALSE);
}
nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4) ;
bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int) (kused-kstart));
if (kbufp != NULL)
free((char *) kbufp);
kbufp = nbufp;
ksize += KBLOCK;
kused = kused - kstart + nstart;
kstart = nstart;
return TRUE;
}
/*
* This function gets characters from
* the kill buffer. If the character index "n" is
* off the end, it returns "-1". This lets the caller
* just scan along until it gets a "-1" back.
*/
kremove(n) {
if (n < 0 || n + kstart >= kused)
return (-1);
return (kbufp[n + kstart] & 0xFF);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'main.c'
then
echo shar: will not over-write existing file "'main.c'"
else
cat << \SHAR_EOF > 'main.c'
/*
* Mainline, macro commands.
*/
#include "def.h"
int thisflag; /* Flags, this command */
int lastflag; /* Flags, last command */
int curgoal; /* Goal column */
BUFFER *curbp; /* Current buffer */
WINDOW *curwp; /* Current window */
BUFFER *bheadp; /* BUFFER listhead */
WINDOW *wheadp = (WINDOW *)NULL; /* WINDOW listhead */
KEY kbdm[NKBDM] = {(KCTLX|')')}; /* Macro */
KEY *kbdmip; /* Input for above */
KEY *kbdmop; /* Output for above */
char pat[NPAT]; /* Pattern */
#ifdef HASH
SYMBOL *symbol[NSHASH]; /* Symbol table listhead. */
#else
/* should really be a *symbol, but don't want to break the hash code yet */
SYMBOL *symbol[1];
#endif
SYMBOL *binding[NKEYS]; /* Key bindings. */
#ifdef DPROMPT
extern char prompt[], *promptp; /* delayed prompting */
#endif
main(argc, argv) char *argv[]; {
register KEY c;
register int f;
register int n;
register int mflag;
#ifdef STARTUP
char *sfile, *startupfile();
#endif
char bname[NBUFN];
#ifdef SYSINIT
SYSINIT; /* system dependent. */
#endif
vtinit(); /* Virtual terminal. */
edinit(); /* Buffers, windows. */
keymapinit(); /* Symbols, bindings. */
/* doing update() before reading files causes the error messages from
* the file I/O show up on the screen. (and also an extra display
* of the mode line if there are files specified on the command line.)
*/
update();
#ifdef STARTUP /* User startup file. */
if ((sfile = startupfile()) != NULL)
(VOID) load(sfile);
#endif
while (--argc > 0) {
makename(bname, *++argv);
curbp = bfind(bname, TRUE);
(VOID) showbuffer(curbp, curwp, 0);
(VOID) readin(*argv);
}
lastflag = 0; /* Fake last flags. */
loop:
#ifdef DPROMPT
*(promptp = prompt) = '\0';
if(epresf == KPROMPT) eerase();
#endif
update(); /* Fix up the screen. */
c = getkey(KPROMPT);
if (epresf == TRUE) {
eerase();
update();
}
f = FALSE;
n = 1;
if (((KMETA|'0') <= c && c <= (KMETA|'9')) || c == (KMETA|'-')) {
f = TRUE;
c = c & ~KMETA;
} else if (c == (KCTRL|'U')) {
f = TRUE;
n = 4;
while ((c=getkey(KNOMAC | KPROMPT)) == (KCTRL|'U'))
n *= 4;
}
if (f == TRUE) {
if ((c>='0' && c<='9') || c=='-') {
if (c == '-') {
n = 0;
mflag = TRUE;
} else {
n = ((int) c) - '0';
mflag = FALSE;
}
while ((c=getkey(KNOMAC | KPROMPT))>='0' && c<='9')
n = 10*n + ((int) c) - '0';
if (mflag != FALSE)
n = -n;
}
}
if (kbdmip != NULL) { /* Terminate macros. */
if (c!=(KCTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
(VOID) ctrlg(FALSE, 0, KRANDOM);
goto loop;
}
if (f != FALSE) {
kbdmip[-1] = (KEY) (KCTRL|'U');/* overwrite ESC */
*kbdmip++ = (KEY) n;
*kbdmip++ = (KEY) c;
}
}
switch (execute(c, f, n)) { /* Do it. */
case TRUE: break;
case ABORT:
ewprintf("Quit"); /* and fall through */
case FALSE: default:
ttbeep();
if (kbdmip != NULL) {
kbdm[0] = (KEY) (KCTLX|')');
kbdmip = NULL;
}
}
goto loop;
}
/*
* Command execution. Look up the binding in the the
* binding array, and do what it says. Return a very bad status
* if there is no binding, or if the symbol has a type that
* is not usable (there is no way to get this into a symbol table
* entry now). Also fiddle with the flags.
*/
execute(c, f, n) KEY c; {
register SYMBOL *sp;
register int status;
if ((sp=binding[c]) != NULL) {
thisflag = 0;
status = (*sp->s_funcp)(f, n, c);
lastflag = thisflag;
return (status);
}
lastflag = 0;
return (FALSE);
}
/*
* Initialize all of the buffers
* and windows. The buffer name is passed down as
* an argument, because the main routine may have been
* told to read in a file by default, and we want the
* buffer name to be right.
*/
edinit() {
register BUFFER *bp;
register WINDOW *wp;
bheadp = NULL;
bp = bfind("*scratch*", TRUE); /* Text buffer. */
wp = (WINDOW *)malloc(sizeof(WINDOW)); /* Initial window. */
if (bp==NULL || wp==NULL) panic("edinit");
curbp = bp; /* Current ones. */
wheadp = wp;
curwp = wp;
wp->w_wndp = NULL; /* Initialize window. */
wp->w_bufp = bp;
bp->b_nwnd = 1; /* Displayed. */
wp->w_linep = bp->b_linep;
wp->w_dotp = bp->b_linep;
wp->w_doto = 0;
wp->w_markp = NULL;
wp->w_marko = 0;
wp->w_toprow = 0;
wp->w_ntrows = nrow-2; /* 2 = mode, echo. */
wp->w_force = 0;
wp->w_flag = WFMODE|WFHARD; /* Full. */
}
/*
* Quit command. If an argument, always
* quit. Otherwise confirm if a buffer has been
* changed and not written out. Normally bound
* to "C-X C-C".
*/
/*ARGSUSED*/
quit(f, n, k) {
register int s;
if ((s = anycb(FALSE)) == ABORT) return ABORT;
if (s == FALSE
|| eyesno("Some modified buffers exist, really exit") == TRUE) {
vttidy();
exit(GOOD);
}
return TRUE;
}
/*
* Begin a keyboard macro.
* Error if not at the top level
* in keyboard processing. Set up
* variables and return.
*/
/*ARGSUSED*/
ctlxlp(f, n, k) {
if (kbdmip!=NULL || kbdmop!=NULL) {
ewprintf("Already defining kbd macro!");
return (FALSE);
}
ewprintf("Defining kbd macro...");
kbdmip = &kbdm[0];
return (TRUE);
}
/*
* End keyboard macro. Check for
* the same limit conditions as the
* above routine. Set up the variables
* and return to the caller.
*/
/*ARGSUSED*/
ctlxrp(f, n, k) {
if (kbdmip == NULL) {
ewprintf("Not defining kbd macro.");
return (FALSE);
}
ewprintf("Keyboard macro defined");
kbdmip = NULL;
return (TRUE);
}
/*
* Execute a macro.
* The command argument is the
* number of times to loop. Quit as
* soon as a command gets an error.
* Return TRUE if all ok, else
* FALSE.
*/
/*ARGSUSED*/
ctlxe(f, n, k) {
register KEY c;
register int af;
register int an;
register int s;
if (kbdmip!=NULL || kbdmop!=NULL) {
ewprintf("Not now");
return (FALSE);
}
if (n < 0)
return (TRUE);
do {
kbdmop = &kbdm[0];
do {
af = FALSE;
an = 1;
if ((c = *kbdmop++) == (KCTRL|'U')) {
af = TRUE;
an = (int) *kbdmop++;
c = *kbdmop++;
}
s = TRUE;
} while (c!=(KCTLX|')') && (s=execute(c, af, an))==TRUE);
kbdmop = NULL;
} while (s==TRUE && --n);
return (s);
}
/*
* User abort. Should be called by any input routine that sees a C-g
* to abort whatever C-g is aborting these days. Currently does
* nothing.
*/
/*ARGSUSED*/
ctrlg(f, n, k) {
return (ABORT);
}
/*
* Display the version. All this does
* is copy the version string onto the echo line.
*/
/*ARGSUSED*/
showversion(f, n, k) {
ewprintf(version);
return TRUE ;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'paragraph.c'
then
echo shar: will not over-write existing file "'paragraph.c'"
else
cat << \SHAR_EOF > 'paragraph.c'
/*
* Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6
* and GNU-ified by mwm at ucbvax. Several bug fixes by blarson at usc-oberon.
*/
#include "def.h"
static int fillcol = 70 ;
#define MAXWORD 256
/*
* go back to the begining of the current paragraph
* here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
* combination to delimit the begining of a paragraph
*/
/*ARGSUSED*/
gotobop(f, n, k) {
register int suc; /* success of last backchar */
if (n < 0) /* the other way...*/
return(gotoeop(f, -n, KRANDOM));
while (n-- > 0) { /* for each one asked for */
/* first scan back until we are in a word */
suc = backchar(FALSE, 1, KRANDOM);
while (!inword() && suc)
suc = backchar(FALSE, 1, KRANDOM);
curwp->w_doto = 0; /* and go to the B-O-Line */
/* and scan back until we hit a <NL><SP> <NL><TAB> or <NL><NL> */
while (lback(curwp->w_dotp) != curbp->b_linep)
if (llength(lback(curwp->w_dotp))
&& lgetc(curwp->w_dotp,0) != ' '
&& lgetc(curwp->w_dotp,0) != '\t')
curwp->w_dotp = lback(curwp->w_dotp);
else
break;
}
curwp->w_flag |= WFMOVE; /* force screen update */
return TRUE;
}
/*
* go forword to the end of the current paragraph
* here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
* combination to delimit the begining of a paragraph
*/
/*ARGSUSED*/
gotoeop(f, n, k) {
register int suc; /* success of last backchar */
if (n < 0) /* the other way...*/
return(gotobop(f, -n, KRANDOM));
while (n-- > 0) { /* for each one asked for */
/* Find the first word on/after the current line */
curwp->w_doto = 0;
suc = forwchar(FALSE, 1, KRANDOM);
while (!inword() && suc)
suc = forwchar(FALSE, 1, KRANDOM);
curwp->w_doto = 0;
if (curwp->w_dotp == curbp->b_linep)
break; /* check for eob */
curwp->w_dotp = lforw(curwp->w_dotp);
/* and scan forword until we hit a <NL><SP> or ... */
while (curwp->w_dotp != curbp->b_linep) {
if (llength(curwp->w_dotp)
&& lgetc(curwp->w_dotp,0) != ' '
&& lgetc(curwp->w_dotp,0) != '\t')
curwp->w_dotp = lforw(curwp->w_dotp);
else
break;
}
}
curwp->w_flag |= WFMOVE; /* force screen update */
return TRUE;
}
/*
* Fill the current paragraph according to the current
* fill column
*/
/*ARGSUSED*/
fillpara(f, n, k) {
register int c; /* current char durring scan */
register int wordlen; /* length of current word */
register int clength; /* position on line during fill */
register int i; /* index during word copy */
register int eopflag; /* Are we at the End-Of-Paragraph? */
int firstflag; /* first word? (needs no space) */
int newlength; /* tentative new line length */
int eolflag; /* was at end of line */
LINE *eopline; /* pointer to line just past EOP */
char wbuf[MAXWORD]; /* buffer for current word */
/* record the pointer to the line just past the EOP */
(VOID) gotoeop(FALSE, 1, KRANDOM);
eopline = curwp->w_dotp;
/* and back top the begining of the paragraph */
(VOID) gotobop(FALSE, 1, KRANDOM);
/* initialize various info */
i = TRUE;
while (i == TRUE && !inword())
i = forwchar(FALSE, 1, KRANDOM);
clength = curwp->w_doto;
wordlen = 0;
/* scan through lines, filling words */
firstflag = TRUE;
eopflag = FALSE;
while (!eopflag) {
/* get the next character in the paragraph */
if (eolflag=(curwp->w_doto == llength(curwp->w_dotp))) {
c = ' ';
if (lforw(curwp->w_dotp) == eopline)
eopflag = TRUE;
} else
c = lgetc(curwp->w_dotp, curwp->w_doto);
/* and then delete it */
if (ldelete((RSIZE) 1, KNONE) == FALSE) return FALSE ;
/* if not a separator, just add it in */
if (c != ' ' && c != '\t') {
if (wordlen < MAXWORD - 1)
wbuf[wordlen++] = c;
else {
/* You loose chars beyond MAXWORD if the word
* is to long. I'm to lazy to fix it now; it
* just silently truncated the word before, so
* I get to feel smug.
*/
ewprintf("Word too long!");
}
} else if (wordlen) {
/* calculate tenatitive new length with word added */
newlength = clength + 1 + wordlen;
/* if at end of line or at doublespace and previous
* character was one of '.','?','!' doublespace here.
*/
if((eolflag || curwp->w_doto==llength(curwp->w_dotp)
|| (c=lgetc(curwp->w_dotp,curwp->w_doto))==' '
|| c=='\t')
&& ISEOSP(wbuf[wordlen-1])
&& wordlen<MAXWORD-1)
wbuf[wordlen++] = ' ';
/* at a word break with a word waiting */
if (newlength <= fillcol) {
/* add word to current line */
if (!firstflag) {
(VOID) linsert((RSIZE) 1, ' ');
++clength;
}
firstflag = FALSE;
} else {
if(curwp->w_doto > 0 &&
lgetc(curwp->w_dotp,curwp->w_doto-1)==' ') {
curwp->w_doto -= 1;
(VOID) ldelete((RSIZE) 1, KNONE);
}
/* start a new line */
(VOID) lnewline();
clength = 0;
}
/* and add the word in in either case */
for (i=0; i<wordlen; i++) {
(VOID) linsert((RSIZE) 1, wbuf[i]);
++clength;
}
wordlen = 0;
}
}
/* and add a last newline for the end of our new paragraph */
(VOID) lnewline();
/* we realy should wind up where we started, (which is hard to keep
* track of) but I think the end of the last line is better than the
* begining of the blank line. */
(VOID) backchar(FALSE, 1, KRANDOM);
return TRUE;
}
/* delete n paragraphs starting with the current one */
/*ARGSUSED*/
killpara(f, n, k) {
register int status; /* returned status of functions */
while (n--) { /* for each paragraph to delete */
/* mark out the end and begining of the para to delete */
(VOID) gotoeop(FALSE, 1, KRANDOM);
/* set the mark here */
curwp->w_markp = curwp->w_dotp;
curwp->w_marko = curwp->w_doto;
/* go to the begining of the paragraph */
(VOID) gotobop(FALSE, 1, KRANDOM);
curwp->w_doto = 0; /* force us to the begining of line */
/* and delete it */
if ((status = killregion(FALSE, 1, KRANDOM)) != TRUE)
return(status);
/* and clean up the 2 extra lines */
(VOID) ldelete((RSIZE) 1, KFORW);
}
return(TRUE);
}
/*
* check to see if we're past fillcol, and if so,
* justify this line. As a last step, justify the line.
*/
/*ARGSUSED*/
fillword(f, n, k) {
register char c;
register int col, i, nce;
for (i = col = 0; col <= fillcol; ++i, ++col) {
if (i == curwp->w_doto) return selfinsert(f, n, k) ;
c = lgetc(curwp->w_dotp, i);
if (c == '\t') col |= 0x07;
else if (ISCTRL(c) != FALSE) ++col;
}
if (curwp->w_doto != llength(curwp->w_dotp)) {
(VOID) selfinsert(f, n, k);
nce = llength(curwp->w_dotp) - curwp->w_doto;
} else nce = 0;
curwp->w_doto = i;
if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
do {
(VOID) backchar(FALSE, 1, KRANDOM);
} while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' '
&& c != '\t' && curwp->w_doto > 0);
if (curwp->w_doto == 0)
do {
(VOID) forwchar(FALSE, 1, KRANDOM);
} while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' '
&& c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
(VOID) delwhite(FALSE, 1, KRANDOM);
(VOID) backdel(FALSE, 1, KRANDOM);
(VOID) lnewline();
curwp->w_doto = llength(curwp->w_dotp) - nce;
curwp->w_flag |= WFMOVE;
if (nce == 0 && curwp->w_doto != 0) return fillword(f, n, k);
return TRUE;
}
/* Set fill column to n. */
/*ARGSUSED*/
setfillcol(f, n, k) {
extern int getcolpos() ;
fillcol = ((f == FALSE) ? getcolpos() : n);
if (kbdmop == NULL) ewprintf("Fill column set to %d", fillcol);
return(TRUE);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'random.c'
then
echo shar: will not over-write existing file "'random.c'"
else
cat << \SHAR_EOF > 'random.c'
/*
* Assorted commands.
* The file contains the command
* processors for a large assortment of unrelated
* commands. The only thing they have in common is
* that they are all command processors.
*/
#include "def.h"
/*
* Display a bunch of useful information about
* the current location of dot. The character under the
* cursor (in octal), the current line, row, and column, and
* approximate position of the cursor in the file (as a percentage)
* is displayed. The column position assumes an infinite position
* display; it does not truncate just because the screen does.
* This is normally bound to "C-X =".
*/
/*ARGSUSED*/
showcpos(f, n, k) {
register LINE *clp;
register long nchar;
long cchar;
register int nline, row;
int cline, cbyte; /* Current line/char/byte */
int ratio;
KEY keychar();
clp = lforw(curbp->b_linep); /* Collect the data. */
nchar = 0;
nline = 0;
for (;;) {
++nline; /* Count this line */
if (clp == curwp->w_dotp) {
cline = nline; /* Mark line */
cchar = nchar + curwp->w_doto;
if (curwp->w_doto == llength(clp))
cbyte = '\n';
else
cbyte = lgetc(clp, curwp->w_doto);
}
nchar += llength(clp) + 1; /* Now count the chars */
if (clp == curbp->b_linep) break ;
clp = lforw(clp);
}
row = curwp->w_toprow; /* Determine row. */
clp = curwp->w_linep;
while (clp!=curbp->b_linep && clp!=curwp->w_dotp) {
++row;
clp = lforw(clp);
}
++row; /* Convert to origin 1. */
/*NOSTRICT*/
/* nchar can't be zero (because of the "bonus" \n at end of file) */
ratio = (100L*cchar) / nchar;
ewprintf("Char: %c (0%o) point=%ld(%d%%) line=%d row=%d col=%d",
(int) keychar(cbyte, FALSE), cbyte, cchar, ratio, cline, row,
getcolpos());
return (TRUE);
}
getcolpos() {
register int col, i, c;
col = 0; /* Determine column. */
for (i=0; i<curwp->w_doto; ++i) {
c = lgetc(curwp->w_dotp, i);
if (c == '\t')
col |= 0x07;
else if (ISCTRL(c) != FALSE)
++col;
++col;
}
return col + 1; /* Convert to origin 1. */
}
/*
* Twiddle the two characters on either side of
* dot. If dot is at the end of the line twiddle the
* two characters before it. Return with an error if dot
* is at the beginning of line; it seems to be a bit
* pointless to make this work. This fixes up a very
* common typo with a single stroke. Normally bound
* to "C-T". This always works within a line, so
* "WFEDIT" is good enough.
*/
/*ARGSUSED*/
twiddle(f, n, k) {
register LINE *dotp;
register int doto, odoto;
register int cl;
register int cr;
dotp = curwp->w_dotp;
odoto = doto = curwp->w_doto;
if (doto==llength(dotp) && --doto<0)
return (FALSE);
cr = lgetc(dotp, doto);
if (--doto < 0)
return (FALSE);
cl = lgetc(dotp, doto);
lputc(dotp, doto+0, cr);
lputc(dotp, doto+1, cl);
if (odoto != llength(dotp)) ++(curwp->w_doto);
lchange(WFEDIT);
return (TRUE);
}
/*
* Quote the next character, and
* insert it into the buffer. All the characters
* are taken literally, with the exception of the newline,
* which always has its line splitting meaning. The character
* is always read, even if it is inserted 0 times, for
* regularity.
*/
/*ARGSUSED*/
quote(f, n, k) {
register int s;
register KEY c;
if (kbdmop != NULL) c = (KEY) *kbdmop++;
else c = getkey(KQUOTE);
if (n < 0)
return (FALSE);
if (n == 0)
return (TRUE);
if (c == '\n') {
do {
s = lnewline();
} while (s==TRUE && --n);
return (s);
}
return (linsert((RSIZE) n, (char) c));
}
/*
* Ordinary text characters are bound to this function,
* which inserts them into the buffer. Characters marked as control
* characters (using the CTRL flag) may be remapped to their ASCII
* equivalent. This makes TAB (C-I) work right, and also makes the
* world look reasonable if a control character is bound to this
* this routine by hand. Any META or CTLX flags on the character
* are discarded. This is the only routine that actually looks
* the the "k" argument.
*/
/*ARGSUSED*/
selfinsert(f, n, k) {
register int c;
if (n < 0)
return (FALSE);
if (n == 0)
return (TRUE);
c = k & KCHAR;
if ((k&KCTRL)!=0 && c>='@' && c<='_') /* ASCII-ify. */
c -= '@';
return (linsert((RSIZE) n, c));
}
/*
* Open up some blank space. The basic plan
* is to insert a bunch of newlines, and then back
* up over them. Everything is done by the subcommand
* procerssors. They even handle the looping. Normally
* this is bound to "C-O".
*/
/*ARGSUSED*/
openline(f, n, k) {
register int i;
register int s;
if (n < 0)
return (FALSE);
if (n == 0)
return (TRUE);
i = n; /* Insert newlines. */
do {
s = lnewline();
} while (s==TRUE && --i);
if (s == TRUE) /* Then back up overtop */
s = backchar(f, n, KRANDOM); /* of them all. */
return (s);
}
/*
* Insert a newline.
* If you are at the end of the line and the
* next line is a blank line, just move into the
* blank line. This makes "C-O" and "C-X C-O" work
* nicely, and reduces the ammount of screen
* update that has to be done. This would not be
* as critical if screen update were a lot
* more efficient.
*/
/*ARGSUSED*/
newline(f, n, k) {
register LINE *lp;
register int s;
if (n < 0)
return (FALSE);
while (n--) {
lp = curwp->w_dotp;
if (llength(lp) == curwp->w_doto
&& lp != curbp->b_linep
&& llength(lforw(lp)) == 0) {
if ((s=forwchar(FALSE, 1, KRANDOM)) != TRUE)
return (s);
} else if ((s=lnewline()) != TRUE)
return (s);
}
return (TRUE);
}
/*
* Delete blank lines around dot.
* What this command does depends if dot is
* sitting on a blank line. If dot is sitting on a
* blank line, this command deletes all the blank lines
* above and below the current line. If it is sitting
* on a non blank line then it deletes all of the
* blank lines after the line. Normally this command
* is bound to "C-X C-O". Any argument is ignored.
*/
/*ARGSUSED*/
deblank(f, n, k) {
register LINE *lp1;
register LINE *lp2;
register RSIZE nld;
lp1 = curwp->w_dotp;
while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
lp1 = lp2;
lp2 = lp1;
nld = (RSIZE) 0;
while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
++nld;
if (nld == 0)
return (TRUE);
curwp->w_dotp = lforw(lp1);
curwp->w_doto = 0;
return (ldelete((RSIZE)nld, KNONE));
}
/*
* Delete any whitespace around dot, then insert a space.
*/
/*ARGSUSED*/
delwhite(f, n, k) {
register int col, c, s;
col = curwp->w_doto;
while ((c = lgetc(curwp->w_dotp, col)) == ' ' || c == '\t')
++col;
do
if ((s = backchar(FALSE, 1, KRANDOM)) == FALSE) break;
while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t') ;
if (s == TRUE) (VOID) forwchar(FALSE, 1, KRANDOM);
(VOID) ldelete((RSIZE)(col - curwp->w_doto), KNONE);
return linsert((RSIZE) 1, ' ');
}
/*
* Insert a newline, then enough
* tabs and spaces to duplicate the indentation
* of the previous line. Assumes tabs are every eight
* characters. Quite simple. Figure out the indentation
* of the current line. Insert a newline by calling
* the standard routine. Insert the indentation by
* inserting the right number of tabs and spaces.
* Return TRUE if all ok. Return FALSE if one
* of the subcomands failed. Normally bound
* to "C-J".
*/
/*ARGSUSED*/
indent(f, n, k) {
register int nicol;
register int c;
register int i;
if (n < 0)
return (FALSE);
while (n--) {
nicol = 0;
for (i=0; i<llength(curwp->w_dotp); ++i) {
c = lgetc(curwp->w_dotp, i);
if (c!=' ' && c!='\t')
break;
if (c == '\t')
nicol |= 0x07;
++nicol;
}
if (lnewline() == FALSE
|| ((i=nicol/8)!=0 && linsert((RSIZE) i, '\t')==FALSE)
|| ((i=nicol%8)!=0 && linsert((RSIZE) i, ' ')==FALSE))
return (FALSE);
}
return (TRUE);
}
/*
* Delete forward. This is real
* easy, because the basic delete routine does
* all of the work. Watches for negative arguments,
* and does the right thing. If any argument is
* present, it kills rather than deletes, to prevent
* loss of text if typed with a big argument.
* Normally bound to "C-D".
*/
/*ARGSUSED*/
forwdel(f, n, k) {
if (n < 0)
return (backdel(f, -n, KRANDOM));
if (f != FALSE) { /* Really a kill. */
if ((lastflag&CFKILL) == 0)
kdelete();
thisflag |= CFKILL;
}
return (ldelete((RSIZE) n, f ? KFORW : KNONE));
}
/*
* Delete backwards. This is quite easy too,
* because it's all done with other functions. Just
* move the cursor back, and delete forwards.
* Like delete forward, this actually does a kill
* if presented with an argument.
*/
/*ARGSUSED*/
backdel(f, n, k) {
register int s;
if (n < 0)
return (forwdel(f, -n, KRANDOM));
if (f != FALSE) { /* Really a kill. */
if ((lastflag&CFKILL) == 0)
kdelete();
thisflag |= CFKILL;
}
if ((s=backchar(f, n, KRANDOM)) == TRUE)
s = ldelete((RSIZE) n, f ? KFORW : KNONE);
return (s);
}
/*
* Kill line. If called without an argument,
* it kills from dot to the end of the line, unless it
* is at the end of the line, when it kills the newline.
* If called with an argument of 0, it kills from the
* start of the line to dot. If called with a positive
* argument, it kills from dot forward over that number
* of newlines. If called with a negative argument it
* kills any text before dot on the current line,
* then it kills back abs(arg) lines.
*/
/*ARGSUSED*/
killline(f, n, k) {
register RSIZE chunk;
register LINE *nextp;
register int i, c;
if ((lastflag&CFKILL) == 0) /* Clear kill buffer if */
kdelete(); /* last wasn't a kill. */
thisflag |= CFKILL;
if (f == FALSE) {
for (i = curwp->w_doto; i < llength(curwp->w_dotp); ++i)
if ((c = lgetc(curwp->w_dotp, i)) != ' ' && c != '\t')
break;
if (i == llength(curwp->w_dotp))
chunk = llength(curwp->w_dotp)-curwp->w_doto + 1;
else {
chunk = llength(curwp->w_dotp)-curwp->w_doto;
if (chunk == 0)
chunk = 1;
}
} else if (n > 0) {
chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
nextp = lforw(curwp->w_dotp);
i = n;
while (--i) {
if (nextp == curbp->b_linep)
break;
chunk += llength(nextp)+1;
nextp = lforw(nextp);
}
} else { /* n <= 0 */
chunk = curwp->w_doto;
curwp->w_doto = 0;
i = n;
while (i++) {
if (lback(curwp->w_dotp) == curbp->b_linep)
break;
curwp->w_dotp = lback(curwp->w_dotp);
curwp->w_flag |= WFMOVE;
chunk += llength(curwp->w_dotp)+1;
}
}
/*
* KFORW here is a bug. Should be KBACK/KFORW, but we need to
* rewrite the ldelete code (later)?
*/
return (ldelete(chunk, KFORW));
}
/*
* Yank text back from the kill buffer. This
* is really easy. All of the work is done by the
* standard insert routines. All you do is run the loop,
* and check for errors. The blank
* lines are inserted with a call to "newline"
* instead of a call to "lnewline" so that the magic
* stuff that happens when you type a carriage
* return also happens when a carriage return is
* yanked back from the kill buffer.
* An attempt has been made to fix the cosmetic bug
* associated with a yank when dot is on the top line of
* the window (nothing moves, because all of the new
* text landed off screen).
*/
/*ARGSUSED*/
yank(f, n, k) {
register int c;
register int i;
register LINE *lp;
register int nline;
if (n < 0)
return (FALSE);
nline = 0; /* Newline counting. */
while (n--) {
isetmark(); /* mark around last yank */
i = 0;
while ((c=kremove(i)) >= 0) {
if (c == '\n') {
if (newline(FALSE, 1, KRANDOM) == FALSE)
return (FALSE);
++nline;
} else {
if (linsert((RSIZE) 1, c) == FALSE)
return (FALSE);
}
++i;
}
}
lp = curwp->w_linep; /* Cosmetic adjustment */
if (curwp->w_dotp == lp) { /* if offscreen insert. */
while (nline-- && lback(lp)!=curbp->b_linep)
lp = lback(lp);
curwp->w_linep = lp; /* Adjust framing. */
curwp->w_flag |= WFHARD;
}
return (TRUE);
}
/*
* Commands to toggle the four modes. Without an argument, sets the
* mode on, with an argument, sets the mode off.
*/
/*ARGSUSED*/
bsmapmode(f, n, k) {
if (f == FALSE) mode |= MBSMAP;
else mode &= ~MBSMAP;
upmodes((BUFFER *) NULL);
return TRUE;
}
/*ARGSUSED*/
flowmode(f, n, k) {
if (f == FALSE) mode |= MFLOW;
else mode &= ~MFLOW;
upmodes((BUFFER *) NULL);
return TRUE;
}
/*ARGSUSED*/
indentmode(f, n, k) {
if (f == FALSE) {
mode |= MINDENT;
if ((binding[KCTRL|'M'] = symlookup("newline-and-indent"))
== NULL)
panic("no newline-and-indent in indentmode");
if ((binding[KCTRL|'J'] = symlookup("insert-newline")) == NULL)
panic("no insert-newline in indentmode");
} else {
mode &= ~MINDENT;
if ((binding[KCTRL|'M'] = symlookup("insert-newline")) == NULL)
panic("no insert-newline in indentmode");
if ((binding[KCTRL|'J'] = symlookup("newline-and-indent"))
== NULL)
panic("no newline-and-indent in indentmode");
}
upmodes((BUFFER *) NULL);
return TRUE;
}
/*ARGSUSED*/
fillmode(f, n, k) {
if (f == FALSE) {
mode |= MFILL;
if ((binding[' '] = symlookup("insert-with-wrap")) == NULL)
panic("no insert-with-wrap in fillmode");
} else {
mode &= ~MFILL;
if ((binding[' '] = symlookup("self-insert-command")) == NULL)
panic("no self-insert-command in fillmode");
}
upmodes((BUFFER *) NULL);
return TRUE;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'region.c'
then
echo shar: will not over-write existing file "'region.c'"
else
cat << \SHAR_EOF > 'region.c'
/*
* Region based commands.
* The routines in this file
* deal with the region, that magic space
* between "." and mark. Some functions are
* commands. Some functions are just for
* internal use.
*/
#include "def.h"
/*
* Kill the region. Ask "getregion"
* to figure out the bounds of the region.
* Move "." to the start, and kill the characters.
*/
/*ARGSUSED*/
killregion(f, n, k) {
register int s;
REGION region;
if ((s=getregion(®ion)) != TRUE)
return (s);
if ((lastflag&CFKILL) == 0) /* This is a kill type */
kdelete(); /* command, so do magic */
thisflag |= CFKILL; /* kill buffer stuff. */
curwp->w_dotp = region.r_linep;
curwp->w_doto = region.r_offset;
return (ldelete(region.r_size, KFORW));
}
/*
* Copy all of the characters in the
* region to the kill buffer. Don't move dot
* at all. This is a bit like a kill region followed
* by a yank.
*/
/*ARGSUSED*/
copyregion(f, n, k) {
register LINE *linep;
register int loffs;
register int s;
REGION region;
if ((s=getregion(®ion)) != TRUE)
return (s);
if ((lastflag&CFKILL) == 0) /* Kill type command. */
kdelete();
thisflag |= CFKILL;
linep = region.r_linep; /* Current line. */
loffs = region.r_offset; /* Current offset. */
while (region.r_size--) {
if (loffs == llength(linep)) { /* End of line. */
if ((s=kinsert('\n', KFORW)) != TRUE)
return (s);
linep = lforw(linep);
loffs = 0;
} else { /* Middle of line. */
if ((s=kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
return (s);
++loffs;
}
}
return (TRUE);
}
/*
* Lower case region. Zap all of the upper
* case characters in the region to lower case. Use
* the region code to set the limits. Scan the buffer,
* doing the changes. Call "lchange" to ensure that
* redisplay is done in all buffers.
*/
/*ARGSUSED*/
lowerregion(f, n, k) {
register LINE *linep;
register int loffs;
register int c;
register int s;
REGION region;
if ((s=getregion(®ion)) != TRUE)
return (s);
lchange(WFHARD);
linep = region.r_linep;
loffs = region.r_offset;
while (region.r_size--) {
if (loffs == llength(linep)) {
linep = lforw(linep);
loffs = 0;
} else {
c = lgetc(linep, loffs);
if (ISUPPER(c) != FALSE)
lputc(linep, loffs, TOLOWER(c));
++loffs;
}
}
return (TRUE);
}
/*
* Upper case region. Zap all of the lower
* case characters in the region to upper case. Use
* the region code to set the limits. Scan the buffer,
* doing the changes. Call "lchange" to ensure that
* redisplay is done in all buffers.
*/
/*ARGSUSED*/
upperregion(f, n, k) {
register LINE *linep;
register int loffs;
register int c;
register int s;
REGION region;
if ((s=getregion(®ion)) != TRUE)
return (s);
lchange(WFHARD);
linep = region.r_linep;
loffs = region.r_offset;
while (region.r_size--) {
if (loffs == llength(linep)) {
linep = lforw(linep);
loffs = 0;
} else {
c = lgetc(linep, loffs);
if (ISLOWER(c) != FALSE)
lputc(linep, loffs, TOUPPER(c));
++loffs;
}
}
return (TRUE);
}
/*
* This routine figures out the bound of the region
* in the current window, and stores the results into the fields
* of the REGION structure. Dot and mark are usually close together,
* but I don't know the order, so I scan outward from dot, in both
* directions, looking for mark. The size is kept in a long. At the
* end, after the size is figured out, it is assigned to the size
* field of the region structure. If this assignment loses any bits,
* then we print an error. This is "type independent" overflow
* checking. All of the callers of this routine should be ready to
* get an ABORT status, because I might add a "if regions is big,
* ask before clobberring" flag.
*/
getregion(rp) register REGION *rp; {
register LINE *flp;
register LINE *blp;
register long fsize; /* Long now. */
register long bsize;
if (curwp->w_markp == NULL) {
ewprintf("No mark set in this window");
return (FALSE);
}
if (curwp->w_dotp == curwp->w_markp) { /* "r_size" always ok. */
rp->r_linep = curwp->w_dotp;
if (curwp->w_doto < curwp->w_marko) {
rp->r_offset = curwp->w_doto;
rp->r_size = (RSIZE) (curwp->w_marko-curwp->w_doto);
} else {
rp->r_offset = curwp->w_marko;
rp->r_size = (RSIZE) (curwp->w_doto-curwp->w_marko);
}
return (TRUE);
}
blp = curwp->w_dotp; /* Get region size. */
flp = curwp->w_dotp;
bsize = curwp->w_doto;
fsize = llength(flp)-curwp->w_doto+1;
while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
if (flp != curbp->b_linep) {
flp = lforw(flp);
if (flp == curwp->w_markp) {
rp->r_linep = curwp->w_dotp;
rp->r_offset = curwp->w_doto;
return (setsize(rp,
(RSIZE) (fsize+curwp->w_marko)));
}
fsize += llength(flp)+1;
}
if (lback(blp) != curbp->b_linep) {
blp = lback(blp);
bsize += llength(blp)+1;
if (blp == curwp->w_markp) {
rp->r_linep = blp;
rp->r_offset = curwp->w_marko;
return (setsize(rp,
(RSIZE) (bsize-curwp->w_marko)));
}
}
}
ewprintf("Bug: lost mark"); /* Gak! */
return (FALSE);
}
/*
* Set size, and check for overflow.
*/
setsize(rp, size) register REGION *rp; register RSIZE size; {
rp->r_size = size;
if (rp->r_size != size) {
ewprintf("Region is too large");
return (FALSE);
}
return (TRUE);
}
#ifdef PREFIXREGION
/*
* Implements one of my favorite keyboard macros; put a string at the
* beginning of a number of lines in a buffer. The quote string is
* settable by using set-prefix-string. Great for quoting mail, which
* is the real reason I wrote it, but also has uses for creating bar
* comments (like the one you're reading) in C code.
*/
#define PREFIXLENGTH 40
static char prefix_string[PREFIXLENGTH] = { '>', '\0' };
/*
* Prefix the region with whatever is in prefix_string.
* Leaves dot at the beginning of the line after the end
* of the region. If an argument is given, prompts for the
* line prefix string.
*/
/*ARGSUSED*/
prefixregion(f, n, k)
{
register int s;
register LINE *first, *last;
register int nline;
REGION region;
char *prefix = prefix_string;
if ((f == TRUE) && ((s = setprefix(FALSE, 1, KRANDOM)) != TRUE))
return (s);
/* get # of lines to affect */
if ((s = getregion(®ion)) != TRUE)
return (s);
first = region.r_linep;
last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
for (nline = 1; first != last; nline++)
first = lforw(first);
/*move to beginning of region */
curwp->w_dotp = region.r_linep;
curwp->w_doto = region.r_offset;
/* for each line, go to beginning and insert the prefix string */
while (nline--) {
gotobol();
for (prefix = prefix_string; *prefix; prefix++)
(VOID) linsert((RSIZE) 1, *prefix);
forwline(FALSE, 1, KRANDOM);
}
gotobol();
return (TRUE);
}
/*
* Set prefix string.
*/
/*ARGSUSED*/
setprefix(f, n, k)
{
char buf[PREFIXLENGTH];
register int s;
if (prefix_string[0] == '\0')
s = ereply("Prefix string: ",buf,sizeof buf);
else
s = ereply("Prefix string (default %s): ",
buf,sizeof buf,prefix_string);
if (s == TRUE)
(VOID) strcpy(prefix_string, buf);
if ((s == FALSE) && (prefix_string[0] != '\0')) /* CR -- use old one */
s = TRUE;
return (s);
}
#endif
SHAR_EOF
fi # end of overwriting check
if test -f 'prefix.c'
then
echo shar: will not over-write existing file "'prefix.c'"
else
cat << \SHAR_EOF > 'prefix.c'
/*
* This code is a kludge for the two prefix sequences from GNU (well,
* the two I want) that uemacs doesn't have. Rather than quadruple the table
* space for keys, plus have to test for them everywhere, I'll just kludge
* it with functions that are bound to those keys. Later, maybe I'll do
* prefixes right.
*/
#include "def.h"
/*ARGSUSED*/
ctlx4hack(f, n, k) {
register KEY c;
if ((c = getkey(KPROMPT)) == 'b' || c == 'B')
return poptobuffer(f, n, KRANDOM);
if (c == 'f' || c == (KCTRL|'F') || c == 'F')
return poptofile(f, n, KRANDOM);
if (c == (KCTRL|'G') || c == (KCTLX|KCTRL|'G')
|| c == (KMETA|KCTRL|'G')) {
(VOID) ctrlg(FALSE, 1, KRANDOM);
return ABORT;
}
return FALSE;
}
/*ARGSUSED*/
help(f, n, k) {
register KEY c;
c = getkey(KPROMPT);
while (c == (KCTRL|'H')) {
ewprintf("B C: ");
c = getkey(0);
}
if (c == 'b' || c == 'B') return wallchart(f, n, KRANDOM);
if (c == 'c' || c == 'C') return desckey(f, n, KRANDOM);
if (c == (KCTRL|'G') || c == (KCTLX|KCTRL|'G')
|| c == (KMETA|KCTRL|'G')) {
(VOID) ctrlg(FALSE, 1, KRANDOM);
return ABORT;
}
return FALSE;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'version.c'
then
echo shar: will not over-write existing file "'version.c'"
else
cat << \SHAR_EOF > 'version.c'
/*
* This file contains the string that get written
* out by the emacs-version command.
* Rich had it generated by a command file. I do
* it manually, until I can figure out a way to get
* the MicroGnuEmacs version number generated in an
* reasonable and automatic manner.
*/
char *version = "MicroGnuEmacs 1a" ;
SHAR_EOF
fi # end of overwriting check
if test -f 'word.c'
then
echo shar: will not over-write existing file "'word.c'"
else
cat << \SHAR_EOF > 'word.c'
/*
* Word mode commands.
* 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 "def.h"
/*
* Move the cursor backward by
* "n" words. All of the details of motion
* are performed by the "backchar" and "forwchar"
* routines.
*/
/*ARGSUSED*/
backword(f, n, k) {
if (n < 0)
return (forwword(f, -n, KRANDOM));
if (backchar(FALSE, 1, KRANDOM) == FALSE)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (backchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
while (inword() != FALSE) {
if (backchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
}
return (forwchar(FALSE, 1, KRANDOM));
}
/*
* Move the cursor forward by
* the specified number of words. All of the
* motion is done by "forwchar".
*/
/*ARGSUSED*/
forwword(f, n, k) {
if (n < 0)
return (backword(f, -n, KRANDOM));
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
while (inword() != FALSE) {
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
}
return (TRUE);
}
/*
* Move the cursor forward by
* the specified number of words. As you move,
* convert any characters to upper case.
*/
/*ARGSUSED*/
upperword(f, n, k) {
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISLOWER(c) != FALSE) {
c = TOUPPER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
}
return (TRUE);
}
/*
* Move the cursor forward by
* the specified number of words. As you move
* convert characters to lower case.
*/
/*ARGSUSED*/
lowerword(f, n, k) {
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISUPPER(c) != FALSE) {
c = TOLOWER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
}
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.
*/
/*ARGSUSED*/
capword(f, n, k) {
register int c;
if (n < 0)
return (FALSE);
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
if (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISLOWER(c) != FALSE) {
c = TOUPPER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
while (inword() != FALSE) {
c = lgetc(curwp->w_dotp, curwp->w_doto);
if (ISUPPER(c) != FALSE) {
c = TOLOWER(c);
lputc(curwp->w_dotp, curwp->w_doto, c);
lchange(WFHARD);
}
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return TRUE;
}
}
}
return (TRUE);
}
/*
* Kill forward by "n" words.
*/
/*ARGSUSED*/
delfword(f, n, k) {
register RSIZE size;
register LINE *dotp;
register int doto;
if (n < 0)
return (FALSE);
if ((lastflag&CFKILL) == 0) /* Purge kill buffer. */
kdelete();
thisflag |= CFKILL;
dotp = curwp->w_dotp;
doto = curwp->w_doto;
size = 0;
while (n--) {
while (inword() == FALSE) {
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
goto out; /* Hit end of buffer. */
++size;
}
while (inword() != FALSE) {
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
goto out; /* Hit end of buffer. */
++size;
}
}
out:
curwp->w_dotp = dotp;
curwp->w_doto = doto;
return (ldelete(size, KFORW));
}
/*
* Kill backwards by "n" words. The rules
* for success and failure are now different, to prevent
* strange behavior at the start of the buffer. The command
* only fails if something goes wrong with the actual delete
* of the characters. It is successful even if no characters
* are deleted, or if you say delete 5 words, and there are
* only 4 words left. I considered making the first call
* to "backchar" special, but decided that that would just
* be wierd. Normally this is bound to "M-Rubout" and
* to "M-Backspace".
*/
/*ARGSUSED*/
delbword(f, n, k) {
register RSIZE size;
if (n < 0)
return (FALSE);
if ((lastflag&CFKILL) == 0) /* Purge kill buffer. */
kdelete();
thisflag |= CFKILL;
if (backchar(FALSE, 1, KRANDOM) == FALSE)
return (TRUE); /* Hit buffer start. */
size = 1; /* One deleted. */
while (n--) {
while (inword() == FALSE) {
if (backchar(FALSE, 1, KRANDOM) == FALSE)
goto out; /* Hit buffer start. */
++size;
}
while (inword() != FALSE) {
if (backchar(FALSE, 1, KRANDOM) == FALSE)
goto out; /* Hit buffer start. */
++size;
}
}
if (forwchar(FALSE, 1, KRANDOM) == FALSE)
return (FALSE);
--size; /* Undo assumed delete. */
out:
return (ldelete(size, KBACK));
}
/*
* 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() {
if (curwp->w_doto == llength(curwp->w_dotp))
return (FALSE);
if (ISWORD(lgetc(curwp->w_dotp, curwp->w_doto)) != FALSE)
return (TRUE);
return (FALSE);
}
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0
--
Bob Larson
Arpa: Blarson at Usc-Eclb.Arpa or blarson at usc-oberon.arpa
Uucp: (ihnp4,hplabs,tektronix)!sdcrdcf!usc-oberon!blarson
More information about the Mod.sources
mailing list