Automatic backup for MicroEmacs 3.9e

Automatic backup for MicroEmacs 3.9e

Post by Urs Zurbuch » Sun, 02 Dec 1990 11:14:00



[May the schwartz be with the line eater]

Hello, you fans of MicroEmacs and other small things,

Something I missed badly in MicroEmacs (ever since I used it), was its
inability to automatically save my original file as a backup file. More
than once I lost some hours work hitting the wrong key, just beacuse there
was no backup file.
(BTW, this would also solve the problem (recently mentioned) when working
under MS-DOS and hitting ^C during a save. Ok, the ^C wouldn't be trapped
here, too, but at least you had a backup and could start again :-) )

Now, instead of going on complaining, I put my nose deep into the sources
and added that feature.

I had to change three source and two header files. Following are the dif-
files as shar. Also included is a file 'readme' with some remarks concerning
the implementation.
Note that I posted the complete version of file.c. The diffs were as large
as the original.

----- CUT HERE ----- CUT HERE ----- CUT HERE ----- CUT HERE ----- CUT HERE --
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#       readme
#       edef.dif
#       estruct.dif
#       fileio.dif
#       main.dif
#       file.c
# This archive created: Tue Dec 15 11:08:50 1987
export PATH; PATH=/bin:$PATH
if test -f 'readme'
then
        echo shar: will not over-write existing file "'readme'"
else
cat << \SHAR_EOF > 'readme'
To add the backup-feature to MicroEmacs 3.9e use the four dif-files in this
posting. You should be able to use patch to apply the changes to your sources.
But be careful. I already implemented some of the patches posted on usenet
during the last few weeks, BUT NOT ALL OF THEM. So it's really possible
that you don't have the same 'original' sources as I had when extracting the
diffs.
This is true for MAIN.C for sure. I have changed some other things which
aren't included in this posting here. I added a short notice at the end of the
revision history. And you will see only my last entry in the dif-file. But,
hey, now you know what to look for.
(There is of course another entry in the revision history for this new
feature.)
(BTW the way, I don't have a version of Patch myself. Could some kind soul
please send the sources to me?)
Ok, now to the important stuff (assuming that you made the patch successfully):
In estruct.h:
        There are two new preprocessor constants called BACKUP and BUPEVS
        respectively. The meaning for the first should be clear. If you set
        it to one, the code for the backup feature is compiled, too.
        With the second constant you can define wether a backup file should
        be generated with every save or just with the first one of an editing
        session. If you set it to one you will always have the youngest two
        version of your file saved to disk: the original and a backup. If you
        set the constant to zero you will have the original file and, as a
        backup file, the file as it was when you started editing.
        Made everything unclear ?

How does it work:
        The file is first saved under a name which should be guaranteed to
        be unique on a given system ( using mktemp("meXXXXXX") ). If that is
        successfull, the original is renamed to the name of the backup file
        and the saved file is then renamed to the original file. If anything
        in this process goes wrong, the original situation is reinstalled
        and the user gets a message "SAVE FAILED".
        The name of the backup file is 'computed' as follows:

        MSDOS:  a tilde '~' is prepended to the extension. This way we get
                different backup files for (e.g.) foo.c & foo.h
        UNIX:   at the front of the filename is a '#' inserted. The filename
                is guaranteed to be not longer than 14 characters (255 on BSD).

Some special remarks:
        I also changed the function 'fexist' in fileio.c to use the system
        call 'access(filename, mode)' when using a Unix C compiler or
        Microsoft C. I think it should be faster and you're not using a
        filehandle to test for a file's presence.
        Please tell me of any other compiler which knows this function.
        I also added a new function 'frename' which just does what you think.
        This is ifdef'ed for MSC and UNIX as well. The same applies as above.

Restrictions:
        This patch works only for MS-DOS and (any) UNIX, by now. I don't
        have an AMIGA, an ATARI STx nor a VMS-VAX, so I couldn't add the code
        necessary for them.
        I have some colleagues who have Amigas and Ataris. I should be able
        to figure out how it should be done. But DO NOT rely on that. If
        someone of you implemets it, please send a copy to Daniel Lawrence
        and to me (unless Daniel states that he isn't interested in that
        feature at all, of course).
        On UNIX, it will work and make a backup file, but I'm not sure if
        the new, saved file has the same status according to locks as the
        original. (Bye the way, does it if I just save my file without
        exiting ?)
        For you BSD-types: I'm sure you already got used to it, but I used
        some of the string functions as they are defined for SYS V. I decided
        not to use a defined constant for that function because all the
        other functions (like strcat, strchr, ...) aren't defined as well.
        You better look for strrchr, strcpy and strcat in file.c

