> 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

Reply via email to