ftp.nice.ch/pub/next/unix/editor/me.3.10.N.bs.tar.gz#/me-3.10.N.bs/src/buffer.c

This is buffer.c in view mode; [Download] [Up]

/*  BUFFER.C:   buffer mgmt. routines
		MicroEMACS 3.10

 * Buffer management.
 * Some of the functions are internal,
 * and some are actually attached to user
 * keys. Like everyone else, they set hints
 * for the display system.
 */
#include        <stdio.h>
#include	"estruct.h"
#include	"etype.h"
#include        "edef.h"
#include	"elang.h"

/*
 * Attach a buffer to a window. The
 * values of dot and mark come from the buffer
 * if the use count is 0. Otherwise, they come
 * from some other window.
 */
PASCAL NEAR usebuffer(f, n)
{
        register BUFFER *bp;	/* temporary buffer pointer */

	/* get the buffer name to switch to */
	bp = getdefb();
	bp = getcbuf(TEXT24, bp ? bp->b_bname : "main", TRUE);
/*                          "Use buffer" */
	if (!bp)
		return(ABORT);

	/* make it invisable if there is an argument */
	if (f == TRUE)
		bp->b_flag |= BFINVS;

	/* switch to it in any case */
	return(swbuffer(bp));
}

PASCAL NEAR nextbuffer(f, n)	/* switch to the next buffer in the buffer list */

int f, n;	/* default flag, numeric argument */
{
	register BUFFER *bp;	/* current eligable buffer */
	register int status;

	/* make sure the arg is legit */
	if (f == FALSE)
		n = 1;
	if (n < 1)
		return(FALSE);

	/* cycle thru buffers until n runs out */
	while (n-- > 0) {
		bp = getdefb();
		if (bp == NULL)
			return(FALSE);
		status = swbuffer(bp);
		if (status != TRUE)
			return(status);
	}
	return(status);
}

PASCAL NEAR swbuffer(bp)	/* make buffer BP current */

BUFFER *bp;

{
        register WINDOW *wp;
	register int cmark;		/* current mark */

	/* let a user macro get hold of things...if he wants */
	execkey(&exbhook, FALSE, 1);

        if (--curbp->b_nwnd == 0) {             /* Last use.            */
                curbp->b_dotp  = curwp->w_dotp;
                curbp->b_doto  = curwp->w_doto;
		for (cmark = 0; cmark < NMARKS; cmark++) {
        	        curbp->b_markp[cmark] = curwp->w_markp[cmark];
                	curbp->b_marko[cmark] = curwp->w_marko[cmark];
                }
		curbp->b_fcol  = curwp->w_fcol;
        }
        curbp = bp;                             /* Switch.              */
	if (curbp->b_active != TRUE) {		/* buffer not active yet*/
		/* read it in and activate it */
		readin(curbp->b_fname, TRUE);
		curbp->b_dotp = lforw(curbp->b_linep);
		curbp->b_doto = 0;
		curbp->b_active = TRUE;
	}
        curwp->w_bufp  = bp;
        curwp->w_linep = bp->b_linep;           /* For macros, ignored. */
        curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty.         */
        if (bp->b_nwnd++ == 0) {                /* First use.           */
                curwp->w_dotp  = bp->b_dotp;
                curwp->w_doto  = bp->b_doto;
		for (cmark = 0; cmark < NMARKS; cmark++) {
        	        curwp->w_markp[cmark] = bp->b_markp[cmark];
                	curwp->w_marko[cmark] = bp->b_marko[cmark];
                }
		curwp->w_fcol  = bp->b_fcol;
        } else {
		wp = wheadp;			/* Look for old */
	        while (wp != NULL) {
	                if (wp!=curwp && wp->w_bufp==bp) {
	                        curwp->w_dotp  = wp->w_dotp;
	                        curwp->w_doto  = wp->w_doto;
				for (cmark = 0; cmark < NMARKS; cmark++) {
	                	        curwp->w_markp[cmark] = wp->w_markp[cmark];
	                        	curwp->w_marko[cmark] = wp->w_marko[cmark];
	                        }
				curwp->w_fcol  = wp->w_fcol;
	                        break;
	                }
	                wp = wp->w_wndp;
	        }
	}

	/* let a user macro get hold of things...if he wants */
	execkey(&bufhook, FALSE, 1);

        return(TRUE);
}

