/* * 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 #include "ed.h" /* USEBUFFER eXtended command. Prompt for buffer name. Store it in * external pattern lastbuf. Call selbuf() to make the change. Bound * to CTLX-B. */ usebuffer(f, n) register int f, n; { register int s; if ((s=readpattern("Use buffer [DEFAULT] ", &lastbuf)) != TRUE) return (s); return(selbuf(lastbuf)); } /* * 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. */ selbuf(bufname) register char *bufname; { register BUFFER *bp; register WINDOW *wp; /* Find a buffer. If the buffer does not exist, then ask the user * whether a new buffer should be created. */ if ((bp=bfind(bufname, MAYBE, 0)) == NULL) return (FALSE); strcpy(lastbuf, curbp->b_bname); /* set up for return */ if (--curbp->b_nwnd == 0) { /* Last use. */ curbp->b_dotp = curwp->w_dotp; curbp->b_doto = curwp->w_doto; curbp->b_markp = curwp->w_markp; curbp->b_marko = curwp->w_marko; } curbp = bp; /* Switch. */ 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; curwp->w_markp = bp->b_markp; curwp->w_marko = bp->b_marko; return (TRUE); } 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; curwp->w_markp = wp->w_markp; curwp->w_marko = wp->w_marko; break; } wp = wp->w_wndp; } return (TRUE); } /* KILLBUFFER eXtended command. Prompt for buffer name. Call delbuf() * to do the actual kill. Bound to CTLX-K. */ killbuffer(f, n) register int f, n; { register int s; if ((s=readpattern("Kill buffer [DEFAULT] ", &lastbuf)) != TRUE) return (s); return(delbuf(lastbuf)); } /* * Dispose of a buffer, by name. * Look up bufname (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. */ delbuf(bufname) register char *bufname; { register BUFFER *bp; register BUFFER *bp1; register BUFFER *bp2; register int s; if ((bp=bfind(bufname, FALSE, 0)) == NULL) /* Easy if unknown.*/ return (TRUE); strcpy(lastbuf, curbp->b_bname); if (bp->b_nwnd != 0) { /* Error if on screen. */ mlwrite("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); } /* * 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". */ listbuffers(f, n) register int f, n; { register WINDOW *wp; register BUFFER *bp; register int s; if (blistp == NULL) { blistp = bfind("[List]", TRUE, BFTEMP); /* Buffer list buffer*/ if (blistp == NULL) return(ABORT); } if ((s=makelist()) != 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; bp->b_markp = wp->w_markp; bp->b_marko = wp->w_marko; } 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; wp->w_markp = NULL; wp->w_marko = 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). */ makelist() { register char *cp1; register char *cp2; register int c; register BUFFER *bp; register LINE *lp; register long nbytes; register int s; register int type; char b[6+1]; char line[128]; blistp->b_flag &= ~BFCHG; /* Don't complain! */ blistp->b_bmode |= BMNWRAP; if ((s=bclear(blistp)) != TRUE) /* Blow old text away */ return (s); strcpy(blistp->b_fname, ""); if (addline(blistp,"C Size Buffer File") == FALSE || addline(blistp,"- ---- ------ ----") == FALSE) return (FALSE); bp = bheadp; /* For all buffers */ while (bp != NULL) { if ((bp->b_flag&BFTEMP) != 0) { /* Skip magic ones. */ bp = bp->b_bufp; continue; } cp1 = &line[0]; /* Start at left edge */ if ((bp->b_flag&BFCHG) != 0) /* "*" if changed */ *cp1++ = '*'; else *cp1++ = ' '; *cp1++ = ' '; /* Gap. */ nbytes = 0L; /* Count bytes in buf. */ lp = lforw(bp->b_linep); while (lp != bp->b_linep) { nbytes += llength(lp)+1; lp = lforw(lp); } ltoa(b, 6, 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; cp2 = &bp->b_fname[0]; /* File name */ if (*cp2 != 0) { while (cp1 < &line[1+1+6+1+NBUFN+1]) *cp1++ = ' '; while ((c = *cp2++) != 0) { if (cp1 < &line[128-1]) *cp1++ = c; } } *cp1 = 0; /* Add to the buffer. */ if (addline(blistp, line) == FALSE) return (FALSE); bp = bp->b_bufp; } return (TRUE); /* All done */ } ltoa(buf, width, num) register char buf[]; register int width; register long num; { buf[width] = 0; /* End of string. */ while (num >= 10L) { /* Conditional digits. */ buf[--width] = (int)(num%10L) + '0'; num /= 10L; } buf[--width] = 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 "bp" (one with BFTEMP set). Handcraft the EOL * on the end. Return TRUE if it worked and * FALSE if you ran out of room. */ addline(bp, text) register BUFFER *bp; register char *text; { register LINE *lp; register int i; register int ntext; ntext = strlen(text); if ((lp=lalloc(ntext)) == NULL) return (FALSE); for (i=0; ib_linep->l_bp->l_fp = lp; /* Hook onto the end */ lp->l_bp = bp->b_linep->l_bp; bp->b_linep->l_bp = lp; lp->l_fp = bp->b_linep; if (bp->b_dotp == bp->b_linep) /* If "." is at the end */ bp->b_dotp = lp; /* move it to new line */ 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. */ anycb() { register BUFFER *bp; bp = bheadp; while (bp != NULL) { if ((bp->b_flag&BFTEMP)==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 named buffer is found, but is a TEMP buffer (like * the buffer list) conplain. 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 * bfind(bname, cflag, bflag) register char *bname; register int cflag, bflag; { register BUFFER *bp; register LINE *lp; char *index(),*ptr; bp = bheadp; while (bp != NULL) { if (strcmp(bname, bp->b_bname) == 0) { if ((bp->b_flag&BFTEMP) != 0) if (cflag == FALSE) { mlwrite("Cannot select builtin buffer"); return (FALSE); } return (bp); } bp = bp->b_bufp; } /* Buffer does not exist. Prompt the user to see if a new * buffer should be created. */ if (cflag == MAYBE) { if (mlyesno("Create new buffer") != TRUE) return(FALSE); cflag = TRUE; /* yes, create it */ } if (cflag == TRUE) { if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) return (NULL); if ((lp=lalloc(0)) == NULL) { free((char *) bp); return (NULL); } /* clear all mode flags */ bp->b_bmode &=~BMWRAP; bp->b_bmode &=~BMNWRAP; bp->b_bmode &=~BMCMODE; if (ptr=index(bname,'.')) { if (strncmp(ptr, ".mss",4)==0) bp->b_bmode |= BMWRAP; else if (strcmp(ptr,".c")==0) bp->b_bmode |= BMCMODE; else if (strcmp(ptr,".h")==0) bp->b_bmode |= BMCMODE; else bp->b_bmode |= glmode; } else bp->b_bmode |= glmode; bp->b_bufp = bheadp; bheadp = bp; bp->b_dotp = lp; bp->b_doto = 0; bp->b_markp = lp; /* All new buffers begin with mark */ bp->b_marko = 0; bp->b_flag = bflag; bp->b_nwnd = 0; bp->b_linep = lp; strcpy(bp->b_fname, ""); strcpy(bp->b_bname, bname); 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. */ bclear(bp) register BUFFER *bp; { register LINE *lp; register int s; if ((bp->b_flag&BFTEMP) == 0 /* Not scratch buffer. */ && (bp->b_flag&BFCHG) != 0 /* Something changed */ && (s=mlyesno("Discard changes")) != TRUE) return (s); bp->b_flag &= ~BFCHG; /* Not changed */ while ((lp=lforw(bp->b_linep)) != bp->b_linep) lfree(lp); bp->b_dotp = bp->b_linep; /* Fix "." */ bp->b_doto = 0; bp->b_markp = NULL; /* Invalidate "mark" */ bp->b_marko = 0; return (TRUE); }