SHAR_EOF
fi # end of overwriting check
if test -f 'edef.dif'
then
        echo shar: will not over-write existing file "'edef.dif'"
else
cat << \SHAR_EOF > 'edef.dif'
*** edef.org    Sun Dec 13 22:16:06 1987
--- edef.h      Mon Dec 14 20:19:40 1987
***************
*** 127,132
  char  tap[NPAT];                      /* Reversed pattern array.      */
  char  rpat[NPAT];                     /* replacement pattern          */

  /* The variable matchlen holds the length of the matched
   * string - used by the replace functions.
   * The variable patmatch holds the string that satisfies

--- 127,136 -----
  char  tap[NPAT];                      /* Reversed pattern array.      */
  char  rpat[NPAT];                     /* replacement pattern          */

+ #if   BACKUP
+ char  *bup_file;              /* temporary filename for saved files   */
+ #endif
+
  /* The variable matchlen holds the length of the matched
   * string - used by the replace functions.
   * The variable patmatch holds the string that satisfies
***************
*** 180,185
  extern  short   kbdm[];                 /* Holds kayboard macro data    */
  extern  char    pat[];                  /* Search pattern               */
  extern        char    rpat[];                 /* Replacement pattern          */
  extern        char    *execstr;               /* pointer to string to execute */
  extern        char    golabel[];              /* current line to go to        */
  extern        int     execlevel;              /* execution IF level           */

--- 184,192 -----
  extern  short   kbdm[];                 /* Holds kayboard macro data    */
  extern  char    pat[];                  /* Search pattern               */
  extern        char    rpat[];                 /* Replacement pattern          */
+ #if   BACKUP
+ extern        char    *bup_file;              /* temporary save filename      */
+ #endif
  extern        char    *execstr;               /* pointer to string to execute */
  extern        char    golabel[];              /* current line to go to        */
  extern        int     execlevel;              /* execution IF level           */
SHAR_EOF
fi # end of overwriting check
if test -f 'estruct.dif'
then
        echo shar: will not over-write existing file "'estruct.dif'"
else
cat << \SHAR_EOF > 'estruct.dif'
*** estruct.org Sun Dec 13 17:14:06 1987
--- estruct.h   Mon Dec 14 20:19:00 1987
***************
*** 97,102
  #define       COLOR   1       /* color commands and windows                   */

  #define       FILOCK  0       /* file locking under unix BSD 4.2              */
  #define       ISRCH   1       /* Incremental searches like ITS EMACS          */
  #define       WORDPRO 1       /* Advanced word processing features            */
  #define       FLABEL  0       /* function key label code [HP150]              */

--- 97,104 -----
  #define       COLOR   1       /* color commands and windows                   */

  #define       FILOCK  0       /* file locking under unix BSD 4.2              */
+ #define       BACKUP  1       /* automatically make a backup file             */
+ #define BUPEVS        0       /* backup file every save (or with first save only) */
  #define       ISRCH   1       /* Incremental searches like ITS EMACS          */
  #define       WORDPRO 1       /* Advanced word processing features            */
  #define       FLABEL  0       /* function key label code [HP150]              */
***************
*** 420,425
          char    b_flag;                 /* Flags                        */
        int     b_mode;                 /* editor mode of this buffer   */
          char    b_fname[NFILEN];        /* File name                    */
          char    b_bname[NBUFN];         /* Buffer name                  */
  #if   CRYPT
        char    b_key[NPAT];            /* current encrypted key        */

--- 422,430 -----
          char    b_flag;                 /* Flags                        */
        int     b_mode;                 /* editor mode of this buffer   */
          char    b_fname[NFILEN];        /* File name                    */
+ #if   BACKUP && !BUPEVS
+         int   b_bupflg;               /* Backup file at next save?    */
+ #endif
          char    b_bname[NBUFN];         /* Buffer name                  */
  #if   CRYPT
        char    b_key[NPAT];            /* current encrypted key        */
***************
*** 426,432
  #endif
  }       BUFFER;

! #define BFINVS  0x01                    /* Internal invisable buffer    */
  #define BFCHG   0x02                    /* Changed since last write     */
  #define       BFTRUNC 0x04                    /* buffer was truncated when read */

--- 431,437 -----
  #endif
  }       BUFFER;

! #define BFINVS  0x01                    /* Internal invisible buffer    */
  #define BFCHG   0x02                    /* Changed since last write     */
  #define       BFTRUNC 0x04                    /* buffer was truncated when read */

SHAR_EOF
fi # end of overwriting check
if test -f 'fileio.dif'
then
        echo shar: will not over-write existing file "'fileio.dif'"