/*
 * Dispose of a buffer, by name.
 * Ask for the name. Look it up (don't get too
 * upset if it isn't there at all!). Get quite upset
 * if the buffer is being displayed. Clear the buffer (ask
 * if the buffer has been changed). Then free the header
 * line and the buffer header. Bound to "C-X K".
 */
PASCAL NEAR killbuffer(f, n)

{
	register BUFFER *bp;	/* ptr to buffer to dump */

	/* get the buffer name to kill */
	bp = getdefb();
	bp = getcbuf(TEXT26, bp ? bp->b_bname : "main", TRUE);
/*                   "Kill buffer" */
	if (bp == NULL)
		return(ABORT);

	return(zotbuf(bp));
}

BUFFER *PASCAL NEAR getdefb()	/* get the default buffer for a use or kill */

{
	BUFFER *bp;	/* default buffer */

	/* Find the next buffer, which will be the default */
	bp = curbp->b_bufp;

	/* cycle through the buffers to find an eligable one */
	while (bp == NULL || bp->b_flag & BFINVS) {
		if (bp == NULL)
			bp = bheadp;
		else
			bp = bp->b_bufp;

		/* don't get caught in an infinite loop! */
		if (bp == curbp) {
			bp = NULL;
			break;
		}
	}		
	return(bp);
}

PASCAL NEAR zotbuf(bp)	/* kill the buffer pointed to by bp */

register BUFFER *bp;

{
        register BUFFER *bp1;
        register BUFFER *bp2;
        register int    s;

        if (bp->b_nwnd != 0) {                  /* Error if on screen.  */
                mlwrite(TEXT28);
/*                      "Buffer is being displayed" */
                return(FALSE);
        }
        if ((s=bclear(bp)) != TRUE)             /* Blow text away.      */
                return(s);
        free((char *) bp->b_linep);             /* Release header line. */
        bp1 = NULL;                             /* Find the header.     */
        bp2 = bheadp;
        while (bp2 != bp) {
                bp1 = bp2;
                bp2 = bp2->b_bufp;
        }
        bp2 = bp2->b_bufp;                      /* Next one in chain.   */
        if (bp1 == NULL)                        /* Unlink it.           */
                bheadp = bp2;
        else
                bp1->b_bufp = bp2;
        free((char *) bp);                      /* Release buffer block */
        return(TRUE);
}

PASCAL NEAR namebuffer(f,n)	/*	Rename the current buffer	*/

int f, n;		/* default Flag & Numeric arg */

{
	register BUFFER *bp;	/* pointer to scan through all buffers */
	char bufn[NBUFN];	/* buffer to hold buffer name */

	/* prompt for and get the new buffer name */
ask:	if (mlreply(TEXT29, bufn, NBUFN) != TRUE)
/*                  "Change buffer name to: " */
		return(FALSE);

	/* and check for duplicates */
	bp = bheadp;
	while (bp != NULL) {
		if (bp != curbp) {
			/* if the names the same */
			if (strcmp(bufn, bp->b_bname) == 0)
				goto ask;  /* try again */
		}
		bp = bp->b_bufp;	/* onward */
	}

	strcpy(curbp->b_bname, bufn);	/* copy buffer name to structure */
	curwp->w_flag |= WFMODE;	/* make mode line replot */
	mlerase();
	return(TRUE);
}

/*
	List all of the active buffers.  First update the special
	buffer that holds the list.  Next make sure at least 1
	window is displaying the buffer list, splitting the screen
	if this is what it takes.  Lastly, repaint all of the
	windows that are displaying the list.  Bound to "C-X C-B". 
	A numeric argument forces it to list invisable buffers as
	well.
*/

