/* * 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, save2 = FALSE, ret; char pbuf[NFILEN + 11]; for (bp = bheadp; bp != NULL; bp = bp->b_bufp) { if (*(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)) { dobeep(); ewprintf("Error: filename too long!"); return (UERROR); } if ((f == TRUE || (save = eyorn(pbuf)) == TRUE) && (save2 = buffsave(bp)) == TRUE) { bp->b_flag &= ~BFCHG; upmodes(bp); } else { if (save2 == FIOERR) return (save2); s = TRUE; } if (save == ABORT) return (save); save = TRUE; } } if (save == FALSE /* && kbdmop == NULL */ ) /* experimental */ ewprintf("(No files need saving)"); return (s); }
/* ARGSUSED */ int backchar(int f, int n) { struct line *lp; if (n < 0) return (forwchar(f, -n)); while (n--) { if (curwp->w_doto == 0) { if ((lp = lback(curwp->w_dotp)) == curbp->b_headp) { if (!(f & FFRAND)) { dobeep(); ewprintf("Beginning of buffer"); } return (FALSE); } curwp->w_dotp = lp; curwp->w_doto = llength(lp); curwp->w_rflag |= WFMOVE; curwp->w_dotline--; } else curwp->w_doto--; } return (TRUE); }
int dorevert(void) { int lineno; struct undo_rec *rec; if (access(curbp->b_fname, F_OK|R_OK) != 0) { dobeep(); if (errno == ENOENT) ewprintf("File %s no longer exists!", curbp->b_fname); else ewprintf("File %s is no longer readable!", curbp->b_fname); return (FALSE); } /* Save our current line, so we can go back after reloading. */ lineno = curwp->w_dotline; /* Prevent readin from asking if we want to kill the buffer. */ curbp->b_flag &= ~BFCHG; /* Clean up undo memory */ while ((rec = TAILQ_FIRST(&curbp->b_undo))) { TAILQ_REMOVE(&curbp->b_undo, rec, next); free_undo_record(rec); } if (readin(curbp->b_fname)) return(setlineno(lineno)); return (FALSE); }
/* * Set fill column to n for justify. */ int setfillcol(int f, int n) { char buf[32], *rep; const char *es; int nfill; if ((f & FFARG) != 0) { fillcol = n; } else { if ((rep = eread("Set fill-column: ", buf, sizeof(buf), EFNEW | EFCR)) == NULL) return (ABORT); else if (rep[0] == '\0') return (FALSE); nfill = strtonum(rep, 0, INT_MAX, &es); if (es != NULL) { dobeep(); ewprintf("Invalid fill column: %s", rep); return (FALSE); } fillcol = nfill; ewprintf("Fill column set to %d", fillcol); } return (TRUE); }
/* * Write a buffer to the already opened file. bp points to the * buffer. Return the status. */ int ffputbuf(FILE *ffp, struct buffer *bp) { struct line *lp, *lpend; lpend = bp->b_headp; for (lp = lforw(lpend); lp != lpend; lp = lforw(lp)) { if (fwrite(ltext(lp), 1, llength(lp), ffp) != llength(lp)) { dobeep(); ewprintf("Write I/O error"); return (FIOERR); } if (lforw(lp) != lpend) /* no implied \n on last line */ putc('\n', ffp); } /* * XXX should be variable controlled (once we have variables) */ if (llength(lback(lpend)) != 0) { if (eyorn("No newline at end of file, add one") == TRUE) { lnewline_at(lback(lpend), llength(lback(lpend))); putc('\n', ffp); } } return (FIOSUC); }
/* * tags line is of the format "<tag>\t<filename>\t<pattern>". Split them * by replacing '\t' with '\0'. This wouldn't alter the size of malloc'ed * l, and can be freed during cleanup. */ int addctag(char *l) { struct ctag *t; if ((t = malloc(sizeof(struct ctag))) == NULL) { dobeep(); ewprintf("Out of memory"); return (FALSE); } t->tag = l; if ((l = strchr(l, '\t')) == NULL) goto cleanup; *l++ = '\0'; t->fname = l; if ((l = strchr(l, '\t')) == NULL) goto cleanup; *l++ = '\0'; if (*l == '\0') goto cleanup; t->pat = strip(l, strlen(l)); RB_INSERT(tagtree, &tags, t); return (TRUE); cleanup: free(t); free(l); return (TRUE); }
/* ARGSUSED */ int poptag(int f, int n) { struct line *dotp; struct tagpos *s; if (SLIST_EMPTY(&shead)) { dobeep(); ewprintf("No previous location for find-tag invocation"); return (FALSE); } s = SLIST_FIRST(&shead); SLIST_REMOVE_HEAD(&shead, entry); if (loadbuffer(s->bname) == FALSE) return (FALSE); curwp->w_dotline = s->dotline; curwp->w_doto = s->doto; /* storing of dotp in tagpos wouldn't work out in cases when * that buffer is killed by user(dangling pointer). Explicitly * traverse till dotline for correct handling. */ dotp = curwp->w_bufp->b_headp; while (s->dotline--) dotp = dotp->l_fp; curwp->w_dotp = dotp; free(s->bname); free(s); return (TRUE); }
/* ARGSUSED */ int do_redraw(int f, int n, int force) { struct mgwin *wp; int oldnrow, oldncol; oldnrow = nrow; oldncol = ncol; ttresize(); if (nrow != oldnrow || ncol != oldncol || force) { /* find last */ wp = wheadp; while (wp->w_wndp != NULL) wp = wp->w_wndp; /* check if too small */ if (nrow < wp->w_toprow + 3) { dobeep(); ewprintf("Display unusable"); return (FALSE); } wp->w_ntrows = nrow - wp->w_toprow - 2; sgarbf = TRUE; update(CMODE); } else sgarbf = TRUE; return (TRUE); }
/* ARGSUSED */ int enlargewind(int f, int n) { struct mgwin *adjwp; struct line *lp; int i; if (n < 0) return (shrinkwind(f, -n)); if (wheadp->w_wndp == NULL) { dobeep(); ewprintf("Only one window"); return (FALSE); } if ((adjwp = curwp->w_wndp) == NULL) { adjwp = wheadp; while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp; } if (adjwp->w_ntrows <= n) { dobeep(); ewprintf("Impossible change"); return (FALSE); } /* shrink below */ if (curwp->w_wndp == adjwp) { lp = adjwp->w_linep; for (i = 0; i < n && lp != adjwp->w_bufp->b_headp; ++i) lp = lforw(lp); adjwp->w_linep = lp; adjwp->w_toprow += n; /* shrink above */ } else { lp = curwp->w_linep; for (i = 0; i < n && lback(lp) != curbp->b_headp; ++i) lp = lback(lp); curwp->w_linep = lp; curwp->w_toprow -= n; } curwp->w_ntrows += n; adjwp->w_ntrows -= n; curwp->w_rflag |= WFMODE | WFFULL; adjwp->w_rflag |= WFMODE | WFFULL; return (TRUE); }
/* * Set size, and check for overflow. */ static int setsize(struct region *rp, RSIZE size) { rp->r_size = size; if (rp->r_size != size) { dobeep(); ewprintf("Region is too large"); return (FALSE); } return (TRUE); }
/* ARGSUSED */ int filewrite(int f, int n) { struct stat statbuf; int s; char fname[NFILEN], bn[NBUFN], tmp[NFILEN + 25]; char *adjfname, *bufp; FILE *ffp; if (getbufcwd(fname, sizeof(fname)) != TRUE) fname[0] = '\0'; if ((bufp = eread("Write file: ", fname, NFILEN, EFDEF | EFNEW | EFCR | EFFILE)) == NULL) return (ABORT); else if (bufp[0] == '\0') return (FALSE); adjfname = adjustname(fname, TRUE); if (adjfname == NULL) return (FALSE); /* Check if file exists; write checks done later */ if (stat(adjfname, &statbuf) == 0) { if (S_ISDIR(statbuf.st_mode)) { dobeep(); ewprintf("%s is a directory", adjfname); return (FALSE); } snprintf(tmp, sizeof(tmp), "File `%s' exists; overwrite", adjfname); if ((s = eyorn(tmp)) != TRUE) return (s); } /* old attributes are no longer current */ bzero(&curbp->b_fi, sizeof(curbp->b_fi)); if ((s = writeout(&ffp, curbp, adjfname)) == TRUE) { (void)strlcpy(curbp->b_fname, adjfname, sizeof(curbp->b_fname)); if (getbufcwd(curbp->b_cwd, sizeof(curbp->b_cwd)) != TRUE) (void)strlcpy(curbp->b_cwd, "/", sizeof(curbp->b_cwd)); if (augbname(bn, curbp->b_fname, sizeof(bn)) == FALSE) return (FALSE); free(curbp->b_bname); if ((curbp->b_bname = strdup(bn)) == NULL) return (FALSE); (void)fupdstat(curbp); curbp->b_flag &= ~BFCHG; upmodes(curbp); undo_add_boundary(FFRAND, 1); undo_add_modified(); } return (s); }
/* ARGSUSED */ int next_error(int f, int n) { if (compile_win == NULL || compile_buffer == NULL) { dobeep(); ewprintf("No compilation active"); return (FALSE); } curwp = compile_win; curbp = compile_buffer; if (curwp->w_dotp == blastlp(curbp)) { dobeep(); ewprintf("No more hits"); return (FALSE); } curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_rflag |= WFMOVE; return (compile_goto_error(f, n)); }
/* * Create a socketpair, fork and execv path with argv. * STDIN, STDOUT and STDERR of child process are redirected to socket. * Parent writes len chars from text to socket. */ int pipeio(const char* const path, char* const argv[], char* const text, int len, struct buffer *outbp) { int s[2]; char *err; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s) == -1) { dobeep(); ewprintf("socketpair error"); return (FALSE); } switch(fork()) { case -1: dobeep(); ewprintf("Can't fork"); return (FALSE); case 0: /* Child process */ close(s[0]); if (dup2(s[1], STDIN_FILENO) == -1) _exit(1); if (dup2(s[1], STDOUT_FILENO) == -1) _exit(1); if (dup2(s[1], STDERR_FILENO) == -1) _exit(1); if (path == NULL) _exit(1); execv(path, argv); err = strerror(errno); write(s[1], err, strlen(err)); _exit(1); default: /* Parent process */ close(s[1]); return (iomux(s[0], text, len, outbp)); } return (FALSE); }
/* 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) { dobeep(); 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 (enewline(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); }
/*ARGSUSED */ int piperegion(int f, int n) { struct region region; int len; char *cmd, cmdbuf[NFILEN], *text; char *argv[] = {"sh", "-c", (char *) NULL, (char *) NULL}; /* C-u M-| is not supported yet */ if (n > 1) return (ABORT); if (curwp->w_markp == NULL) { dobeep(); ewprintf("The mark is not set now, so there is no region"); return (FALSE); } if ((cmd = eread("Shell command on region: ", cmdbuf, sizeof(cmdbuf), EFNEW | EFCR)) == NULL || (cmd[0] == '\0')) return (ABORT); argv[2] = cmd; if (getregion(®ion) != TRUE) return (FALSE); len = region.r_size; if ((text = malloc(len + 1)) == NULL) { dobeep(); ewprintf("Cannot allocate memory."); return (FALSE); } region_get_data(®ion, text, len); return shellcmdoutput(argv, text, len); }
/* * Search tagstree for a given token. */ struct ctag * searchtag(char *tok) { struct ctag t, *res; t.tag = tok; if ((res = RB_FIND(tagtree, &tags, &t)) == NULL) { dobeep(); ewprintf("No tag containing %s", tok); return (NULL); } return res; }
/* ARGSUSED */ int forwline(int f, int n) { struct line *dlp; if (n < 0) return (backline(f | FFRAND, -n)); if ((dlp = curwp->w_dotp) == curbp->b_headp) { if (!(f & FFRAND)) { dobeep(); ewprintf("End of buffer"); } return(TRUE); } if ((lastflag & CFCPCN) == 0) /* Fix goal. */ setgoal(); thisflag |= CFCPCN; if (n == 0) return (TRUE); while (n--) { dlp = lforw(dlp); if (dlp == curbp->b_headp) { curwp->w_dotp = lback(dlp); curwp->w_doto = llength(curwp->w_dotp); curwp->w_rflag |= WFMOVE; if (!(f & FFRAND)) { dobeep(); ewprintf("End of buffer"); } return (TRUE); } curwp->w_dotline++; } curwp->w_rflag |= WFMOVE; curwp->w_dotp = dlp; curwp->w_doto = getgoal(dlp); return (TRUE); }
/* * This function performs the details of file writing; writing the file * in buffer bp to file fn. Uses the file management routines in the * "fileio.c" package. Most of the grief is checking of some sort. * You may want to call fupdstat() after using this function. */ int writeout(FILE ** ffp, struct buffer *bp, char *fn) { struct stat statbuf; int s; char dp[NFILEN]; if (stat(fn, &statbuf) == -1 && errno == ENOENT) { errno = 0; (void)xdirname(dp, fn, sizeof(dp)); (void)strlcat(dp, "/", sizeof(dp)); if (access(dp, W_OK) && errno == EACCES) { dobeep(); ewprintf("Directory %s write-protected", dp); return (FIOERR); } else if (errno == ENOENT) { dobeep(); ewprintf("%s: no such directory", dp); return (FIOERR); } } /* open writes message */ if ((s = ffwopen(ffp, fn, bp)) != FIOSUC) return (FALSE); s = ffputbuf(*ffp, bp); if (s == FIOSUC) { /* no write error */ s = ffclose(*ffp, bp); if (s == FIOSUC) ewprintf("Wrote %s", fn); } else { /* print a message indicating write error */ (void)ffclose(*ffp, bp); dobeep(); ewprintf("Unable to write %s", fn); } return (s == FIOSUC); }
/* * Hack to show matching paren. Self-insert character, then show matching * character, if any. Bound to "blink-and-insert". */ int showmatch(int f, int n) { int i, s; for (i = 0; i < n; i++) { if ((s = selfinsert(FFRAND, 1)) != TRUE) return (s); /* unbalanced -- warn user */ if (balance() != TRUE) dobeep(); } return (TRUE); }
/* ARGSUSED */ int searchagain(int f, int n) { if (srch_lastdir == SRCH_FORW) { if (forwsrch() == FALSE) { dobeep(); ewprintf("Search failed: \"%s\"", pat); return (FALSE); } return (TRUE); } if (srch_lastdir == SRCH_BACK) { if (backsrch() == FALSE) { dobeep(); ewprintf("Search failed: \"%s\"", pat); return (FALSE); } return (TRUE); } dobeep(); ewprintf("No last search"); return (FALSE); }
/* * Open a file for writing. */ int ffwopen(FILE ** ffp, const char *fn, struct buffer *bp) { int fd; mode_t fmode = DEFFILEMODE; if (bp && bp->b_fi.fi_mode) fmode = bp->b_fi.fi_mode & 07777; fd = open(fn, O_RDWR | O_CREAT | O_TRUNC, fmode); if (fd == -1) { ffp = NULL; dobeep(); ewprintf("Cannot open file for writing : %s", strerror(errno)); return (FIOERR); } if ((*ffp = fdopen(fd, "w")) == NULL) { dobeep(); ewprintf("Cannot open file for writing : %s", strerror(errno)); close(fd); return (FIOERR); } /* * If we have file information, use it. We don't bother to check for * errors, because there's no a lot we can do about it. Certainly * trying to change ownership will fail if we aren't root. That's * probably OK. If we don't have info, no need to get it, since any * future writes will do the same thing. */ if (bp && bp->b_fi.fi_mode) { fchmod(fd, bp->b_fi.fi_mode & 07777); fchown(fd, bp->b_fi.fi_uid, bp->b_fi.fi_gid); } return (FIOSUC); }
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] == '$') { dobeep(); 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(FFRAND, 1)); else ret = TRUE; cleanup: free(line); return (ret); }
int copy(char *frname, char *toname) { int ifd, ofd; char buf[BUFSIZ]; mode_t fmode = DEFFILEMODE; /* XXX?? */ struct stat orig; ssize_t sr; if ((ifd = open(frname, O_RDONLY)) == -1) return (FALSE); if (fstat(ifd, &orig) == -1) { dobeep(); ewprintf("fstat: %s", strerror(errno)); close(ifd); return (FALSE); } if ((ofd = open(toname, O_WRONLY|O_CREAT|O_TRUNC, fmode)) == -1) { close(ifd); return (FALSE); } while ((sr = read(ifd, buf, sizeof(buf))) > 0) { if (write(ofd, buf, (size_t)sr) != sr) { ewprintf("write error : %s", strerror(errno)); break; } } if (fchmod(ofd, orig.st_mode) == -1) ewprintf("Cannot set original mode : %s", strerror(errno)); if (sr == -1) { ewprintf("Read error : %s", strerror(errno)); close(ifd); close(ofd); return (FALSE); } /* * It is "normal" for this to fail since we can't guarantee that * we will be running as root. */ if (fchown(ofd, orig.st_uid, orig.st_gid) && errno != EPERM) ewprintf("Cannot set owner : %s", strerror(errno)); (void) close(ifd); (void) close(ofd); return (TRUE); }
/* ARGSUSED */ int delbword(int f, int n) { RSIZE size; int s; if ((s = checkdirty(curbp)) != TRUE) return (s); if (curbp->b_flag & BFREADONLY) { dobeep(); ewprintf("Buffer is read-only"); return (FALSE); } if (n < 0) return (FALSE); /* purge kill buffer */ if ((lastflag & CFKILL) == 0) kdelete(); thisflag |= CFKILL; if (backchar(FFRAND, 1) == FALSE) /* hit buffer start */ return (TRUE); /* one deleted */ size = 1; while (n--) { while (inword() == FALSE) { if (backchar(FFRAND, 1) == FALSE) /* hit buffer start */ goto out; ++size; } while (inword() != FALSE) { if (backchar(FFRAND, 1) == FALSE) /* hit buffer start */ goto out; ++size; } } if (forwchar(FFRAND, 1) == FALSE) return (FALSE); /* undo assumed delete */ --size; out: return (ldelete(size, KBACK)); }
/* ARGSUSED */ int backsearch(int f, int n) { int s; if ((s = readpattern("Search backward")) != TRUE) return (s); if (backsrch() == FALSE) { dobeep(); ewprintf("Search failed: \"%s\"", pat); return (FALSE); } srch_lastdir = SRCH_BACK; return (TRUE); }
/* ARGSUSED */ int forwsearch(int f, int n) { int s; if ((s = readpattern("Search")) != TRUE) return (s); if (forwsrch() == FALSE) { dobeep(); ewprintf("Search failed: \"%s\"", pat); return (FALSE); } srch_lastdir = SRCH_FORW; return (TRUE); }
/* ARGSUSED */ int capword(int f, int n) { int c, s; RSIZE size; if ((s = checkdirty(curbp)) != TRUE) return (s); if (curbp->b_flag & BFREADONLY) { dobeep(); ewprintf("Buffer is read-only"); return (FALSE); } if (n < 0) return (FALSE); while (n--) { while (inword() == FALSE) { if (forwchar(FFRAND, 1) == FALSE) return (TRUE); } size = countfword(); undo_add_change(curwp->w_dotp, curwp->w_doto, size); if (inword() != FALSE) { c = lgetc(curwp->w_dotp, curwp->w_doto); if (ISLOWER(c) != FALSE) { c = TOUPPER(c); lputc(curwp->w_dotp, curwp->w_doto, c); lchange(WFFULL); } if (forwchar(FFRAND, 1) == FALSE) return (TRUE); while (inword() != FALSE) { c = lgetc(curwp->w_dotp, curwp->w_doto); if (ISUPPER(c) != FALSE) { c = TOLOWER(c); lputc(curwp->w_dotp, curwp->w_doto, c); lchange(WFFULL); } if (forwchar(FFRAND, 1) == FALSE) return (TRUE); } } } return (TRUE); }
/* ARGSUSED */ int delfword(int f, int n) { RSIZE size; struct line *dotp; int doto; int s; if ((s = checkdirty(curbp)) != TRUE) return (s); if (curbp->b_flag & BFREADONLY) { dobeep(); ewprintf("Buffer is read-only"); return (FALSE); } if (n < 0) return (FALSE); /* purge kill buffer */ if ((lastflag & CFKILL) == 0) kdelete(); thisflag |= CFKILL; dotp = curwp->w_dotp; doto = curwp->w_doto; size = 0; while (n--) { while (inword() == FALSE) { if (forwchar(FFRAND, 1) == FALSE) /* hit the end of the buffer */ goto out; ++size; } while (inword() != FALSE) { if (forwchar(FFRAND, 1) == FALSE) /* hit the end of the buffer */ goto out; ++size; } } out: curwp->w_dotp = dotp; curwp->w_doto = doto; return (ldelete(size, KFORW)); }
/* * Page the other window. Check to make sure it exists, then * nextwind, forwpage and restore window pointers. */ int pagenext(int f, int n) { struct mgwin *wp; if (wheadp->w_wndp == NULL) { dobeep(); ewprintf("No other window"); return (FALSE); } wp = curwp; (void) nextwind(f, n); (void) forwpage(f, n); curwp = wp; curbp = wp->w_bufp; return (TRUE); }
/* * Save the contents of the buffer argument into its associated file. Do * nothing if there have been no changes (is this a bug, or a feature?). * Error if there is no remembered file name. If this is the first write * since the read or visit, then a backup copy of the file is made. * Allow user to select whether or not to make backup files by looking at * the value of makebackup. */ int buffsave(struct buffer *bp) { int s; FILE *ffp; /* return, no changes */ if ((bp->b_flag & BFCHG) == 0) { ewprintf("(No changes need to be saved)"); return (TRUE); } /* must have a name */ if (bp->b_fname[0] == '\0') { dobeep(); ewprintf("No file name"); return (FALSE); } /* Ensure file has not been modified elsewhere */ /* We don't use the ignore flag here */ if (fchecktime(bp) != TRUE) { if ((s = eyesno("File has changed on disk since last save. " "Save anyway")) != TRUE) return (s); } if (makebackup && (bp->b_flag & BFBAK)) { s = fbackupfile(bp->b_fname); /* hard error */ if (s == ABORT) return (FALSE); /* softer error */ if (s == FALSE && (s = eyesno("Backup error, save anyway")) != TRUE) return (s); } if ((s = writeout(&ffp, bp, bp->b_fname)) == TRUE) { (void)fupdstat(bp); bp->b_flag &= ~(BFCHG | BFBAK); upmodes(bp); undo_add_boundary(FFRAND, 1); undo_add_modified(); } return (s); }