else
cat << \SHAR_EOF > 'fileio.dif'
*** fileio.org  Fri Nov 20 14:26:22 1987
--- fileio.c    Mon Dec 14 21:08:28 1987
***************
*** 186,191
  {
        FILE *fp;

        /* try to open the file for reading */
        fp = fopen(fname, "r");

--- 186,194 -----
  {
        FILE *fp;

+ #if   MSC | UNIX
+       return( ( access( fname, 0 )) ? FALSE : TRUE );
+ #else
        /* try to open the file for reading */
        fp = fopen(fname, "r");

***************
*** 196,201
        /* otherwise, close it and report true */
        fclose(fp);
        return(TRUE);
  }

  #if   AZTEC & MSDOS

--- 199,221 -----
        /* otherwise, close it and report true */
        fclose(fp);
        return(TRUE);
+ #endif        /* MSC | UNIX */
+ }
+
+ int frename( from, to )       /* rename a file */
+ char  *from;
+ char  *to;
+ {
+ #if   MSC
+       return( rename( from, to ));
+ #endif
+ #if   UNIX
+       if( link( from, to ) == 0 )
+               if( unlink( from ) == 0 )
+                       return( 0 );
+               unlink( to );
+               return( -1 );
+ #endif        /* UNIX */
  }

  #if   AZTEC & MSDOS
SHAR_EOF
fi # end of overwriting check
if test -f 'main.dif'
then
        echo shar: will not over-write existing file "'main.dif'"
else
cat << \SHAR_EOF > 'main.dif'
*** main.org    Sun Dec 13 17:12:32 1987
--- main.c      Mon Dec 14 20:19:46 1987
***************
*** 859,864
   *    30-nov-87
   *    - made flook() look first in the list in epath.h, then in the HOME
   *      directory, then in the current directory, and then down the $PATH
   */

  #include        <stdio.h>

--- 859,868 -----
   *    30-nov-87
   *    - made flook() look first in the list in epath.h, then in the HOME
   *      directory, then in the current directory, and then down the $PATH
+  *    14-dec-87
+  *    - added support for backup files. when saved for the first time during
+  *      and edit-session each file is renamed to a backup file.
+  *      by now, only MS-DOS and Unix supported.
   */

  #include        <stdio.h>
***************
*** 933,938
  #endif
        char *strncpy();
        extern *pathname[];             /* startup file path/name array */

        /* initialize the editor */
          vtinit();             /* Display */

--- 937,945 -----
  #endif
        char *strncpy();
        extern *pathname[];             /* startup file path/name array */
+ #if   BACKUP
+       char *mktemp();
+ #endif

        /* initialize the editor */
          vtinit();             /* Display */