PASCAL NEAR listbuffers(f, n)
{
        register WINDOW *wp;
        register BUFFER *bp;
        register int    s;
	register int cmark;		/* current mark */

        if ((s=makelist(f)) != TRUE)
                return(s);
        if (blistp->b_nwnd == 0) {              /* Not on screen yet.   */
                if ((wp=wpopup()) == NULL)
                        return(FALSE);
                bp = wp->w_bufp;
                if (--bp->b_nwnd == 0) {
                        bp->b_dotp  = wp->w_dotp;
                        bp->b_doto  = wp->w_doto;
			for (cmark = 0; cmark < NMARKS; cmark++) {
                	        bp->b_markp[cmark] = wp->w_markp[cmark];
                        	bp->b_marko[cmark] = wp->w_marko[cmark];
                        }
			bp->b_fcol  = wp->w_fcol;
                }
                wp->w_bufp  = blistp;
                ++blistp->b_nwnd;
        }
        wp = wheadp;
        while (wp != NULL) {
                if (wp->w_bufp == blistp) {
                        wp->w_linep = lforw(blistp->b_linep);
                        wp->w_dotp  = lforw(blistp->b_linep);
                        wp->w_doto  = 0;
			for (cmark = 0; cmark < NMARKS; cmark++) {
                        	wp->w_markp[cmark] = NULL;
	                        wp->w_marko[cmark] = 0;
	                }
                        wp->w_flag |= WFMODE|WFHARD;
                }
                wp = wp->w_wndp;
        }
        return(TRUE);
}

/*
 * This routine rebuilds the
 * text in the special secret buffer
 * that holds the buffer list. It is called
 * by the list buffers command. Return TRUE
 * if everything works. Return FALSE if there
 * is an error (if there is no memory). Iflag
 * indecates weather to list hidden buffers.
 */
PASCAL NEAR makelist(iflag)

int iflag;	/* list hidden buffer flag */

{
        register char   *cp1;
        register char   *cp2;
        register int    c;
        register BUFFER *bp;
        register LINE   *lp;
        register int    s;
	register int	i;
        long nbytes;		/* # of bytes in current buffer */
        char b[7+1];
        char line[128];

        blistp->b_flag &= ~BFCHG;               /* Don't complain!      */
        if ((s=bclear(blistp)) != TRUE)         /* Blow old text away   */
                return(s);
        strcpy(blistp->b_fname, "");
        if (addline(TEXT30) == FALSE
/*                  "ACT   Modes      Size Buffer          File" */
        ||  addline("--- --------- ------- --------------- ----") == FALSE)
                return(FALSE);
        bp = bheadp;                            /* For all buffers      */

	/* build line to report global mode settings */
	cp1 = &line[0];
	*cp1++ = ' ';
	*cp1++ = ' ';
	*cp1++ = ' ';
	*cp1++ = ' ';

	/* output the mode codes */
	for (i = 0; i < NUMMODES; i++)
		if (gmode & (1 << i))
			*cp1++ = modecode[i];
		else
			*cp1++ = '.';
	strcpy(cp1, TEXT31);
/*                  "         Global Modes" */
	if (addline(line) == FALSE)
		return(FALSE);

	/* output the list of buffers */
        while (bp != NULL) {
		/* skip invisable buffers if iflag is false */
                if (((bp->b_flag&BFINVS) != 0) && (iflag != TRUE)) {
                        bp = bp->b_bufp;
                        continue;
                }
                cp1 = &line[0];                 /* Start at left edge   */

		/* output status of ACTIVE flag (has the file been read in? */
                if (bp->b_active == TRUE)    /* "@" if activated       */
                        *cp1++ = '@';
                else
                        *cp1++ = ' ';

		/* output status of changed flag */
                if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed       */
                        *cp1++ = '*';
                else
                        *cp1++ = ' ';

		/* report if the file is truncated */
                if ((bp->b_flag&BFTRUNC) != 0)
                        *cp1++ = '#';
                else
                        *cp1++ = ' ';

                *cp1++ = ' ';	/* space */

		/* output the mode codes */
		for (i = 0; i < NUMMODES; i++) {
			if (bp->b_mode & (1 << i))
				*cp1++ = modecode[i];
			else
				*cp1++ = '.';
		}
                *cp1++ = ' ';                   /* Gap.                 */
                nbytes = 0L;                    /* Count bytes in buf.  */
                lp = lforw(bp->b_linep);
                while (lp != bp->b_linep) {
                        nbytes += (long)llength(lp)+1L;
                        lp = lforw(lp);
                }
                long_asc(b, 7, nbytes);             /* 6 digit buffer size. */
                cp2 = &b[0];
                while ((c = *cp2++) != 0)
                        *cp1++ = c;
                *cp1++ = ' ';                   /* Gap.                 */
                cp2 = &bp->b_bname[0];          /* Buffer name          */
                while ((c = *cp2++) != 0)
                        *cp1++ = c;
                *cp1++ = ' ';                   /* Gap.                 */
                cp2 = &bp->b_fname[0];          /* File name            */
                if (*cp2 != 0) {
                        while (cp1 < &line[22+NBUFN])
                                *cp1++ = ' ';
                        while ((c = *cp2++) != 0) {
                                if (cp1 < &line[128-1])
                                        *cp1++ = c;
                        }
                }
                *cp1 = 0;                       /* Add to the buffer.   */
                if (addline(line) == FALSE)
                        return(FALSE);
                bp = bp->b_bufp;
        }
        return(TRUE);                          /* All done             */
}

