X-Git-Url: https://pd.if.org/git/?p=pd_readline;a=blobdiff_plain;f=mg%2Fbuffer.c;fp=mg%2Fbuffer.c;h=0a4254c4e60e312fc9f5f7b67d6ef231e3ff4360;hp=0000000000000000000000000000000000000000;hb=a9843085ec916c175bd245a8398f30e6cc03f984;hpb=26fe4e09c6c3c250334fdeed60ce3061febecde2 diff --git a/mg/buffer.c b/mg/buffer.c new file mode 100644 index 0000000..0a4254c --- /dev/null +++ b/mg/buffer.c @@ -0,0 +1,863 @@ +/* $OpenBSD: buffer.c,v 1.78 2012/03/14 13:56:35 lum Exp $ */ + +/* This file is in the public domain. */ + +/* + * Buffer handling. + */ + +#include "def.h" +#include "kbd.h" /* needed for modes */ + +#include +#include + +static struct buffer *makelist(void); +static struct buffer *bnew(const char *); + +static int usebufname(const char *); + +/* Flag for global working dir */ +extern int globalwd; + +/* ARGSUSED */ +int +togglereadonly(int f, int n) +{ + int s; + + if ((s = checkdirty(curbp)) != TRUE) + return (s); + if (!(curbp->b_flag & BFREADONLY)) + curbp->b_flag |= BFREADONLY; + else { + curbp->b_flag &= ~BFREADONLY; + if (curbp->b_flag & BFCHG) + ewprintf("Warning: Buffer was modified"); + } + curwp->w_rflag |= WFMODE; + + return (TRUE); +} + +/* Switch to the named buffer. + * If no name supplied, switch to the default (alternate) buffer. + */ +int +usebufname(const char *bufp) +{ + struct buffer *bp; + + if (bufp == NULL) + return (ABORT); + if (bufp[0] == '\0' && curbp->b_altb != NULL) + bp = curbp->b_altb; + else if ((bp = bfind(bufp, TRUE)) == NULL) + return (FALSE); + + /* and put it in current window */ + curbp = bp; + return (showbuffer(bp, curwp, WFFRAME | WFFULL)); +} + +/* + * 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. *scratch* is the default alternate + * buffer. + */ +/* ARGSUSED */ +int +usebuffer(int f, int n) +{ + char bufn[NBUFN], *bufp; + + /* Get buffer to use from user */ + if ((curbp->b_altb == NULL) && + ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL)) + bufp = eread("Switch to buffer: ", bufn, NBUFN, EFNEW | EFBUF); + else + bufp = eread("Switch to buffer: (default %s) ", bufn, NBUFN, + EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname); + + return (usebufname(bufp)); +} + +/* + * pop to buffer asked for by the user. + */ +/* ARGSUSED */ +int +poptobuffer(int f, int n) +{ + struct buffer *bp; + struct mgwin *wp; + char bufn[NBUFN], *bufp; + + /* Get buffer to use from user */ + if ((curbp->b_altb == NULL) && + ((curbp->b_altb = bfind("*scratch*", TRUE)) == NULL)) + bufp = eread("Switch to buffer in other window: ", bufn, NBUFN, + EFNEW | EFBUF); + else + bufp = eread("Switch to buffer in other window: (default %s) ", + bufn, NBUFN, EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname); + if (bufp == NULL) + return (ABORT); + if (bufp[0] == '\0' && curbp->b_altb != NULL) + bp = curbp->b_altb; + else if ((bp = bfind(bufn, TRUE)) == NULL) + return (FALSE); + if (bp == curbp) + return (splitwind(f, n)); + /* and put it in a new, non-ephemeral window */ + if ((wp = popbuf(bp, WNONE)) == NULL) + return (FALSE); + curbp = bp; + curwp = wp; + 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!). Clear the buffer (ask + * if the buffer has been changed). Then free the header + * line and the buffer header. Bound to "C-X k". + */ +/* ARGSUSED */ +int +killbuffer_cmd(int f, int n) +{ + struct buffer *bp; + char bufn[NBUFN], *bufp; + + if ((bufp = eread("Kill buffer: (default %s) ", bufn, NBUFN, + EFNUL | EFNEW | EFBUF, curbp->b_bname)) == NULL) + return (ABORT); + else if (bufp[0] == '\0') + bp = curbp; + else if ((bp = bfind(bufn, FALSE)) == NULL) + return (FALSE); + return (killbuffer(bp)); +} + +int +killbuffer(struct buffer *bp) +{ + struct buffer *bp1; + struct buffer *bp2; + struct mgwin *wp; + int s; + struct undo_rec *rec, *next; + + /* + * Find some other buffer to display. Try the alternate buffer, + * then the first different buffer in the buffer list. If there's + * only one buffer, create buffer *scratch* and make it the alternate + * buffer. Return if *scratch* is only buffer... + */ + if ((bp1 = bp->b_altb) == NULL) { + bp1 = (bp == bheadp) ? bp->b_bufp : bheadp; + if (bp1 == NULL) { + /* only one buffer. see if it's *scratch* */ + if (bp == bfind("*scratch*", FALSE)) + return (TRUE); + /* create *scratch* for alternate buffer */ + if ((bp1 = bfind("*scratch*", TRUE)) == NULL) + return (FALSE); + } + } + if ((s = bclear(bp)) != TRUE) + return (s); + for (wp = wheadp; bp->b_nwnd > 0; wp = wp->w_wndp) { + if (wp->w_bufp == bp) { + bp2 = bp1->b_altb; /* save alternate buffer */ + if (showbuffer(bp1, wp, WFMODE | WFFRAME | WFFULL)) + bp1->b_altb = bp2; + else + bp1 = bp2; + } + } + if (bp == curbp) + curbp = bp1; + free(bp->b_headp); /* Release header line. */ + bp2 = NULL; /* Find the header. */ + bp1 = bheadp; + while (bp1 != bp) { + if (bp1->b_altb == bp) + bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb; + bp2 = bp1; + bp1 = bp1->b_bufp; + } + bp1 = bp1->b_bufp; /* Next one in chain. */ + if (bp2 == NULL) /* Unlink it. */ + bheadp = bp1; + else + bp2->b_bufp = bp1; + while (bp1 != NULL) { /* Finish with altb's */ + if (bp1->b_altb == bp) + bp1->b_altb = (bp->b_altb == bp1) ? NULL : bp->b_altb; + bp1 = bp1->b_bufp; + } + rec = TAILQ_FIRST(&bp->b_undo); + + while (rec != NULL) { + next = TAILQ_NEXT(rec, next); + free_undo_record(rec); + rec = next; + } + + free(bp->b_bname); /* Release name block */ + free(bp); /* Release buffer block */ + return (TRUE); +} + +/* + * Save some buffers - just call anycb with the arg flag. + */ +/* ARGSUSED */ +int +savebuffers(int f, int n) +{ + if (anycb(f) == ABORT) + return (ABORT); + return (TRUE); +} + +/* + * Listing buffers. + */ +static int listbuf_ncol; + +static int listbuf_goto_buffer(int f, int n); +static int listbuf_goto_buffer_one(int f, int n); +static int listbuf_goto_buffer_helper(int f, int n, int only); + +static PF listbuf_pf[] = { + listbuf_goto_buffer +}; +static PF listbuf_one[] = { + listbuf_goto_buffer_one +}; + + +static struct KEYMAPE (2 + IMAPEXT) listbufmap = { + 2, + 2 + IMAPEXT, + rescan, + { + { + CCHR('M'), CCHR('M'), listbuf_pf, NULL + }, + { + '1', '1', listbuf_one, NULL + } + } +}; + +/* + * Display the buffer list. This is done + * in two parts. The "makelist" routine figures out + * the text, and puts it in a buffer. "popbuf" + * then pops the data onto the screen. Bound to + * "C-X C-B". + */ +/* ARGSUSED */ +int +listbuffers(int f, int n) +{ + static int initialized = 0; + struct buffer *bp; + struct mgwin *wp; + + if (!initialized) { + maps_add((KEYMAP *)&listbufmap, "listbufmap"); + initialized = 1; + } + + if ((bp = makelist()) == NULL || (wp = popbuf(bp, WNONE)) == NULL) + return (FALSE); + wp->w_dotp = bp->b_dotp; /* fix up if window already on screen */ + wp->w_doto = bp->b_doto; + bp->b_modes[0] = name_mode("fundamental"); + bp->b_modes[1] = name_mode("listbufmap"); + bp->b_nmodes = 1; + + return (TRUE); +} + +/* + * This routine rebuilds the text for the + * list buffers command. Return pointer + * to new list if everything works. + * Return NULL if there is an error (if + * there is no memory). + */ +static struct buffer * +makelist(void) +{ + int w = ncol / 2; + struct buffer *bp, *blp; + struct line *lp; + + if ((blp = bfind("*Buffer List*", TRUE)) == NULL) + return (NULL); + if (bclear(blp) != TRUE) + return (NULL); + blp->b_flag &= ~BFCHG; /* Blow away old. */ + blp->b_flag |= BFREADONLY; + + listbuf_ncol = ncol; /* cache ncol for listbuf_goto_buffer */ + + if (addlinef(blp, "%-*s%s", w, " MR Buffer", "Size File") == FALSE || + addlinef(blp, "%-*s%s", w, " -- ------", "---- ----") == FALSE) + return (NULL); + + for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { + RSIZE nbytes; + + nbytes = 0; /* Count bytes in buf. */ + if (bp != blp) { + lp = bfirstlp(bp); + while (lp != bp->b_headp) { + nbytes += llength(lp) + 1; + lp = lforw(lp); + } + if (nbytes) + nbytes--; /* no bonus newline */ + } + + if (addlinef(blp, "%c%c%c %-*.*s%c%-6d %-*s", + (bp == curbp) ? '.' : ' ', /* current buffer ? */ + ((bp->b_flag & BFCHG) != 0) ? '*' : ' ', /* changed ? */ + ((bp->b_flag & BFREADONLY) != 0) ? ' ' : '*', + w - 5, /* four chars already written */ + w - 5, /* four chars already written */ + bp->b_bname, /* buffer name */ + strlen(bp->b_bname) < w - 5 ? ' ' : '$', /* truncated? */ + nbytes, /* buffer size */ + w - 7, /* seven chars already written */ + bp->b_fname) == FALSE) + return (NULL); + } + blp->b_dotp = bfirstlp(blp); /* put dot at beginning of + * buffer */ + blp->b_doto = 0; + return (blp); /* All done */ +} + +static int +listbuf_goto_buffer(int f, int n) +{ + return (listbuf_goto_buffer_helper(f, n, 0)); +} + +static int +listbuf_goto_buffer_one(int f, int n) +{ + return (listbuf_goto_buffer_helper(f, n, 1)); +} + +static int +listbuf_goto_buffer_helper(int f, int n, int only) +{ + struct buffer *bp; + struct mgwin *wp; + char *line = NULL; + int i, ret = FALSE; + + if (curwp->w_dotp->l_text[listbuf_ncol/2 - 1] == '$') { + ewprintf("buffer name truncated"); + return (FALSE); + } + + if ((line = malloc(listbuf_ncol/2)) == NULL) + return (FALSE); + + memcpy(line, curwp->w_dotp->l_text + 4, listbuf_ncol/2 - 5); + for (i = listbuf_ncol/2 - 6; i > 0; i--) { + if (line[i] != ' ') { + line[i + 1] = '\0'; + break; + } + } + if (i == 0) + goto cleanup; + + for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { + if (strcmp(bp->b_bname, line) == 0) + break; + } + if (bp == NULL) + goto cleanup; + + if ((wp = popbuf(bp, WNONE)) == NULL) + goto cleanup; + curbp = bp; + curwp = wp; + + if (only) + ret = (onlywind(f, n)); + else + ret = TRUE; + +cleanup: + free(line); + + return (ret); +} + +/* + * The argument "fmt" points to a format string. Append this line to the + * buffer. Handcraft the EOL on the end. Return TRUE if it worked and + * FALSE if you ran out of room. + */ +int +addlinef(struct buffer *bp, char *fmt, ...) +{ + va_list ap; + struct line *lp; + + if ((lp = lalloc(0)) == NULL) + return (FALSE); + va_start(ap, fmt); + if (vasprintf(&lp->l_text, fmt, ap) == -1) { + lfree(lp); + va_end(ap); + return (FALSE); + } + lp->l_used = strlen(lp->l_text); + va_end(ap); + + bp->b_headp->l_bp->l_fp = lp; /* Hook onto the end */ + lp->l_bp = bp->b_headp->l_bp; + bp->b_headp->l_bp = lp; + lp->l_fp = bp->b_headp; + bp->b_lines++; + + return (TRUE); +} + +/* + * Look through the list of buffers, giving the user a chance to save them. + * Return TRUE if there are any changed buffers afterwards. Buffers that don't + * have an associated file don't count. Return FALSE if there are no changed + * buffers. Return ABORT if an error occurs or if the user presses c-g. + */ +int +anycb(int f) +{ + struct buffer *bp; + int s = FALSE, save = FALSE, ret; + char pbuf[NFILEN + 11]; + + for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { + if (bp->b_fname != NULL && *(bp->b_fname) != '\0' && + (bp->b_flag & BFCHG) != 0) { + ret = snprintf(pbuf, sizeof(pbuf), "Save file %s", + bp->b_fname); + if (ret < 0 || ret >= sizeof(pbuf)) { + ewprintf("Error: filename too long!"); + return (ABORT); + } + if ((f == TRUE || (save = eyorn(pbuf)) == TRUE) && + buffsave(bp) == TRUE) { + bp->b_flag &= ~BFCHG; + upmodes(bp); + } else + s = TRUE; + if (save == ABORT) + return (save); + save = TRUE; + } + } + if (save == FALSE /* && kbdmop == NULL */ ) /* experimental */ + ewprintf("(No files need saving)"); + return (s); +} + +/* + * Search for a buffer, by name. + * If not found, and the "cflag" is TRUE, + * create a new buffer. Return pointer to the found + * (or new) buffer. + */ +struct buffer * +bfind(const char *bname, int cflag) +{ + struct buffer *bp; + + bp = bheadp; + while (bp != NULL) { + if (strcmp(bname, bp->b_bname) == 0) + return (bp); + bp = bp->b_bufp; + } + if (cflag != TRUE) + return (NULL); + + bp = bnew(bname); + + return (bp); +} + +/* + * Create a new buffer and put it in the list of + * all buffers. + */ +static struct buffer * +bnew(const char *bname) +{ + struct buffer *bp; + struct line *lp; + int i; + size_t len; + + bp = calloc(1, sizeof(struct buffer)); + if (bp == NULL) { + ewprintf("Can't get %d bytes", sizeof(struct buffer)); + return (NULL); + } + if ((lp = lalloc(0)) == NULL) { + free(bp); + return (NULL); + } + bp->b_altb = bp->b_bufp = NULL; + bp->b_dotp = lp; + bp->b_doto = 0; + bp->b_markp = NULL; + bp->b_marko = 0; + bp->b_flag = defb_flag; + /* if buffer name starts and ends with '*', we ignore changes */ + len = strlen(bname); + if (len) { + if (bname[0] == '*' && bname[len - 1] == '*') + bp->b_flag |= BFIGNDIRTY; + } + bp->b_nwnd = 0; + bp->b_headp = lp; + bp->b_nmodes = defb_nmodes; + TAILQ_INIT(&bp->b_undo); + bp->b_undoptr = NULL; + memset(&bp->b_undopos, 0, sizeof(bp->b_undopos)); + i = 0; + do { + bp->b_modes[i] = defb_modes[i]; + } while (i++ < defb_nmodes); + bp->b_fname[0] = '\0'; + bp->b_cwd[0] = '\0'; + bzero(&bp->b_fi, sizeof(bp->b_fi)); + lp->l_fp = lp; + lp->l_bp = lp; + bp->b_bufp = bheadp; + bheadp = bp; + bp->b_dotline = bp->b_markline = 1; + bp->b_lines = 1; + if ((bp->b_bname = strdup(bname)) == NULL) { + ewprintf("Can't get %d bytes", strlen(bname) + 1); + return (NULL); + } + + 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. + */ +int +bclear(struct buffer *bp) +{ + struct line *lp; + int s; + + /* Has buffer changed, and do we care? */ + if (!(bp->b_flag & BFIGNDIRTY) && (bp->b_flag & BFCHG) != 0 && + (s = eyesno("Buffer modified; kill anyway")) != TRUE) + return (s); + bp->b_flag &= ~BFCHG; /* Not changed */ + while ((lp = lforw(bp->b_headp)) != bp->b_headp) + lfree(lp); + bp->b_dotp = bp->b_headp; /* Fix dot */ + bp->b_doto = 0; + bp->b_markp = NULL; /* Invalidate "mark" */ + bp->b_marko = 0; + bp->b_dotline = bp->b_markline = 1; + bp->b_lines = 1; + + return (TRUE); +} + +/* + * Display the given buffer in the given window. Flags indicated + * action on redisplay. Update modified flag so insert loop can check it. + */ +int +showbuffer(struct buffer *bp, struct mgwin *wp, int flags) +{ + struct buffer *obp; + struct mgwin *owp; + + /* Ensure file has not been modified elsewhere */ + if (fchecktime(bp) != TRUE) + bp->b_flag |= BFDIRTY; + + if (wp->w_bufp == bp) { /* Easy case! */ + wp->w_rflag |= flags; + wp->w_dotp = bp->b_dotp; + wp->w_doto = bp->b_doto; + return (TRUE); + } + /* First, detach the old buffer from the window */ + if ((bp->b_altb = obp = wp->w_bufp) != NULL) { + if (--obp->b_nwnd == 0) { + obp->b_dotp = wp->w_dotp; + obp->b_doto = wp->w_doto; + obp->b_markp = wp->w_markp; + obp->b_marko = wp->w_marko; + obp->b_dotline = wp->w_dotline; + obp->b_markline = wp->w_markline; + } + } + /* Now, attach the new buffer to the window */ + wp->w_bufp = bp; + + if (bp->b_nwnd++ == 0) { /* First use. */ + wp->w_dotp = bp->b_dotp; + wp->w_doto = bp->b_doto; + wp->w_markp = bp->b_markp; + wp->w_marko = bp->b_marko; + wp->w_dotline = bp->b_dotline; + wp->w_markline = bp->b_markline; + } else + /* already on screen, steal values from other window */ + for (owp = wheadp; owp != NULL; owp = wp->w_wndp) + if (wp->w_bufp == bp && owp != wp) { + wp->w_dotp = owp->w_dotp; + wp->w_doto = owp->w_doto; + wp->w_markp = owp->w_markp; + wp->w_marko = owp->w_marko; + wp->w_dotline = owp->w_dotline; + wp->w_markline = owp->w_markline; + break; + } + wp->w_rflag |= WFMODE | flags; + return (TRUE); +} + +/* + * Augment a buffer name with a number, if necessary + * + * If more than one file of the same basename() is open, + * the additional buffers are named "file<2>", "file<3>", and + * so forth. This function adjusts a buffer name to + * include the number, if necessary. + */ +int +augbname(char *bn, const char *fn, size_t bs) +{ + int count; + size_t remain, len; + + if ((len = xbasename(bn, fn, bs)) >= bs) + return (FALSE); + + remain = bs - len; + for (count = 2; bfind(bn, FALSE) != NULL; count++) + snprintf(bn + len, remain, "<%d>", count); + + return (TRUE); +} + +/* + * Pop the buffer we got passed onto the screen. + * Returns a status. + */ +struct mgwin * +popbuf(struct buffer *bp, int flags) +{ + struct mgwin *wp; + + if (bp->b_nwnd == 0) { /* Not on screen yet. */ + /* + * Pick a window for a pop-up. + * If only one window, split the screen. + * Flag the new window as ephemeral + */ + if (wheadp->w_wndp == NULL && + splitwind(FFOTHARG, flags) == FALSE) + return (NULL); + + /* + * Pick the uppermost window that isn't + * the current window. An LRU algorithm + * might be better. Return a pointer, or NULL on error. + */ + wp = wheadp; + + while (wp != NULL && wp == curwp) + wp = wp->w_wndp; + } else + for (wp = wheadp; wp != NULL; wp = wp->w_wndp) + if (wp->w_bufp == bp) { + wp->w_rflag |= WFFULL | WFFRAME; + return (wp); + } + if (showbuffer(bp, wp, WFFULL) != TRUE) + return (NULL); + return (wp); +} + +/* + * Insert another buffer at dot. Very useful. + */ +/* ARGSUSED */ +int +bufferinsert(int f, int n) +{ + struct buffer *bp; + struct line *clp; + int clo, nline; + char bufn[NBUFN], *bufp; + + /* Get buffer to use from user */ + if (curbp->b_altb != NULL) + bufp = eread("Insert buffer: (default %s) ", bufn, NBUFN, + EFNUL | EFNEW | EFBUF, curbp->b_altb->b_bname); + else + bufp = eread("Insert buffer: ", bufn, NBUFN, EFNEW | EFBUF); + if (bufp == NULL) + return (ABORT); + if (bufp[0] == '\0' && curbp->b_altb != NULL) + bp = curbp->b_altb; + else if ((bp = bfind(bufn, FALSE)) == NULL) + return (FALSE); + + if (bp == curbp) { + ewprintf("Cannot insert buffer into self"); + return (FALSE); + } + /* insert the buffer */ + nline = 0; + clp = bfirstlp(bp); + for (;;) { + for (clo = 0; clo < llength(clp); clo++) + if (linsert(1, lgetc(clp, clo)) == FALSE) + return (FALSE); + if ((clp = lforw(clp)) == bp->b_headp) + break; + if (newline(FFRAND, 1) == FALSE) /* fake newline */ + return (FALSE); + nline++; + } + if (nline == 1) + ewprintf("[Inserted 1 line]"); + else + ewprintf("[Inserted %d lines]", nline); + + clp = curwp->w_linep; /* cosmetic adjustment */ + if (curwp->w_dotp == clp) { /* for offscreen insert */ + while (nline-- && lback(clp) != curbp->b_headp) + clp = lback(clp); + curwp->w_linep = clp; /* adjust framing. */ + curwp->w_rflag |= WFFULL; + } + return (TRUE); +} + +/* + * Turn off the dirty bit on this buffer. + */ +/* ARGSUSED */ +int +notmodified(int f, int n) +{ + struct mgwin *wp; + + curbp->b_flag &= ~BFCHG; + wp = wheadp; /* Update mode lines. */ + while (wp != NULL) { + if (wp->w_bufp == curbp) + wp->w_rflag |= WFMODE; + wp = wp->w_wndp; + } + ewprintf("Modification-flag cleared"); + return (TRUE); +} + +/* + * Popbuf and set all windows to top of buffer. + */ +int +popbuftop(struct buffer *bp, int flags) +{ + struct mgwin *wp; + + bp->b_dotp = bfirstlp(bp); + bp->b_doto = 0; + if (bp->b_nwnd != 0) { + for (wp = wheadp; wp != NULL; wp = wp->w_wndp) + if (wp->w_bufp == bp) { + wp->w_dotp = bp->b_dotp; + wp->w_doto = 0; + wp->w_rflag |= WFFULL; + } + } + return (popbuf(bp, flags) != NULL); +} + +/* + * Return the working directory for the current buffer, terminated + * with a '/'. First, try to extract it from the current buffer's + * filename. If that fails, use global cwd. + */ +int +getbufcwd(char *path, size_t plen) +{ + char cwd[NFILEN]; + + if (plen == 0) + return (FALSE); + + if (globalwd == FALSE && curbp->b_cwd[0] != '\0') { + (void)strlcpy(path, curbp->b_cwd, plen); + } else { + if (getcwdir(cwd, sizeof(cwd)) == FALSE) + goto error; + (void)strlcpy(path, cwd, plen); + } + return (TRUE); +error: + path[0] = '\0'; + return (FALSE); +} + +/* + * Ensures a buffer has not been modified elsewhere; e.g. on disk. + * Prompt the user if it has. + * Returns TRUE if it has NOT (i.e. buffer is ok to edit). + * FALSE or ABORT otherwise + */ +int +checkdirty(struct buffer *bp) +{ + int s; + + if ((bp->b_flag & (BFDIRTY | BFIGNDIRTY)) == BFDIRTY) { + if ((s = eyorn("File changed on disk; really edit the buffer")) + != TRUE) + return (s); + bp->b_flag &= ~BFDIRTY; + bp->b_flag |= BFIGNDIRTY; + } + + return (TRUE); +} +