> So perhaps it is better for mg to behave more like emacs when it comes > to saving backup files in a single directory. Especially if a user has > two files open with the same name and are working on them > simultaneously. In this diff I've added the path to the backup file > name. Like emacs, it changes any '/' to '!'. >
Here is a slightly modified diff; add NUL termination to backup path. Are there objections to this going in? -lum Index: def.h =================================================================== RCS file: /cvs/src/usr.bin/mg/def.h,v retrieving revision 1.123 diff -u -p -r1.123 def.h --- def.h 7 Jun 2012 15:15:04 -0000 1.123 +++ def.h 9 Jun 2012 20:22:10 -0000 @@ -446,6 +446,7 @@ struct list *make_file_list(char *); int fisdir(const char *); int fchecktime(struct buffer *); int fupdstat(struct buffer *); +int backuptohomedir(int, int); /* kbd.c X */ int do_meta(int, int); Index: fileio.c =================================================================== RCS file: /cvs/src/usr.bin/mg/fileio.c,v retrieving revision 1.89 diff -u -p -r1.89 fileio.c --- fileio.c 25 May 2012 04:56:58 -0000 1.89 +++ fileio.c 9 Jun 2012 20:22:10 -0000 @@ -22,6 +22,10 @@ #include "kbd.h" +static char *bkuplocation(const char *); + +static char *bkupdir; + /* * Open a file for reading. */ @@ -189,6 +193,51 @@ ffgetline(FILE *ffp, char *buf, int nbuf } /* + * Location of backup file. This function creates the correct path. + */ +static char * +bkuplocation(const char *fn) +{ + struct stat sb; + char *ret; + + if (bkupdir != NULL && (stat(bkupdir, &sb) == 0) && + S_ISDIR(sb.st_mode)) { + char fname[NFILEN]; + const char *c; + int i = 0, len; + + c = fn; + len = strlen(bkupdir); + + while (*c != '\0') { + /* Make sure we don't go over combined: + * strlen(bkupdir + '/' + fname + '\0') + */ + if (i >= NFILEN - len - 1) + return (NULL); + if (*c == '/') { + fname[i] = '!'; + } else if (*c == '!') { + if (i >= NFILEN - len - 2) + return (NULL); + fname[i++] = '!'; + fname[i] = '!'; + } else + fname[i] = *c; + i++; + c++; + } + fname[i] = '\0'; + if (asprintf(&ret, "%s/%s", bkupdir, fname) == -1) + return (NULL); + } else if ((ret = strndup(fn, NFILEN)) == NULL) + return (NULL); + + return (ret); +} + +/* * Make a backup copy of "fname". On Unix the backup has the same * name as the original file, with a "~" on the end; this seems to * be newest of the new-speak. The error handling is all in "file.c". @@ -203,23 +252,29 @@ fbackupfile(const char *fn) int from, to, serrno; ssize_t nread; char buf[BUFSIZ]; - char *nname, *tname; + char *nname, *tname, *bkpth; if (stat(fn, &sb) == -1) { ewprintf("Can't stat %s : %s", fn, strerror(errno)); return (FALSE); } - if (asprintf(&nname, "%s~", fn) == -1) { + if ((bkpth = bkuplocation(fn)) == NULL) + return (FALSE); + + if (asprintf(&nname, "%s~", bkpth) == -1) { ewprintf("Can't allocate temp file name : %s", strerror(errno)); + free(bkpth); return (ABORT); } - if (asprintf(&tname, "%s.XXXXXXXXXX", fn) == -1) { + if (asprintf(&tname, "%s.XXXXXXXXXX", bkpth) == -1) { ewprintf("Can't allocate temp file name : %s", strerror(errno)); + free(bkpth); free(nname); return (ABORT); } + free(bkpth); if ((from = open(fn, O_RDONLY)) == -1) { free(nname); @@ -610,4 +665,28 @@ fchecktime(struct buffer *bp) return (TRUE); +} + +int +backuptohomedir(int f, int n) +{ + const char *c = "~/.mg.d"; + char *p; + + if (bkupdir == NULL) { + p = adjustname(c, TRUE); + bkupdir = strndup(p, NFILEN); + if (bkupdir == NULL) + return(FALSE); + + if (mkdir(bkupdir, 0700) == -1 && errno != EEXIST) { + free(bkupdir); + bkupdir = NULL; + } + } else { + free(bkupdir); + bkupdir = NULL; + } + + return (TRUE); } Index: funmap.c =================================================================== RCS file: /cvs/src/usr.bin/mg/funmap.c,v retrieving revision 1.39 diff -u -p -r1.39 funmap.c --- funmap.c 7 Jun 2012 15:15:04 -0000 1.39 +++ funmap.c 9 Jun 2012 20:22:10 -0000 @@ -25,6 +25,7 @@ static struct funmap functnames[] = { {fillmode, "auto-fill-mode",}, {indentmode, "auto-indent-mode",}, {backtoindent, "back-to-indentation",}, + {backuptohomedir, "backup-to-home-directory",}, {backchar, "backward-char",}, {delbword, "backward-kill-word",}, {gotobop, "backward-paragraph",}, Index: mg.1 =================================================================== RCS file: /cvs/src/usr.bin/mg/mg.1,v retrieving revision 1.61 diff -u -p -r1.61 mg.1 --- mg.1 7 Jun 2012 15:15:04 -0000 1.61 +++ mg.1 9 Jun 2012 20:22:10 -0000 @@ -350,6 +350,9 @@ to a new line. Toggle indent mode, where indentation is preserved after a newline. .It back-to-indentation Move the dot to the first non-whitespace character on the current line. +.It backup-to-home-directory +Save backup copies to a ~/.mg.d directory instead of working directory. +Requires make-backup-files to be on. .It backward-char Move cursor backwards one character. .It backward-kill-word