From 0b98546c7b94e0858d8daad1b96091ba91734f4b Mon Sep 17 00:00:00 2001 From: Kjell Wooding Date: Mon, 15 Sep 2008 16:11:36 +0000 Subject: Enable dirty buffer detection in mg. Emulate the emacs behavior: after suspend/resume, buffer switch, or at save time, warn (prompt) the user if the file has been modified on disk in the interim. This has already saved my butt numerous times. ok phessler --- usr.bin/mg/buffer.c | 34 ++++++++++++++++++++++++--- usr.bin/mg/def.h | 9 ++++++-- usr.bin/mg/file.c | 13 +++++++++-- usr.bin/mg/fileio.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++------- usr.bin/mg/line.c | 24 +++++++++++++++++-- usr.bin/mg/region.c | 8 ++++++- usr.bin/mg/sysdef.h | 3 ++- usr.bin/mg/tty.c | 7 +++++- usr.bin/mg/word.c | 20 ++++++++++++---- 9 files changed, 160 insertions(+), 24 deletions(-) (limited to 'usr.bin/mg') diff --git a/usr.bin/mg/buffer.c b/usr.bin/mg/buffer.c index 9d7b89e3af0..64761e58106 100644 --- a/usr.bin/mg/buffer.c +++ b/usr.bin/mg/buffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: buffer.c,v 1.67 2007/05/28 17:52:17 kjell Exp $ */ +/* $OpenBSD: buffer.c,v 1.68 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -22,10 +22,14 @@ extern int globalwd; 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; + curbp->b_flag &= ~BFREADONLY; if (curbp->b_flag & BFCHG) ewprintf("Warning: Buffer was modified"); } @@ -572,7 +576,7 @@ bclear(struct buffer *bp) /* * Display the given buffer in the given window. Flags indicated - * action on redisplay. + * action on redisplay. Update modified flag so insert loop can check it. */ int showbuffer(struct buffer *bp, struct mgwin *wp, int flags) @@ -580,6 +584,10 @@ 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_flag |= flags; wp->w_dotp = bp->b_dotp; @@ -798,3 +806,23 @@ error: return (FALSE); } +/* + * Ensures a buffer has not been modified elsewhere. + * Returns TRUE if it has NOT. 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); +} + diff --git a/usr.bin/mg/def.h b/usr.bin/mg/def.h index f26d46a2505..542a07c084e 100644 --- a/usr.bin/mg/def.h +++ b/usr.bin/mg/def.h @@ -1,4 +1,4 @@ -/* $OpenBSD: def.h,v 1.106 2008/06/14 08:39:30 kjell Exp $ */ +/* $OpenBSD: def.h,v 1.107 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -272,7 +272,8 @@ struct buffer { #endif #define BFOVERWRITE 0x08 /* overwrite mode */ #define BFREADONLY 0x10 /* read only mode */ - +#define BFDIRTY 0x20 /* Buffer was modified elsewhere */ +#define BFIGNDIRTY 0x40 /* Ignore modifications */ /* * This structure holds information about recent actions for the Undo command. */ @@ -404,6 +405,7 @@ int usebuffer(int, int); int notmodified(int, int); int popbuftop(struct buffer *); int getbufcwd(char *, size_t); +int checkdirty(struct buffer *); /* display.c */ int vtresize(int, int, int); @@ -424,6 +426,7 @@ void free_file_list(struct list *); /* fileio.c */ int ffropen(const char *, struct buffer *); +void ffstat(struct buffer *); int ffwopen(const char *, struct buffer *); int ffclose(struct buffer *); int ffputbuf(struct buffer *); @@ -434,6 +437,8 @@ char *startupfile(char *); int copy(char *, char *); struct list *make_file_list(char *); int fisdir(const char *); +int fchecktime(struct buffer *); +int fupdstat(struct buffer *); /* kbd.c X */ int do_meta(int, int); diff --git a/usr.bin/mg/file.c b/usr.bin/mg/file.c index cf4b744de35..6f3f87f7d78 100644 --- a/usr.bin/mg/file.c +++ b/usr.bin/mg/file.c @@ -1,4 +1,4 @@ -/* $OpenBSD: file.c,v 1.67 2008/06/18 17:13:53 kjell Exp $ */ +/* $OpenBSD: file.c,v 1.68 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -212,7 +212,7 @@ readin(char *fname) if (bclear(curbp) != TRUE) return (TRUE); /* Clear readonly. May be set by autoexec path */ - curbp->b_flag &=~ BFREADONLY; + curbp->b_flag &= ~BFREADONLY; if ((status = insertfile(fname, fname, TRUE)) != TRUE) { ewprintf("File is not readable: %s", fname); return (FALSE); @@ -566,6 +566,14 @@ buffsave(struct buffer *bp) 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 */ @@ -632,6 +640,7 @@ writeout(struct buffer *bp, char *fn) } else /* ignore close error if it is a write error */ (void)ffclose(bp); + (void)fupdstat(bp); return (s == FIOSUC); } diff --git a/usr.bin/mg/fileio.c b/usr.bin/mg/fileio.c index 2f6e8f56856..1f4c40c8fdb 100644 --- a/usr.bin/mg/fileio.c +++ b/usr.bin/mg/fileio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fileio.c,v 1.81 2007/11/27 16:22:14 martynas Exp $ */ +/* $OpenBSD: fileio.c,v 1.82 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -8,8 +8,8 @@ #include "def.h" -#include #include +#include #include #include #include @@ -31,8 +31,6 @@ static FILE *ffp; int ffropen(const char *fn, struct buffer *bp) { - struct stat statbuf; - if ((ffp = fopen(fn, "r")) == NULL) { if (errno == ENOENT) return (FIOFNF); @@ -43,13 +41,44 @@ ffropen(const char *fn, struct buffer *bp) if (fisdir(fn) == TRUE) return (FIODIR); - if (bp && fstat(fileno(ffp), &statbuf) == 0) { + ffstat(bp); + + return (FIOSUC); +} + +/* + * Update stat/dirty info + */ +void +ffstat(struct buffer *bp) +{ + struct stat sb; + + if (bp && fstat(fileno(ffp), &sb) == 0) { /* set highorder bit to make sure this isn't all zero */ - bp->b_fi.fi_mode = statbuf.st_mode | 0x8000; - bp->b_fi.fi_uid = statbuf.st_uid; - bp->b_fi.fi_gid = statbuf.st_gid; + bp->b_fi.fi_mode = sb.st_mode | 0x8000; + bp->b_fi.fi_uid = sb.st_uid; + bp->b_fi.fi_gid = sb.st_gid; + bp->b_fi.fi_mtime = sb.st_mtimespec; + /* Clear the ignore flag */ + bp->b_flag &= ~(BFIGNDIRTY | BFDIRTY); } +} +/* + * Update the status/dirty info. If there is an error, + * there's not a lot we can do. + */ +int +fupdstat(struct buffer *bp) +{ + if ((ffp = fopen(bp->b_fname, "r")) == NULL) { + if (errno == ENOENT) + return (FIOFNF); + return (FIOERR); + } + ffstat(bp); + ffclose(bp); return (FIOSUC); } @@ -559,3 +588,24 @@ fisdir(const char *fname) return (FALSE); } + +/* + * Check the mtime of the supplied filename. + * Return TRUE if last mtime matches, FALSE if not, + * If the stat fails, return TRUE and try the save anyway + */ +int +fchecktime(struct buffer *bp) +{ + struct stat sb; + + if (stat(bp->b_fname, &sb) == -1) + return (TRUE); + + if (bp->b_fi.fi_mtime.tv_sec != sb.st_mtimespec.tv_sec || + bp->b_fi.fi_mtime.tv_nsec != sb.st_mtimespec.tv_nsec) + return (FALSE); + + return (TRUE); + +} diff --git a/usr.bin/mg/line.c b/usr.bin/mg/line.c index ac600887381..4d0565e0afe 100644 --- a/usr.bin/mg/line.c +++ b/usr.bin/mg/line.c @@ -1,4 +1,4 @@ -/* $OpenBSD: line.c,v 1.44 2006/12/24 01:20:53 kjell Exp $ */ +/* $OpenBSD: line.c,v 1.45 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -142,7 +142,10 @@ linsert_str(const char *s, int n) struct line *lp1; struct mgwin *wp; RSIZE i; - int doto; + int doto, k; + + if ((k = checkdirty(curbp)) != TRUE) + return (k); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read only"); @@ -233,10 +236,14 @@ linsert(int n, int c) struct mgwin *wp; RSIZE i; int doto; + int s; if (!n) return (TRUE); + if ((s = checkdirty(curbp)) != TRUE) + return (s); + if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read only"); return (FALSE); @@ -388,6 +395,10 @@ lnewline_at(struct line *lp1, int doto) int lnewline(void) { + int s; + + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read only"); return (FALSE); @@ -414,7 +425,10 @@ ldelete(RSIZE n, int kflag) size_t len; char *sv; int end; + int s; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read only"); return (FALSE); @@ -497,7 +511,10 @@ ldelnewline(void) { struct line *lp1, *lp2, *lp3; struct mgwin *wp; + int s; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read only"); return (FALSE); @@ -571,7 +588,10 @@ int lreplace(RSIZE plen, char *st) { RSIZE rlen; /* replacement length */ + int s; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read only"); return (FALSE); diff --git a/usr.bin/mg/region.c b/usr.bin/mg/region.c index 751f63fea7f..78555084453 100644 --- a/usr.bin/mg/region.c +++ b/usr.bin/mg/region.c @@ -1,4 +1,4 @@ -/* $OpenBSD: region.c,v 1.26 2008/06/10 23:23:53 kjell Exp $ */ +/* $OpenBSD: region.c,v 1.27 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -98,6 +98,8 @@ lowerregion(int f, int n) struct region region; int loffs, c, s; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read-only"); return (FALSE); @@ -139,6 +141,8 @@ upperregion(int f, int n) struct region region; int loffs, c, s; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read-only"); return (FALSE); @@ -261,6 +265,8 @@ prefixregion(int f, int n) int nline; int s; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read-only"); return (FALSE); diff --git a/usr.bin/mg/sysdef.h b/usr.bin/mg/sysdef.h index 4df4e805a8c..6b7561442b3 100644 --- a/usr.bin/mg/sysdef.h +++ b/usr.bin/mg/sysdef.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sysdef.h,v 1.15 2006/08/01 22:16:03 jason Exp $ */ +/* $OpenBSD: sysdef.h,v 1.16 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -26,4 +26,5 @@ struct fileinfo { uid_t fi_uid; gid_t fi_gid; mode_t fi_mode; + struct timespec fi_mtime; /* Last modified time */ }; diff --git a/usr.bin/mg/tty.c b/usr.bin/mg/tty.c index 49169052153..f803cc7a7ed 100644 --- a/usr.bin/mg/tty.c +++ b/usr.bin/mg/tty.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tty.c,v 1.29 2008/06/11 00:03:49 tobias Exp $ */ +/* $OpenBSD: tty.c,v 1.30 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -127,6 +127,11 @@ ttinit(void) void ttreinit(void) { + /* check if file was modified while we were gone */ + if (fchecktime(curbp) != TRUE) { + curbp->b_flag |= BFDIRTY; + } + if (enter_ca_mode) /* enter application mode */ putpad(enter_ca_mode, 1); diff --git a/usr.bin/mg/word.c b/usr.bin/mg/word.c index 9489120f10a..c18b620e672 100644 --- a/usr.bin/mg/word.c +++ b/usr.bin/mg/word.c @@ -1,4 +1,4 @@ -/* $OpenBSD: word.c,v 1.14 2006/05/28 23:30:16 kjell Exp $ */ +/* $OpenBSD: word.c,v 1.15 2008/09/15 16:11:35 kjell Exp $ */ /* This file is in the public domain. */ @@ -68,9 +68,11 @@ forwword(int f, int n) int upperword(int f, int n) { - int c; + int c, s; RSIZE size; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read-only"); return (FALSE); @@ -108,9 +110,11 @@ upperword(int f, int n) int lowerword(int f, int n) { - int c; + int c, s; RSIZE size; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read-only"); return (FALSE); @@ -149,9 +153,11 @@ lowerword(int f, int n) int capword(int f, int n) { - int c; + int c, s; RSIZE size; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read-only"); return (FALSE); @@ -228,7 +234,10 @@ 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) { ewprintf("Buffer is read-only"); return (FALSE); @@ -279,7 +288,10 @@ int delbword(int f, int n) { RSIZE size; + int s; + if ((s = checkdirty(curbp)) != TRUE) + return (s); if (curbp->b_flag & BFREADONLY) { ewprintf("Buffer is read-only"); return (FALSE); -- cgit v1.2.3