***************
*** 952,957
        eexitflag = FALSE;      /* not time to exit yet */
  #endif

        /* Parse the command line */
        for (carg = 1; carg < argc; ++carg) {

--- 959,969 -----
        eexitflag = FALSE;      /* not time to exit yet */
  #endif

+ #if   BACKUP
+                               /* initialise global variables for backups */
+       bup_file  = mktemp( "meXXXXXX" );
+ #endif
+      
        /* Parse the command line */
        for (carg = 1; carg < argc; ++carg) {
SHAR_EOF
fi # end of overwriting check
if test -f 'file.c'
then
        echo shar: will not over-write existing file "'file.c'"
else
cat << \SHAR_EOF > 'file.c'
/*      FILE.C:   for MicroEMACS

        The routines in this file handle the reading, writing
        and lookup of disk files.  All of details about the
        reading and writing of the disk are in "fileio.c".

*/

#include        <stdio.h>
#include        "estruct.h"
#include        "edef.h"

#if     BACKUP
#include        <errno.h>
extern  int     errno;
#endif

/*
 * Read a file into the current
 * buffer. This is really easy; all you do it
 * find the name of the file, and call the standard
 * "read a file into the current buffer" code.
 * Bound to "C-X C-R".
 */
fileread(f, n)
{
        register int    s;
        char fname[NFILEN];

        if (restflag)           /* don't allow this command if restricted */
                return(resterr());
        if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
                return(s);
        return(readin(fname, TRUE));

}

/*
 * Insert a file into the current
 * buffer. This is really easy; all you do it
 * find the name of the file, and call the standard
 * "insert a file into the current buffer" code.
 * Bound to "C-X C-I".
 */
insfile(f, n)
{
        register int    s;
        char fname[NFILEN];

        if (restflag)           /* don't allow this command if restricted */
                return(resterr());
        if (curbp->b_mode&MDVIEW)        /* don't allow this command if  */
                return(rdonly());       /* we are in read only mode     */
        if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
                return(s);
        return(ifile(fname));

}

/*
 * Select a file for editing.
 * Look around to see if you can find the
 * fine in another buffer; if you can find it
 * just switch to the buffer. If you cannot find
 * the file, create a new buffer, read in the
 * text, and switch to the new buffer.
 * Bound to C-X C-F.
 */
filefind(f, n)
{
        char fname[NFILEN];     /* file user wishes to find */
        register int s;         /* status return */

        if (restflag)           /* don't allow this command if restricted */
                return(resterr());
        if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
                return(s);
        return(getfile(fname, TRUE));

}

viewfile(f, n)  /* visit a file in VIEW mode */
{
        char fname[NFILEN];     /* file user wishes to find */
        register int s;         /* status return */
        register WINDOW *wp;    /* scan for windows that need updating */

        if (restflag)           /* don't allow this command if restricted */
                return(resterr());
        if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
                return (s);
        s = getfile(fname, FALSE);
        if (s) {        /* if we succeed, put it in view mode */
                curwp->w_bufp->b_mode |= MDVIEW;

                /* scan through and update mode lines of all windows */
                wp = wheadp;
                while (wp != NULL) {
                        wp->w_flag |= WFMODE;
                        wp = wp->w_wndp;
                }
        }
        return(s);

}

#if     CRYPT
resetkey()      /* reset the encryption key if needed */

{
        register int s; /* return status */

        /* turn off the encryption flag */
        cryptflag = FALSE;

        /* if we are in crypt mode */
        if (curbp->b_mode & MDCRYPT) {
                if (curbp->b_key[0] == 0) {
                        s = setkey(FALSE, 0);
                        if (s != TRUE)
                                return(s);
                }

                /* let others know... */
                cryptflag = TRUE;

                /* and set up the key to be used! */
                /* de-encrypt it */
                crypt((char *)NULL, 0);
                crypt(curbp->b_key, strlen(curbp->b_key));

                /* re-encrypt it...seeding it to start */
                crypt((char *)NULL, 0);
                crypt(curbp->b_key, strlen(curbp->b_key));
        }

        return(TRUE);

}

#endif

getfile(fname, lockfl)

char fname[];           /* file name to find */
int lockfl;             /* check the file for locks? */

{
        register BUFFER *bp;
        register LINE   *lp;
        register int    i;
        register int    s;
        char bname[NBUFN];      /* buffer name to put file */

#if     MSDOS
        mklower(fname);         /* msdos isn't case sensitive */
#endif
        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
                if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
                        swbuffer(bp);
                        lp = curwp->w_dotp;
                        i = curwp->w_ntrows/2;
                        while (i-- && lback(lp)!=curbp->b_linep)
                                lp = lback(lp);
                        curwp->w_linep = lp;
                        curwp->w_flag |= WFMODE|WFHARD;
                        mlwrite("[Old buffer]");
                        return (TRUE);
                }
        }
        makename(bname, fname);                 /* New buffer name.     */
        while ((bp=bfind(bname, FALSE, 0)) != NULL) {
                /* old buffer name conflict code */
                s = mlreply("Buffer name: ", bname, NBUFN);
                if (s == ABORT)                 /* ^G to just quit      */
                        return (s);
                if (s == FALSE) {               /* CR to clobber it     */
                        makename(bname, fname);
                        break;
                }
        }
        if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
                mlwrite("Cannot create buffer");
                return (FALSE);
        }
        if (--curbp->b_nwnd == 0) {             /* Undisplay.           */
                curbp->b_dotp = curwp->w_dotp;
                curbp->b_doto = curwp->w_doto;
                curbp->b_markp = curwp->w_markp;
                curbp->b_marko = curwp->w_marko;
        }
        curbp = bp;                             /* Switch to it.        */
        curwp->w_bufp = bp;
        curbp->b_nwnd++;
        return(readin(fname, lockfl));          /* Read it in.          */

}

/*
        Read file "fname" into the current buffer, blowing away any text
        found there.  Called by both the read and find commands.  Return
        the final status of the read.  Also called by the mainline, to
        read in a file specified on the command line as an argument.
        The command bound to M-FNR is called after the buffer is set up
        and before it is read.
*/

readin(fname, lockfl)

char    fname[];        /* name of file to read */
int     lockfl;         /* check for file locks? */

