Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!utgpu!water!watmath!clyde!rutgers!husc6!sri-unix!ctnews!pyramid!uccba!hal!ncoast!allbery
From: allbery@ncoast.UUCP
Newsgroups: comp.sources.misc
Subject: memacs 3.8i 6 of 11
Message-ID: <2661@ncoast.UUCP>
Date: Mon, 15-Jun-87 15:02:50 EDT
Article-I.D.: ncoast.2661
Posted: Mon Jun 15 15:02:50 1987
Date-Received: Sat, 20-Jun-87 01:58:36 EDT
Sender: allbery@ncoast.UUCP
Lines: 713
Approved: allbery@ncoast.UUCP
:
#!/bin/sh
# shar+ created from directory /usr2/davidsen/emacs38i
# 13:42 on Thu Jun 11, 1987 by davidsen
echo 'x - line.c (text)'
sed << 'E!O!F' 's/^X//' > line.c
X/*
X * The functions in this file are a general set of line management utilities.
X * They are the only routines that touch the text. They also touch the buffer
X * and window structures, to make sure that the necessary updating gets done.
X * There are routines in this file that handle the kill buffer too. It isn't
X * here for any good reason.
X *
X * Note that this code only updates the dot and mark values in the window list.
X * Since all the code acts on the current window, the buffer that we are
X * editing must be being displayed, which means that "b_nwnd" is non zero,
X * which means that the dot and mark values in the buffer headers are nonsense.
X */
X
X#include
X#include "estruct.h"
X#include "edef.h"
X
XKILL *ykbuf; /* ptr to current kill buffer chunk being yanked */
Xint ykboff; /* offset into that chunk */
X
X/*
X * This routine allocates a block of memory large enough to hold a LINE
X * containing "used" characters. The block is always rounded up a bit. Return
X * a pointer to the new block, or NULL if there isn't any memory left. Print a
X * message in the message line if no space.
X */
XLINE *
Xlalloc(used)
Xregister int used;
X{
X register LINE *lp;
X register int size;
X char *malloc();
X
X size = (used+NBLOCK-1) & ~(NBLOCK-1);
X if (size == 0) /* Assume that an empty */
X size = NBLOCK; /* line is for type-in. */
X if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
X mlwrite("Cannot allocate %d bytes", size);
X return (NULL);
X }
X lp->l_size = size;
X lp->l_used = used;
X return (lp);
X}
X
X/*
X * Delete line "lp". Fix all of the links that might point at it (they are
X * moved to offset 0 of the next line. Unlink the line from whatever buffer it
X * might be in. Release the memory. The buffers are updated too; the magic
X * conditions described in the above comments don't hold here.
X */
Xlfree(lp)
Xregister LINE *lp;
X{
X register BUFFER *bp;
X register WINDOW *wp;
X
X wp = wheadp;
X while (wp != NULL) {
X if (wp->w_linep == lp)
X wp->w_linep = lp->l_fp;
X if (wp->w_dotp == lp) {
X wp->w_dotp = lp->l_fp;
X wp->w_doto = 0;
X }
X if (wp->w_markp == lp) {
X wp->w_markp = lp->l_fp;
X wp->w_marko = 0;
X }
X wp = wp->w_wndp;
X }
X bp = bheadp;
X while (bp != NULL) {
X if (bp->b_nwnd == 0) {
X if (bp->b_dotp == lp) {
X bp->b_dotp = lp->l_fp;
X bp->b_doto = 0;
X }
X if (bp->b_markp == lp) {
X bp->b_markp = lp->l_fp;
X bp->b_marko = 0;
X }
X }
X bp = bp->b_bufp;
X }
X lp->l_bp->l_fp = lp->l_fp;
X lp->l_fp->l_bp = lp->l_bp;
X free((char *) lp);
X}
X
X/*
X * This routine gets called when a character is changed in place in the current
X * buffer. It updates all of the required flags in the buffer and window
X * system. The flag used is passed as an argument; if the buffer is being
X * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
X * mode line needs to be updated (the "*" has to be set).
X */
Xlchange(flag)
Xregister int flag;
X{
X register WINDOW *wp;
X
X if (curbp->b_nwnd != 1) /* Ensure hard. */
X flag = WFHARD;
X if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
X flag |= WFMODE; /* update mode lines. */
X curbp->b_flag |= BFCHG;
X }
X wp = wheadp;
X while (wp != NULL) {
X if (wp->w_bufp == curbp)
X wp->w_flag |= flag;
X wp = wp->w_wndp;
X }
X}
X
Xinsspace(f, n) /* insert spaces forward into text */
X
Xint f, n; /* default flag and numeric argument */
X
X{
X linsert(n, ' ');
X backchar(f, n);
X}
X
X/*
X * Insert "n" copies of the character "c" at the current location of dot. In
X * the easy case all that happens is the text is stored in the line. In the
X * hard case, the line has to be reallocated. When the window list is updated,
X * take special care; I screwed it up once. You always update dot in the
X * current window. You update mark, and a dot in another window, if it is
X * greater than the place where you did the insert. Return TRUE if all is
X * well, and FALSE on errors.
X */
Xlinsert(n, c)
X{
X register char *cp1;
X register char *cp2;
X register LINE *lp1;
X register LINE *lp2;
X register LINE *lp3;
X register int doto;
X register int i;
X register WINDOW *wp;
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X lchange(WFEDIT);
X lp1 = curwp->w_dotp; /* Current line */
X if (lp1 == curbp->b_linep) { /* At the end: special */
X if (curwp->w_doto != 0) {
X mlwrite("bug: linsert");
X return (FALSE);
X }
X if ((lp2=lalloc(n)) == NULL) /* Allocate new line */
X return (FALSE);
X lp3 = lp1->l_bp; /* Previous line */
X lp3->l_fp = lp2; /* Link in */
X lp2->l_fp = lp1;
X lp1->l_bp = lp2;
X lp2->l_bp = lp3;
X for (i=0; il_text[i] = c;
X curwp->w_dotp = lp2;
X curwp->w_doto = n;
X return (TRUE);
X }
X doto = curwp->w_doto; /* Save for later. */
X if (lp1->l_used+n > lp1->l_size) { /* Hard: reallocate */
X if ((lp2=lalloc(lp1->l_used+n)) == NULL)
X return (FALSE);
X cp1 = &lp1->l_text[0];
X cp2 = &lp2->l_text[0];
X while (cp1 != &lp1->l_text[doto])
X *cp2++ = *cp1++;
X cp2 += n;
X while (cp1 != &lp1->l_text[lp1->l_used])
X *cp2++ = *cp1++;
X lp1->l_bp->l_fp = lp2;
X lp2->l_fp = lp1->l_fp;
X lp1->l_fp->l_bp = lp2;
X lp2->l_bp = lp1->l_bp;
X free((char *) lp1);
X } else { /* Easy: in place */
X lp2 = lp1; /* Pretend new line */
X lp2->l_used += n;
X cp2 = &lp1->l_text[lp1->l_used];
X cp1 = cp2-n;
X while (cp1 != &lp1->l_text[doto])
X *--cp2 = *--cp1;
X }
X for (i=0; il_text[doto+i] = c;
X wp = wheadp; /* Update windows */
X while (wp != NULL) {
X if (wp->w_linep == lp1)
X wp->w_linep = lp2;
X if (wp->w_dotp == lp1) {
X wp->w_dotp = lp2;
X if (wp==curwp || wp->w_doto>doto)
X wp->w_doto += n;
X }
X if (wp->w_markp == lp1) {
X wp->w_markp = lp2;
X if (wp->w_marko > doto)
X wp->w_marko += n;
X }
X wp = wp->w_wndp;
X }
X return (TRUE);
X}
X
X/*
X * Insert a newline into the buffer at the current location of dot in the
X * current window. The funny ass-backwards way it does things is not a botch;
X * it just makes the last line in the file not a special case. Return TRUE if
X * everything works out and FALSE on error (memory allocation failure). The
X * update of dot and mark is a bit easier then in the above case, because the
X * split forces more updating.
X */
Xlnewline()
X{
X register char *cp1;
X register char *cp2;
X register LINE *lp1;
X register LINE *lp2;
X register int doto;
X register WINDOW *wp;
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X lchange(WFHARD);
X lp1 = curwp->w_dotp; /* Get the address and */
X doto = curwp->w_doto; /* offset of "." */
X if ((lp2=lalloc(doto)) == NULL) /* New first half line */
X return (FALSE);
X cp1 = &lp1->l_text[0]; /* Shuffle text around */
X cp2 = &lp2->l_text[0];
X while (cp1 != &lp1->l_text[doto])
X *cp2++ = *cp1++;
X cp2 = &lp1->l_text[0];
X while (cp1 != &lp1->l_text[lp1->l_used])
X *cp2++ = *cp1++;
X lp1->l_used -= doto;
X lp2->l_bp = lp1->l_bp;
X lp1->l_bp = lp2;
X lp2->l_bp->l_fp = lp2;
X lp2->l_fp = lp1;
X wp = wheadp; /* Windows */
X while (wp != NULL) {
X if (wp->w_linep == lp1)
X wp->w_linep = lp2;
X if (wp->w_dotp == lp1) {
X if (wp->w_doto < doto)
X wp->w_dotp = lp2;
X else
X wp->w_doto -= doto;
X }
X if (wp->w_markp == lp1) {
X if (wp->w_marko < doto)
X wp->w_markp = lp2;
X else
X wp->w_marko -= doto;
X }
X wp = wp->w_wndp;
X }
X return (TRUE);
X}
X
X/*
X * This function deletes "n" bytes, starting at dot. It understands how do deal
X * with end of lines, etc. It returns TRUE if all of the characters were
X * deleted, and FALSE if they were not (because dot ran into the end of the
X * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
X */
Xldelete(n, kflag)
X
Xlong n; /* # of chars to delete */
Xint kflag; /* put killed text in kill buffer flag */
X
X{
X register char *cp1;
X register char *cp2;
X register LINE *dotp;
X register int doto;
X register int chunk;
X register WINDOW *wp;
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X while (n != 0) {
X dotp = curwp->w_dotp;
X doto = curwp->w_doto;
X if (dotp == curbp->b_linep) /* Hit end of buffer. */
X return (FALSE);
X chunk = dotp->l_used-doto; /* Size of chunk. */
X if (chunk > n)
X chunk = n;
X if (chunk == 0) { /* End of line, merge. */
X lchange(WFHARD);
X if (ldelnewline() == FALSE
X || (kflag!=FALSE && kinsert('\n')==FALSE))
X return (FALSE);
X --n;
X continue;
X }
X lchange(WFEDIT);
X cp1 = &dotp->l_text[doto]; /* Scrunch text. */
X cp2 = cp1 + chunk;
X if (kflag != FALSE) { /* Kill? */
X while (cp1 != cp2) {
X if (kinsert(*cp1) == FALSE)
X return (FALSE);
X ++cp1;
X }
X cp1 = &dotp->l_text[doto];
X }
X while (cp2 != &dotp->l_text[dotp->l_used])
X *cp1++ = *cp2++;
X dotp->l_used -= chunk;
X wp = wheadp; /* Fix windows */
X while (wp != NULL) {
X if (wp->w_dotp==dotp && wp->w_doto>=doto) {
X wp->w_doto -= chunk;
X if (wp->w_doto < doto)
X wp->w_doto = doto;
X }
X if (wp->w_markp==dotp && wp->w_marko>=doto) {
X wp->w_marko -= chunk;
X if (wp->w_marko < doto)
X wp->w_marko = doto;
X }
X wp = wp->w_wndp;
X }
X n -= chunk;
X }
X return (TRUE);
X}
X
X/*
X * Delete a newline. Join the current line with the next line. If the next line
X * is the magic header line always return TRUE; merging the last line with the
X * header line can be thought of as always being a successful operation, even
X * if nothing is done, and this makes the kill buffer work "right". Easy cases
X * can be done by shuffling data around. Hard cases require that lines be moved
X * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
X * "ldelete" only.
X */
Xldelnewline()
X{
X register char *cp1;
X register char *cp2;
X register LINE *lp1;
X register LINE *lp2;
X register LINE *lp3;
X register WINDOW *wp;
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X lp1 = curwp->w_dotp;
X lp2 = lp1->l_fp;
X if (lp2 == curbp->b_linep) { /* At the buffer end. */
X if (lp1->l_used == 0) /* Blank line. */
X lfree(lp1);
X return (TRUE);
X }
X if (lp2->l_used <= lp1->l_size-lp1->l_used) {
X cp1 = &lp1->l_text[lp1->l_used];
X cp2 = &lp2->l_text[0];
X while (cp2 != &lp2->l_text[lp2->l_used])
X *cp1++ = *cp2++;
X wp = wheadp;
X while (wp != NULL) {
X if (wp->w_linep == lp2)
X wp->w_linep = lp1;
X if (wp->w_dotp == lp2) {
X wp->w_dotp = lp1;
X wp->w_doto += lp1->l_used;
X }
X if (wp->w_markp == lp2) {
X wp->w_markp = lp1;
X wp->w_marko += lp1->l_used;
X }
X wp = wp->w_wndp;
X }
X lp1->l_used += lp2->l_used;
X lp1->l_fp = lp2->l_fp;
X lp2->l_fp->l_bp = lp1;
X free((char *) lp2);
X return (TRUE);
X }
X if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
X return (FALSE);
X cp1 = &lp1->l_text[0];
X cp2 = &lp3->l_text[0];
X while (cp1 != &lp1->l_text[lp1->l_used])
X *cp2++ = *cp1++;
X cp1 = &lp2->l_text[0];
X while (cp1 != &lp2->l_text[lp2->l_used])
X *cp2++ = *cp1++;
X lp1->l_bp->l_fp = lp3;
X lp3->l_fp = lp2->l_fp;
X lp2->l_fp->l_bp = lp3;
X lp3->l_bp = lp1->l_bp;
X wp = wheadp;
X while (wp != NULL) {
X if (wp->w_linep==lp1 || wp->w_linep==lp2)
X wp->w_linep = lp3;
X if (wp->w_dotp == lp1)
X wp->w_dotp = lp3;
X else if (wp->w_dotp == lp2) {
X wp->w_dotp = lp3;
X wp->w_doto += lp1->l_used;
X }
X if (wp->w_markp == lp1)
X wp->w_markp = lp3;
X else if (wp->w_markp == lp2) {
X wp->w_markp = lp3;
X wp->w_marko += lp1->l_used;
X }
X wp = wp->w_wndp;
X }
X free((char *) lp1);
X free((char *) lp2);
X return (TRUE);
X}
X
X/*
X * Delete all of the text saved in the kill buffer. Called by commands when a
X * new kill context is being created. The kill buffer array is released, just
X * in case the buffer has grown to immense size. No errors.
X */
Xkdelete()
X{
X KILL *kp; /* ptr to scan kill buffer chunk list */
X
X if (kbufh != NULL) {
X
X /* first, delete all the chunks */
X kbufp = kbufh;
X while (kbufp != NULL) {
X kp = kbufp->d_next;
X free(kbufp);
X kbufp = kp;
X }
X
X /* and reset all the kill buffer pointers */
X kbufh = kbufp = NULL;
X kused = KBLOCK;
X }
X}
X
X/*
X * Insert a character to the kill buffer, allocating new chunks as needed.
X * Return TRUE if all is well, and FALSE on errors.
X */
X
Xkinsert(c)
X
Xint c; /* character to insert in the kill buffer */
X
X{
X KILL *nchunk; /* ptr to newly malloced chunk */
X
X /* check to see if we need a new chunk */
X if (kused >= KBLOCK) {
X if ((nchunk = (KILL *)malloc(sizeof(KILL))) == NULL)
X return(FALSE);
X if (kbufh == NULL) /* set head ptr if first time */
X kbufh = nchunk;
X if (kbufp != NULL) /* point the current to this new one */
X kbufp->d_next = nchunk;
X kbufp = nchunk;
X kbufp->d_next = NULL;
X kused = 0;
X }
X
X /* and now insert the character */
X kbufp->d_chunk[kused++] = c;
X return(TRUE);
X}
X
X/*
X * Yank text back from the kill buffer. This is really easy. All of the work
X * is done by the standard insert routines. All you do is run the loop, and
X * check for errors. Bound to "C-Y".
X */
Xyank(f, n)
X{
X register int c;
X register int i;
X register char *sp; /* pointer into string to insert */
X KILL *kp; /* pointer into kill buffer */
X
X if (curbp->b_mode&MDVIEW) /* don't allow this command if */
X return(rdonly()); /* we are in read only mode */
X if (n < 0)
X return (FALSE);
X /* make sure there is something to yank */
X if (kbufh == NULL)
X return(TRUE); /* not an error, just nothing */
X
X /* for each time.... */
X while (n--) {
X kp = kbufh;
X while (kp != NULL) {
X if (kp->d_next == NULL)
X i = kused;
X else
X i = KBLOCK;
X sp = kp->d_chunk;
X while (i--) {
X if ((c = *sp++) == '\n') {
X if (lnewline() == FALSE)
X return (FALSE);
X } else {
X if (linsert(1, c) == FALSE)
X return (FALSE);
X }
X }
X kp = kp->d_next;
X }
X }
X return (TRUE);
X}
X
X
E!O!F
newsize=`wc -c < line.c`
if [ $newsize -ne 18815 ]
then echo "File line.c was $newsize bytes, 18815 expected"
fi
echo 'x - lock.c (text)'
sed << 'E!O!F' 's/^X//' > lock.c
X/* LOCK: File locking command routines for MicroEMACS
X written by Daniel Lawrence
X */
X
X#include
X#include "estruct.h"
X#include "edef.h"
X
X#if FILOCK
X#if BSD
X#include
X
Xextern int sys_nerr; /* number of system error messages defined */
Xextern char *sys_errlist[]; /* list of message texts */
Xextern int errno; /* current error */
X
Xchar *lname[NLOCKS]; /* names of all locked files */
Xint numlocks; /* # of current locks active */
X
X/* lockchk: check a file for locking and add it to the list */
X
Xlockchk(fname)
X
Xchar *fname; /* file to check for a lock */
X
X{
X register int i; /* loop indexes */
X register int status; /* return status */
X char *undolock();
X
X /* check to see if that file is already locked here */
X if (numlocks > 0)
X for (i=0; i < numlocks; ++i)
X if (strcmp(fname, lname[i]) == 0)
X return(TRUE);
X
X /* if we have a full locking table, bitch and leave */
X if (numlocks == NLOCKS) {
X mlwrite("LOCK ERROR: Lock table full");
X return(ABORT);
X }
X
X /* next, try to lock it */
X status = lock(fname);
X if (status == ABORT) /* file is locked, no override */
X return(ABORT);
X if (status == FALSE) /* locked, overriden, dont add to table */
X return(TRUE);
X
X /* we have now locked it, add it to our table */
X lname[++numlocks - 1] = (char *)malloc(strlen(fname) + 1);
X if (lname[numlocks - 1] == NULL) { /* malloc failure */
X undolock(fname); /* free the lock */
X mlwrite("Cannot lock, out of memory");
X --numlocks;
X return(ABORT);
X }
X
X /* everthing is cool, add it to the table */
X strcpy(lname[numlocks-1], fname);
X return(TRUE);
X}
X
X/* lockrel: release all the file locks so others may edit */
X
Xlockrel()
X
X{
X register int i; /* loop index */
X register int status; /* status of locks */
X register int s; /* status of one unlock */
X
X status = TRUE;
X if (numlocks > 0)
X for (i=0; i < numlocks; ++i) {
X if ((s = unlock(lname[i])) != TRUE)
X status = s;
X free(lname[i]);
X }
X numlocks = 0;
X return(status);
X}
X
X/* lock: Check and lock a file from access by others
X returns TRUE = files was not locked and now is
X FALSE = file was locked and overridden
X ABORT = file was locked, abort command
X*/
X
Xlock(fname)
X
Xchar *fname; /* file name to lock */
X
X{
X register char *locker; /* lock error message */
X register int status; /* return status */
X char msg[NSTRING]; /* message string */
X char *dolock();
X
X /* attempt to lock the file */
X locker = dolock(fname);
X if (locker == NULL) /* we win */
X return(TRUE);
X
X /* file failed...abort */
X if (strncmp(locker, "LOCK", 4) == 0) {
X lckerror(locker);
X return(ABORT);
X }
X
X /* someone else has it....override? */
X strcpy(msg, "File in use by ");
X strcat(msg, locker);
X strcat(msg, ", overide?");
X status = mlyesno(msg); /* ask them */
X if (status == TRUE)
X return(FALSE);
X else
X return(ABORT);
X}
X
X/* unlock: Unlock a file
X this only warns the user if it fails
X */
X
Xunlock(fname)
X
Xchar *fname; /* file to unlock */
X
X{
X register char *locker; /* undolock return string */
X char *undolock();
X
X /* unclock and return */
X locker = undolock(fname);
X if (locker == NULL)
X return(TRUE);
X
X /* report the error and come back */
X lckerror(locker);
X return(FALSE);
X}
X
Xlckerror(errstr) /* report a lock error */
X
Xchar *errstr; /* lock error string to print out */
X
X{
X char obuf[NSTRING]; /* output buffer for error message */
X
X strcpy(obuf, errstr);
X strcat(obuf, " - ");
X if (errno < sys_nerr)
X strcat(obuf, sys_errlist[errno]);
X else
X strcat(obuf, "[can not get system error message]");
X mlwrite(obuf);
X}
X#endif
X#else
Xlckhello() /* dummy function */
X{
X}
X#endif
E!O!F
newsize=`wc -c < lock.c`
if [ $newsize -ne 3565 ]
then echo "File lock.c was $newsize bytes, 3565 expected"
fi
bill davidsen (wedu@ge-crd.arpa)
{chinet | philabs | sesimo}!steinmetz!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me