/* Translate a long to ascii form. Don't trust various systems
   ltoa() routines.. they aren't consistand				*/

PASCAL NEAR long_asc(buf, width, num)

char   buf[];
int    width;
long   num;

{
        buf[width] = 0;                         /* End of string.       */
        while (num >= 10) {                     /* Conditional digits.  */
                buf[--width] = (int)(num%10L) + '0';
                num /= 10L;
        }
        buf[--width] = (int)num + '0';          /* Always 1 digit.      */
        while (width != 0)                      /* Pad with blanks.     */
                buf[--width] = ' ';
}

/*
 * The argument "text" points to
 * a string. Append this line to the
 * buffer list buffer. Handcraft the EOL
 * on the end. Return TRUE if it worked and
 * FALSE if you ran out of room.
 */
PASCAL NEAR addline(text)
char    *text;
{
        register LINE   *lp;
        register int    i;
        register int    ntext;

        ntext = strlen(text);
        if ((lp=lalloc(ntext)) == NULL)
                return(FALSE);
        for (i=0; i<ntext; ++i)
                lputc(lp, i, text[i]);
        blistp->b_linep->l_bp->l_fp = lp;       /* Hook onto the end    */
        lp->l_bp = blistp->b_linep->l_bp;
        blistp->b_linep->l_bp = lp;
        lp->l_fp = blistp->b_linep;
        if (blistp->b_dotp == blistp->b_linep)  /* If "." is at the end */
                blistp->b_dotp = lp;            /* move it to new line  */
        return(TRUE);
}

/*
 * Look through the list of
 * buffers. Return TRUE if there
 * are any changed buffers. Buffers
 * that hold magic internal stuff are
 * not considered; who cares if the
 * list of buffer names is hacked.
 * Return FALSE if no buffers
 * have been changed.
 */
PASCAL NEAR anycb()
{
        register BUFFER *bp;

        bp = bheadp;
        while (bp != NULL) {
                if ((bp->b_flag&BFINVS)==0 && (bp->b_flag&BFCHG)!=0)
                        return(TRUE);
                bp = bp->b_bufp;
        }
        return(FALSE);
}