{
        register LINE   *lp1;
        register LINE   *lp2;
        register int    i;
        register WINDOW *wp;
        register BUFFER *bp;
        register int    s;
        register int    nbytes;
        register int    nline;
        int             lflag;          /* any lines longer than allowed? */
        char mesg[NSTRING];

#if     FILOCK
        if (lockfl && lockchk(fname) == ABORT)
                return(ABORT);
#endif
#if     CRYPT
        s = resetkey();
        if (s != TRUE)
                return(s);
#endif
        bp = curbp;                             /* Cheap.               */
        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
                return (s);
        bp->b_flag &= ~(BFINVS|BFCHG);
#if     BACKUP && !BUPEVS
        curbp->b_bupflg = FALSE;             /* no backup file yet   */
#endif
        strcpy(bp->b_fname, fname);

        /* let a user macro get hold of things...if he wants */
        execute(META|SPEC|'R', FALSE, 1);

        /* turn off ALL keyboard translation in case we get a dos error */
        TTkclose();

        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
                goto out;

        if (s == FIOFNF) {                      /* File not found.      */
                mlwrite("[New file]");
                goto out;
        }

        /* read the file in */
        mlwrite("[Reading file]");
        nline = 0;
        lflag = FALSE;
        while ((s=ffgetline()) == FIOSUC) {
                nbytes = strlen(fline);
                if ((lp1=lalloc(nbytes)) == NULL) {
                        s = FIOMEM;             /* Keep message on the  */
                        break;                  /* display.             */
                }
                lp2 = lback(curbp->b_linep);
                lp2->l_fp = lp1;
                lp1->l_fp = curbp->b_linep;
                lp1->l_bp = lp2;
                curbp->b_linep->l_bp = lp1;
                for (i=0; i<nbytes; ++i)
                        lputc(lp1, i, fline[i]);
                ++nline;
        }
        ffclose();                              /* Ignore errors.       */
        strcpy(mesg, "[");
        if (s==FIOERR) {
                strcat(mesg, "I/O ERROR, ");
                curbp->b_flag |= BFTRUNC;
        }
        if (s == FIOMEM) {
                strcat(mesg, "OUT OF MEMORY, ");
                curbp->b_flag |= BFTRUNC;
        }
        sprintf(&mesg[strlen(mesg)], "Read %d line", nline);
        if (nline > 1)
                strcat(mesg, "s");
        strcat(mesg, "]");
        mlwrite(mesg);

out:
        TTkopen();      /* open the keyboard again */
        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
                if (wp->w_bufp == curbp) {
                        wp->w_linep = lforw(curbp->b_linep);
                        wp->w_dotp  = lforw(curbp->b_linep);
                        wp->w_doto  = 0;
                        wp->w_markp = NULL;
                        wp->w_marko = 0;
                        wp->w_flag |= WFMODE|WFHARD;
                }
        }
        if (s == FIOERR || s == FIOFNF)         /* False if error.      */
                return(FALSE);
        return (TRUE);

}

/*
 * Take a file name, and from it
 * fabricate a buffer name. This routine knows
 * about the syntax of file names on the target system.
 * I suppose that this information could be put in
 * a better place than a line of code.
 */
makename(bname, fname)
char    bname[];
char    fname[];
{
        register char *cp1;
        register char *cp2;

        cp1 = &fname[0];
        while (*cp1 != 0)
                ++cp1;

#if     AMIGA
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
                --cp1;
#endif
#if     VMS
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
                --cp1;
#endif
#if     CPM
        while (cp1!=&fname[0] && cp1[-1]!=':')
                --cp1;
#endif
#if     MSDOS
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
                --cp1;
#endif
#if     ST520
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
                --cp1;
#endif
#if     FINDER
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
                --cp1;
#endif
#if     V7 | USG | BSD
        while (cp1!=&fname[0] && cp1[-1]!='/')
                --cp1;
#endif
        cp2 = &bname[0];
        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
                *cp2++ = *cp1++;
        *cp2 = 0;

}

unqname(name)   /* make sure a buffer name is unique */

char *name;     /* name to check on */

{
        register char *sp;

        /* check to see if it is in the buffer list */
        while (bfind(name, 0, FALSE) != NULL) {

                /* go to the end of the name */
                sp = name;
                while (*sp)
                        ++sp;
                if (sp == name || (*(sp-1) <'0' || *(sp-1) > '8')) {
                        *sp++ = '0';
                        *sp = 0;
                } else
                        *(--sp) += 1;
        }

}

/*
 * Ask for a file name, and write the
 * contents of the current buffer to that file.
 * Update the remembered file name and clear the
 * buffer changed flag. This handling of file names
 * is different from the earlier versions, and
 * is more compatable with Gosling EMACS than
 * with ITS EMACS. Bound to "C-X C-W".
 */
filewrite(f, n)
{
        register WINDOW *wp;
        register int    s;
        char            fname[NFILEN];

        if (restflag)           /* don't allow this command if restricted */
                return(resterr());
        if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
                return (s);
        if ((s=writeout(fname)) == TRUE) {
                strcpy(curbp->b_fname, fname);
                curbp->b_flag &= ~BFCHG;
#if     BACKUP && !BUPEVS
                curbp->b_bupflg = TRUE;
#endif
                wp = wheadp;                    /* Update mode lines.   */
                while (wp != NULL) {
                        if (wp->w_bufp == curbp)
                                wp->w_flag |= WFMODE;
                        wp = wp->w_wndp;
                }
        }
        return (s);

}

