[comp.sources.misc] memacs 3.8i 6 of 11

allbery@ncoast.UUCP (06/15/87)

:
#!/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        <stdio.h>
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; i<n; ++i)
X                        lp2->l_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; i<n; ++i)                     /* Add the characters   */
X                lp2->l_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 <stdio.h>
X#include "estruct.h"
X#include "edef.h"
X
X#if	FILOCK
X#if	BSD
X#include <sys/errno.h>
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