/*
 * Find a buffer, by name. Return a pointer
 * to the BUFFER structure associated with it.
 * If the buffer is not found
 * and the "cflag" is TRUE, create it. The "bflag" is
 * the settings for the flags in in buffer.
 */
BUFFER *PASCAL NEAR bfind(bname, cflag, bflag)

register char   *bname;	/* name of buffer to find */
int cflag;		/* create it if not found? */
int bflag;		/* bit settings for a new buffer */

{
        register BUFFER *bp;
	register BUFFER *sb;	/* buffer to insert after */
        register LINE   *lp;
	int cmark;		/* current mark */

        bp = bheadp;
        while (bp != NULL) {
                if (strcmp(bname, bp->b_bname) == 0)
                        return(bp);
                bp = bp->b_bufp;
        }
        if (cflag != FALSE) {
                if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL)
                        return(NULL);
                if ((lp=lalloc(0)) == NULL) {
                        free((char *) bp);
                        return(NULL);
                }
		/* find the place in the list to insert this buffer */
		if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
			/* insert at the beginning */
	                bp->b_bufp = bheadp;
        	        bheadp = bp;
        	} else {
			sb = bheadp;
			while (sb->b_bufp != NULL) {
				if (strcmp(sb->b_bufp->b_bname, bname) > 0)
					break;
				sb = sb->b_bufp;
			}

			/* and insert it */
       			bp->b_bufp = sb->b_bufp;
        		sb->b_bufp = bp;
       		}

		/* and set up the other buffer fields */
		bp->b_topline = NULL;
		bp->b_botline = NULL;
		bp->b_active = TRUE;
                bp->b_dotp  = lp;
                bp->b_doto  = 0;
		for (cmark = 0; cmark < NMARKS; cmark++) {
        	        bp->b_markp[cmark] = NULL;
                	bp->b_marko[cmark] = 0;
                }
		bp->b_fcol = 0;
                bp->b_flag  = bflag;
		bp->b_mode  = gmode;
                bp->b_nwnd  = 0;
                bp->b_linep = lp;
                strcpy(bp->b_fname, "");
                strcpy(bp->b_bname, bname);
#if	CRYPT
		bp->b_key[0] = 0;
#endif
                lp->l_fp = lp;
                lp->l_bp = lp;
        }
        return(bp);
}

/*
 * This routine blows away all of the text
 * in a buffer. If the buffer is marked as changed
 * then we ask if it is ok to blow it away; this is
 * to save the user the grief of losing text. The
 * window chain is nearly always wrong if this gets
 * called; the caller must arrange for the updates
 * that are required. Return TRUE if everything
 * looks good.
 */
PASCAL NEAR bclear(bp)
register BUFFER *bp;
{
        register LINE   *lp;
        register int    s;
	int cmark;		/* current mark */

        if ((bp->b_flag&BFINVS) == 0            /* Not scratch buffer.  */
        && (bp->b_flag&BFCHG) != 0              /* Something changed    */
        && (s=mlyesno(TEXT32)) != TRUE)
/*                    "Discard changes" */
                return(s);
        bp->b_flag  &= ~BFCHG;                  /* Not changed          */
        while ((lp=lforw(bp->b_linep)) != bp->b_linep)
                lfree(lp);
        bp->b_dotp  = bp->b_linep;              /* Fix "."              */
        bp->b_doto  = 0;
	for (cmark = 0; cmark < NMARKS; cmark++) {
	        bp->b_markp[cmark] = NULL;  /* Invalidate "mark"    */
        	bp->b_marko[cmark] = 0;
        }
	bp->b_fcol = 0;
        return(TRUE);
}

PASCAL NEAR unmark(f, n)	/* unmark the current buffers change flag */

int f, n;	/* unused command arguments */

{
	register WINDOW *wp;

	/* unmark the buffer */
	curbp->b_flag &= ~BFCHG;

	/* unmark all windows as well */
	upmode();

	return(TRUE);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.