/*
 * Save the contents of the current
 * buffer in its associated file. Do nothing
 * if nothing has changed (this may be a bug, not a
 * feature). Error if there is no remembered file
 * name for the buffer. Bound to "C-X C-S". May
 * get called by "C-Z".
 */
filesave(f, n)
{
        register WINDOW *wp;
        register int    s;

        if (curbp->b_mode&MDVIEW)        /* don't allow this command if  */
                return(rdonly());       /* we are in read only mode     */
        if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes.  */
                return (TRUE);
        if (curbp->b_fname[0] == 0) {           /* Must have a name.    */
                mlwrite("No file name");
                return (FALSE);
        }

        /* complain about truncated files */
        if ((curbp->b_flag&BFTRUNC) != 0) {
                if (mlyesno("Truncated file..write it out") == FALSE) {
                        mlwrite("[Aborted]");
                        return(FALSE);
                }
        }

        if ((s=writeout(curbp->b_fname)) == TRUE) {
                curbp->b_flag &= ~BFCHG;
#if     BACKUP && !BUPEVS
                curbp->b_bupflg = TRUE;
#endif
                wp = wheadp;                    /* Update mode lines.   */
                while (wp != NULL) {
                        if (wp->w_bufp == curbp)
                                wp->w_flag |= WFMODE;
                        wp = wp->w_wndp;
                }
        }
        return (s);

}

/*
 * This function performs the details of file
 * writing. Uses the file management routines in the
 * "fileio.c" package. The number of lines written is
 * displayed. Sadly, it looks inside a LINE; provide
 * a macro for this. Most of the grief is error
 * checking of some sort.
 * If backuping is enabled the original file gets renamed
 * to a backup file. It tests a flag of the current buffer.
 * Maybe it would be better to pass it as a parameter to
 * this function. But you don't need it if you don't enable
 * backuping.
 */
writeout(fn)
char    *fn;
{
        register int    s;
        register LINE   *lp;
        register int    nline;
#if     BACKUP
        char            save_file[NFILEN];
#endif

#if     CRYPT
        s = resetkey();
        if (s != TRUE)
                return(s);
#endif
        /* turn off ALL keyboard translation in case we get a dos error */
        TTkclose();

#if     !BACKUP
        if ((s=ffwopen(fn)) != FIOSUC) {        /* Open writes message. */
#else
        getsavefilename( save_file,  fn );
        if ((s=ffwopen( save_file )) != FIOSUC) {
                /* Open a file using a name which is guaranteed to be
                 * unique on this system (using PID). If the write is
                 * successfull it will be renamed to its real name. This
                 * way we don't have a problem with the backup file.
                 * If we get an error here, Open writes a message itself.
                 */
#endif
                TTkopen();
                return (FALSE);
        }
        mlwrite("[Writing...]");              /* tell us were writing */
        lp = lforw(curbp->b_linep);             /* First line.          */
        nline = 0;                              /* Number of lines.     */
        while (lp != curbp->b_linep) {
                if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
                        break;
                ++nline;
                lp = lforw(lp);
        }

        /* turn keyboard translation back on.
         * we do it here so we don't have to call
         * this function with every error return.
         */
        TTkopen();

        if (s == FIOSUC) {                      /* No write error.      */
                s = ffclose();
                if (s == FIOSUC) {              /* No close error.      */
                        if (nline == 1)
                                mlwrite("[Wrote 1 line]");
                        else
                                mlwrite("[Wrote %d lines]", nline);
                }
#if     BACKUP
#if     !BUPEVS
                if( curbp->b_bupflg ) {
                        if( unlink( fn ) != 0 && errno != ENOENT ) {
                                mlwrite( "SAVE FAILED" );
                                unlink( save_file );
                                return( FALSE );
                        }
                } else
#endif
                if( makebackup( fn ) == FALSE )
                        /* We couldn't remove an already existing,
                         * old backup file.
                         * Ask the user if he wishes to save the
                         * file anyway.
                         */
                        if( ( s = mlyesno( "Cannot create backup file -- Continue" )) != TRUE ) {
                                mlwrite( "SAVE FAILED" );
                                unlink( save_file );
                                return( s );
                        }
                        else if( unlink( fn ) != 0 && errno != ENOENT ) {
                                /* cannot delete original file */
                                mlwrite( "SAVE FAILED" );
                                unlink( save_file );
                                return( FALSE );
                        }
                frename( save_file, fn );
#endif
        } else {                                /* Ignore close error   */
                ffclose();                      /* if a write error.    */
#if     BACKUP
                unlink( save_file );            /* remove temp file     */
#endif
        }
        if (s != FIOSUC)                        /* Some sort of error.  */
                return (FALSE);
        return (TRUE);

}

/*
 * The command allows the user
 * to modify the file name associated with
 * the current buffer. It is like the "f" command
 * in UNIX "ed". The operation is simple; just zap
 * the name in the BUFFER structure, and mark the windows
 * as needing an update. You can type a blank line at the
 * prompt if you wish.
 * We set the backup flag here, too. When this buffer is
 * saved to disk the next time the 'new' file is backed up.
 */
filename(f, n)
{
        register WINDOW *wp;
        register int    s;
        char            fname[NFILEN];

        if (restflag)           /* don't allow this command if restricted */
                return(resterr());
        if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
                return (s);
#if     BACKUP && !BUPEVS
        if( strcmp( curbp->b_fname, fname ) != 0 )
                curbp->b_bupflg = FALSE;       /* next save makes backup file */
#endif
        if (s == FALSE)
                strcpy(curbp->b_fname, "");
        else
                strcpy(curbp->b_fname, fname);
        wp = wheadp;                            /* Update mode lines.   */
        while (wp != NULL) {
                if (wp->w_bufp == curbp)
                        wp->w_flag |= WFMODE;
                wp = wp->w_wndp;
        }
        curbp->b_mode &= ~MDVIEW;        /* no longer read only mode */
        return (TRUE);

}

/*
 * Insert file "fname" into the current
 * buffer, Called by insert file command. Return the final
 * status of the read.
 */
ifile(fname)
char    fname[];
{
        register LINE   *lp0;
        register LINE   *lp1;
        register LINE   *lp2;
        register int    i;
        register BUFFER *bp;
        register int    s;
        register int    nbytes;
        register int    nline;
        int             lflag;          /* any lines longer than allowed? */
        char mesg[NSTRING];

        bp = curbp;                             /* Cheap.               */
        bp->b_flag |= BFCHG;                 /* we have changed      */
        bp->b_flag &= ~BFINVS;                   /* and are not temporary*/
        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
                goto out;
        if (s == FIOFNF) {                      /* File not found.      */
                mlwrite("[No such file]");
                return(FALSE);
        }
        mlwrite("[Inserting file]");

#if     CRYPT
        s = resetkey();
        if (s != TRUE)
                return(s);
#endif
        /* back up a line and save the mark here */
        curwp->w_dotp = lback(curwp->w_dotp);
        curwp->w_doto = 0;
        curwp->w_markp = curwp->w_dotp;
        curwp->w_marko = 0;

        nline = 0;
        lflag = FALSE;
        while ((s=ffgetline()) == FIOSUC) {
                nbytes = strlen(fline);
                if ((lp1=lalloc(nbytes)) == NULL) {
                        s = FIOMEM;             /* Keep message on the  */
                        break;                  /* display.             */
                }
                lp0 = curwp->w_dotp; /* line previous to insert */
                lp2 = lp0->l_fp;     /* line after insert */

                /* re-link new line between lp0 and lp2 */
                lp2->l_bp = lp1;
                lp0->l_fp = lp1;
                lp1->l_bp = lp0;
                lp1->l_fp = lp2;

                /* and advance and write out the current line */
                curwp->w_dotp = lp1;
                for (i=0; i<nbytes; ++i)
                        lputc(lp1, i, fline[i]);
                ++nline;
        }
        ffclose();                              /* Ignore errors.       */
        curwp->w_markp = lforw(curwp->w_markp);
        strcpy(mesg, "[");
        if (s==FIOERR) {
                strcat(mesg, "I/O ERROR, ");
                curbp->b_flag |= BFTRUNC;
        }
        if (s == FIOMEM) {
                strcat(mesg, "OUT OF MEMORY, ");
                curbp->b_flag |= BFTRUNC;
        }
        sprintf(&mesg[strlen(mesg)], "Inserted %d line", nline);
        if (nline > 1)
                strcat(mesg, "s");
        strcat(mesg, "]");
        mlwrite(mesg);

out:
        /* advance to the next line and mark the window for changes */
        curwp->w_dotp = lforw(curwp->w_dotp);
        curwp->w_flag |= WFHARD | WFMODE;

        /* copy window parameters back to the buffer structure */
        curbp->b_dotp = curwp->w_dotp;
        curbp->b_doto = curwp->w_doto;
        curbp->b_markp = curwp->w_markp;
        curbp->b_marko = curwp->w_marko;

        if (s == FIOERR)                        /* False if error.      */
                return (FALSE);
        return (TRUE);

}

/* Make a backup file.
 * This is done by renaming the original file to a new name.
 * The name of the backup file is defined as follows:
 *
 * MSDOS: The base file name remains untouched, the extension has a tilde (~)
 *        as its first character and the other characters moved one place
 *        to the right.
 * UNIX:  The first character is a '#'. The rest of the name is moved one
 *        place to the right. The length of the filename may not exceed 14
 *        characters (for BSD the limit is 255).
 *
 * No other operating system supported by now.
 */
#if     BACKUP

makebackup( filename )
char    *filename;
{
        char    backupname[NFILEN];

        getbackupname( backupname, filename );
#if     MSDOS | V7 | USG | BSD
        if( !fexist( filename, 0 ))             /* no original file - */
                return( TRUE );                 /* nothing to backup  */
        if( fexist( backupname, 0 ))
                if( unlink( backupname ))       /* file is readonly */
                        return( FALSE );
        if( frename( filename, backupname ) != 0 )
                return( FALSE );
        return( TRUE );
#else                   /* for all other operating systems return fail */
        return( FALSE );
#endif  /* MSDOS | V7 | USG | BSD */

}

/* Make the name of the backup file according to the original file name
 * This routines knows about the filename possibilities of the different
 * operating systems.
 */
getbackupname( backup, file )
char    *backup;
char    *file;
{
        char    *temp[NFILEN];
        char    *dotpos;

        strcpy( backup, file );
#if     MSDOS
        if( (dotpos = strrchr( backup, '.' )) == NULL )
                strcat( backup, ".~" );
        else {
                strcpy( temp, dotpos +1 );
                dotpos[1] = '~';        /* first char of new extension      */
                temp[2] = '\0';         /* extension is at most 3 chars long*/
                strcat( backup, temp );
        }
#endif  /* MSDOS */

#if     V7 | USG | BSD
        if( (dotpos = strrchr( backup, '/' )) != NULL )
                strcpy( temp, dotpos +1 );
        else
                strcpy( temp, backup );
#if     BSD     /* BSD allows filenames up to 255 characters    */
        if( strlen( temp ) > 255 )
                temp[255] = '\0';
#else           /* other Unixes allow only 14 characters        */
        if( strlen( temp ) > 13 )
                temp[ 13] = '\0';
#endif
        strcpy( backup, "#" );
        strcat( backup, temp );
#endif  /* V7 | USG | BSD */

}

/* Return the name of the savefile in save_file.
 * This routines knows about the filename possibilities of the different
 * operating systems.
 */
getsavefilename( newname,  oldname )
char    *newname;
char    *oldname;
{
        char    *dotpos;

        strcpy( newname, oldname );
#if     MSDOS
        if( (dotpos = strrchr( newname, '/' )) != NULL ||
            (dotpos = strrchr( newname, '\\' )) != NULL )
                strcpy( dotpos +1,  bup_file );
        else if( (dotpos = strrchr( newname, ':' )) != NULL )
                strcpy( dotpos +1,  bup_file );
        else
                strcpy( newname,  bup_file );
#endif  /* MSDOS */

#if     V7 | USG | BSD
        if( (dotpos = strrchr( newname, '/' )) != NULL )
                strcpy( dotpos +1,  bup_file );
        else
                strcpy( newname,  bup_file );
#endif  /* V7 | USG | BSD */

}

#endif  /* BACKUP */

SHAR_EOF
fi # end of overwriting check
#       End of shell archive
exit 0

 
 
 

1. automatic file backup ownership

I am having a problem with automatic backup of files I need to change.

I need to change files that are not owned by me, but have a 666 mode.
When I do that, lemacs creates a backup copy of the original file with
the suffix ~ . The backup copy however, is being made with my
ownership (yes, the directory is 777). This confuses other systems.

My question is how can I make sure that backups will get the same
ownership of the originals, and if it is impossible, how can I
deactivate backup generation for a specific file/buffer.

--
Danny.
-------------------------------
Dan Bar Dov

Applied Materials (Israel)
3320 Scott Blvd. M/S 1119
Santa Clara, CA 95054


Phone:        office (408) 235-6514
              fax    (408) 986-3533
              home   (408) 739-5281
TimeZone:     PST
-------------------------------

2. SCSI Performance in vxWorks

3. can't seem to turn off the automatic backups!

4. procmail to backup outgoing mail

5. Automatic back-up problem

6. Announcemt: Thread-safe SNMP++

7. Multiple automatic backup files...

8. Global Catalog entries Missing

9. automatic creation of backup files

10. microEmacs 3.9e for the Macintosh -- documentation

11. MicroEmacs 3.9e manual

12. MicroEmacs 3.9e cursor key bindings for hp98550

13. "Extreme" bugs in MicroEmacs 3.9e