home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / mar94 / util / edit / vim.lha / Vim / src / fileio.c < prev    next >
C/C++ Source or Header  |  1993-12-14  |  22KB  |  929 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved
  4.  *
  5.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  6.  *                            Tim Thompson            twitch!tjt
  7.  *                            Tony Andrews            onecom!wldrdg!tony 
  8.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  9.  */
  10.  
  11. /*
  12.  * fileio.c: read from and write to a file
  13.  */
  14.  
  15. /*
  16.  * special feature of this version: NUL characters in the file are
  17.  * replaced by newline characters in memory. This allows us to edit
  18.  * binary files!
  19.  */
  20.  
  21. #ifdef MSDOS
  22. # include <io.h>
  23. #endif
  24.  
  25. #include "vim.h"
  26. #include "globals.h"
  27. #include "proto.h"
  28. #include "param.h"
  29. #include "fcntl.h"
  30.  
  31. #ifdef LATTICE
  32. # include <proto/dos.h>        /* for Lock() and UnLock() */
  33. #endif
  34.  
  35. static int    noendofline = FALSE;    /* Set to TRUE when last line has no
  36.                                                             EOL in binary mode */
  37.  
  38. #define BUFSIZE 4096                /* size of normal write buffer */
  39. #define SBUFSIZE 256                /* size of emergency write buffer */
  40.  
  41. static int  write_buf __ARGS((int, char *, int));
  42. static void do_mlines __ARGS((void));
  43.  
  44.     void
  45. filemess(name, s)
  46.     char        *name;
  47.     char        *s;
  48. {
  49.     smsg("\"%s\" %s", ((name == NULL) ? "" : name), s);
  50. }
  51.  
  52. /*
  53.  * Read lines from file 'fname' into the buffer after line 'from'.
  54.  *
  55.  * 1. We allocate blocks with m_blockalloc, as big as possible.
  56.  * 2. Each block is filled with characters from the file with a single read().
  57.  * 3. The lines are inserted in the buffer with appendline().
  58.  *
  59.  * (caller must check that fname != NULL)
  60.  */
  61.     int
  62. readfile(fname, sfname, from, newfile)
  63.     char           *fname;
  64.     char           *sfname;
  65.     linenr_t        from;
  66.     int                newfile;
  67. {
  68. #ifdef UNIX
  69.     int                 fd = -1;
  70. #else
  71.     int                 fd;
  72. #endif
  73.     register u_char     c;
  74.     register linenr_t    lnum = from;
  75.     register u_char     *ptr = NULL;            /* pointer into read buffer */
  76.     register u_char        *buffer = NULL;            /* read buffer */
  77.     register long        size;
  78.     register u_char        *p;
  79.     long                filesize;
  80. #define UNKNOWN        0x0fffffff                    /* file size is unknown */
  81.     linenr_t            linecnt = line_count;
  82.     int                    incomplete = FALSE;     /* was the last line incomplete? */
  83.     int                 error = 0;                /* read errors encountered */
  84.     long                linerest = 0;            /* remaining characters in line */
  85.     long                filerest;                /* remaining characters in file */
  86.     int                    firstpart = TRUE;        /* reading first part */
  87. #ifdef UNIX
  88.     int                    perm;
  89. #endif
  90.     int                    textmode = p_tx;        /* accept CR-LF for line break */
  91.  
  92.     if (sfname == NULL)
  93.         sfname = fname;
  94.     /*
  95.      * Use the short filename whenever possible.
  96.      * Avoids problems with networks and when directory names are changed.
  97.      */
  98.     if (!did_cd)
  99.         fname = sfname;
  100.  
  101.     if (bufempty())        /* special case: buffer has no lines */
  102.         linecnt = 0;
  103.  
  104. #ifdef UNIX
  105.         /*
  106.          * On Unix it is possible to read a directory, so we have to
  107.          * check for it before the open().
  108.          */
  109.     perm = getperm(fname);
  110. #ifdef _POSIX_SOURCE
  111.     if (perm >= 0 && !S_ISREG(perm))                /* not a regular file */
  112. #else
  113.     if (perm >= 0 && (perm & S_IFMT) != S_IFREG)    /* not a regular file */
  114. #endif
  115.     {
  116. #ifdef _POSIX_SOURCE
  117.         if (S_ISDIR(perm))
  118. #else
  119.         if ((perm & S_IFMT) == S_IFDIR)
  120. #endif
  121.             filemess(fname, "is a directory");
  122.         else
  123.             filemess(fname, "is not a file");
  124.         return TRUE;
  125.     }
  126. #endif
  127.  
  128.     if (
  129. #ifdef UNIX
  130.         !(perm & 0200) ||                        /* root's way to check RO */
  131. #endif
  132.         (fd = open(fname, O_RDWR)) == -1)        /* cannot open r/w */
  133.     {
  134.         if ((fd = open(fname, O_RDONLY)) == -1) /* cannot open at all */
  135.         {
  136. #ifdef MSDOS
  137.         /*
  138.          * The screen may be messed up by the "insert disk
  139.          * in drive b: and hit return" message
  140.          */
  141.             updateScreen(CLEAR);
  142. #endif
  143.  
  144. #ifndef UNIX
  145.         /*
  146.          * On MSDOS and Amiga we can't open a directory, check here.
  147.          */
  148.             if (isdir(fname) > 0)
  149.                 filemess(fname, "is a directory");
  150.             else
  151. #endif
  152.                 if (newfile)
  153.                     filemess(fname, "[New File]");
  154.  
  155.             return TRUE;
  156.         }
  157.         if (newfile)                        /* set file readonly */
  158.             p_ro = TRUE;
  159.     }
  160.     else if (newfile && !readonlymode)        /* set file not readonly */
  161.         p_ro = FALSE;
  162.  
  163.     if (newfile)
  164.         noendofline = FALSE;
  165.  
  166.     if ((filesize = lseek(fd, 0L, 2)) < 0)    /* get length of file */
  167.         filesize = UNKNOWN;
  168.     lseek(fd, 0L, 0);
  169.  
  170.     filemess(fname, "");                    /* show that we are busy */
  171.  
  172.     for (filerest = filesize; !error && !got_int && filerest != 0; breakcheck())
  173.     {
  174.         /*
  175.          * We allocate as much space for the file as we can get, plus
  176.          * space for the old line, one NUL in front and one NUL at the tail.
  177.          * The amount is limited by the fact that read() only can read
  178.          * upto max_unsigned characters (and other things).
  179.          * If we don't know the file size, just get one Kbyte.
  180.          */
  181.         if (filesize >= UNKNOWN)
  182.             size = 1024;
  183.         else if (filerest > 0xff00L)
  184.             size = 0xff00L;
  185.         else if (filerest < 10)
  186.             size = 10;
  187.         else
  188.             size = filerest;
  189.  
  190.         for ( ; size >= 10; size /= 2)
  191.         {
  192.             if ((buffer = (u_char *)m_blockalloc((u_long)(size + linerest + 4), FALSE))
  193.                         != NULL)
  194.                 break;
  195.         }
  196.         if (buffer == NULL)
  197.         {
  198.             emsg(e_outofmem);
  199.             error = 1;
  200.             break;
  201.         }
  202.         buffer[0] = NUL;    /* make sure there is a NUL in front of the first line */
  203.         ++buffer;
  204.         if (linerest)        /* copy characters from the previous buffer */
  205.         {
  206.             ptr -= linerest;
  207.             memmove((char *)buffer, (char *)ptr, linerest);
  208.             memset((char *)ptr, 1, linerest);    /* fill with non-NULs */
  209.             ptr[linerest - 1] = NUL;            /* add a NUL on the end */
  210.             free_line((char *)ptr);                /* free the space we don't use */
  211.         }
  212.         ptr = buffer + linerest;
  213.         
  214.         if ((size = (unsigned)read(fd, (char *)ptr, (size_t)size)) <= 0)
  215.         {
  216.             error = 2;
  217.             break;
  218.         }
  219.         if (filesize >= UNKNOWN)            /* if we don't know the file size */
  220.             filesize += size;                /* .. count the number of characters */
  221.         else                                /* .. otherwise */
  222.             filerest -= size;                /* .. compute the remaining length */
  223.  
  224.         /*
  225.          * when reading the first part of a file: guess EOL type
  226.          */
  227.         if (firstpart && p_ta)
  228.         {
  229.             for (p = ptr; p < ptr + size; ++p)
  230.                 if (*p == NL)
  231.                 {
  232.                     if (p > ptr && p[-1] == CR)    /* found CR-NL */
  233.                         textmode = TRUE;
  234.                     else                        /* found a single NL */
  235.                         textmode = FALSE;
  236.                         /* if editing a new file: may set p_tx */
  237.                     if (newfile && p_tx != textmode)
  238.                     {
  239.                         p_tx = textmode;
  240.                         paramchanged("tx");
  241.                     }
  242.                     break;
  243.                 }
  244.         }
  245.  
  246.         /*
  247.          * This loop is executed once for every character read.
  248.          * Keep it fast!
  249.          */
  250.         --ptr;
  251.         while (++ptr, --size >= 0)
  252.         {
  253.             if ((c = *ptr) != NUL && c != NL)    /* catch most common case */
  254.                 continue;
  255.             if (c == NUL)
  256.                 *ptr = NL;        /* NULs are replaced by newlines! */
  257.             else
  258.             {
  259.                 *ptr = NUL;        /* end of line */
  260.                 if (textmode && ptr[-1] == CR)    /* remove CR */
  261.                     ptr[-1] = NUL;
  262.                 if (!appendline(lnum, (char *)buffer))
  263.                 {
  264.                     error = 1;
  265.                     break;
  266.                 }
  267.                 ++lnum;
  268.                 buffer = ptr + 1;
  269.             }
  270.         }
  271.         linerest = ptr - buffer;
  272.         firstpart = FALSE;
  273.     }
  274.     if (lnum != from && !newfile)    /* added at least one line */
  275.         CHANGED;
  276.     if (error != 1 && linerest != 0)
  277.     {
  278.         /*
  279.          * If we get EOF in the middle of a line, note the fact and
  280.          * complete the line ourselves.
  281.          */
  282.         incomplete = TRUE;
  283.         if (newfile && p_bin)        /* remember for when writing */
  284.             noendofline = TRUE;
  285.         *ptr = NUL;
  286.         if (!appendline(lnum, (char *)buffer))
  287.             error = 1;
  288.         else if (!newfile)
  289.             CHANGED;
  290.     }
  291.     if (error == 2 && filesize >= UNKNOWN)    /* no error, just EOF encountered */
  292.     {
  293.         filesize -= UNKNOWN;
  294.         error = 0;
  295.     }
  296.  
  297.     close(fd);
  298.  
  299. #ifdef MSDOS        /* the screen may be messed up by the "insert disk
  300.                             in drive b: and hit return" message */
  301.     updateScreen(CLEAR);
  302. #endif
  303.  
  304.     if (got_int)
  305.     {
  306.         filemess(fname, e_interr);
  307.         return FALSE;            /* an interrupt isn't really an error */
  308.     }
  309.  
  310.     linecnt = line_count - linecnt;
  311.     smsg("\"%s\" %s%s%s%s%ld line%s, %ld character%s",
  312.             fname,
  313.             p_ro ? "[readonly] " : "",
  314.             incomplete ? "[Incomplete last line] " : "",
  315.             error ? "[READ ERRORS] " : "",
  316. #ifdef MSDOS
  317.             textmode ? "" : "[notextmode] ",
  318. #else
  319.             textmode ? "[textmode] " : "",
  320. #endif
  321.             (long)linecnt, plural((long)linecnt),
  322.             filesize, plural(filesize));
  323.  
  324.     if (error && newfile)    /* with errors we should not write the file */
  325.     {
  326.         p_ro = TRUE;
  327.         paramchanged("ro");
  328.     }
  329.  
  330.     u_clearline();        /* cannot use "U" command after adding lines */
  331.  
  332.     if (newfile)        /* edit a new file: read mode from lines */
  333.         do_mlines();
  334.     if (from < line_count)
  335.     {
  336.         Curpos.lnum = from + 1;    /* put cursor at first new line */
  337.         Curpos.col = 0;
  338.     }
  339.  
  340.     return FALSE;
  341. }
  342.  
  343. /*
  344.  * writeit - write to file 'fname' lines 'start' through 'end'
  345.  *
  346.  * We do our own buffering here because fwrite() is so slow.
  347.  *
  348.  * If forceit is true, we don't care for errors when attempting backups (jw).
  349.  * In case of an error everything possible is done to restore the original file.
  350.  * But when forceit is TRUE, we risk loosing it.
  351.  * When whole is TRUE and start == 1 and end == line_count, reset Changed.
  352.  */
  353.     int
  354. writeit(fname, sfname, start, end, append, forceit, whole)
  355.     char            *fname;
  356.     char            *sfname;
  357.     linenr_t        start, end;
  358.     int                append;
  359.     int                forceit;
  360.     int                whole;
  361. {
  362.     int                 fd;
  363.     char               *backup = NULL;
  364.     register char       *s;
  365.     register u_char       *ptr;
  366.     register u_char        c;
  367.     register int        len;
  368.     register linenr_t    lnum;
  369.     long                nchars;
  370.     char                *errmsg = NULL;
  371.     char                *buffer;
  372.     char                smallbuf[SBUFSIZE];
  373.     int                    bufsize;
  374.     long                 perm = -1;            /* file permissions */
  375.     int                    retval = TRUE;
  376.     int                    newfile = FALSE;    /* TRUE if file does not exist yet */
  377. #ifdef UNIX
  378.     struct stat            old;
  379.     int                    made_writable = FALSE;    /* 'w' bit has been set */
  380. #endif
  381. #ifdef AMIGA
  382.     BPTR                flock;
  383. #endif
  384.  
  385.     if (fname == NULL || *fname == NUL)        /* safety check */
  386.         return FALSE;
  387.     if (sfname == NULL)
  388.         sfname = fname;
  389.     /*
  390.      * Use the short filename whenever possible.
  391.      * Avoids problems with networks and when directory names are changed.
  392.      */
  393.     if (!did_cd)
  394.         fname = sfname;
  395.  
  396.     /*
  397.      * Disallow writing from .exrc and .vimrc in current directory for
  398.      * security reasons.
  399.      */
  400.     if (secure)
  401.     {
  402.         secure = 2;
  403.         emsg(e_curdir);
  404.         return FALSE;
  405.     }
  406.  
  407.     if (exiting)
  408.         settmode(0);            /* when exiting allow typahead now */
  409.  
  410.     filemess(fname, "");        /* show that we are busy */
  411.  
  412.     buffer = alloc(BUFSIZE);
  413.     if (buffer == NULL)            /* can't allocate big buffer, use small one */
  414.     {
  415.         buffer = smallbuf;
  416.         bufsize = SBUFSIZE;
  417.     }
  418.     else
  419.         bufsize = BUFSIZE;
  420.  
  421. #ifdef UNIX
  422.         /* get information about original file (if there is one) */
  423.     old.st_dev = old.st_ino = 0;
  424.     if (stat(fname, &old))
  425.         newfile = TRUE;
  426.     else
  427.     {
  428. #ifdef _POSIX_SOURCE
  429.         if (!S_ISREG(old.st_mode))              /* not a file */
  430. #else
  431.         if ((old.st_mode & S_IFMT) != S_IFREG)    /* not a file */
  432. #endif
  433.         {
  434. #ifdef _POSIX_SOURCE
  435.             if (S_ISDIR(old.st_mode))
  436. #else
  437.             if ((old.st_mode & S_IFMT) == S_IFDIR)
  438. #endif
  439.                 errmsg = "is a directory";
  440.             else
  441.                 errmsg = "is not a file";
  442.             goto fail;
  443.         }
  444.         perm = old.st_mode;
  445.     }
  446. /*
  447.  * If we are not appending, the file exists, and the 'writebackup' or
  448.  * 'backup' option is set, try to make a backup copy of the file.
  449.  */
  450.     if (!append && perm >= 0 && (p_wb || p_bk) &&
  451.                     (fd = open(fname, O_RDONLY)) >= 0)
  452.     {
  453.         int                bfd, buflen;
  454.         char            buf[BUFSIZE + 1], *wp;
  455.         int                some_error = FALSE;
  456.         struct stat        new;
  457.  
  458.         new.st_dev = new.st_ino = 0;
  459.  
  460.         /*
  461.          * Unix semantics has it, that we may have a writable file, 
  462.          * that cannot be recreated with a simple open(..., O_CREAT, ) e.g:
  463.          *  - the directory is not writable, 
  464.          *  - the file may be a symbolic link, 
  465.          *  - the file may belong to another user/group, etc.
  466.          *
  467.          * For these reasons, the existing writable file must be truncated and
  468.          * reused. Creation of a backup COPY will be attempted.
  469.          */
  470.         if ((backup = modname(fname, ".bak")) == NULL)
  471.         {
  472.             some_error = TRUE;
  473.             goto nobackup;
  474.         }            
  475.         if (!stat(backup, &new) &&
  476.                     new.st_dev == old.st_dev && new.st_ino == old.st_ino)
  477.         {
  478.             /*
  479.              * may happen when modname gave the same file back.
  480.              * E.g. silly link, or filename-length reached.
  481.              * If we don't check here, we either ruin the file when
  482.              * copying or erase it after writing. jw.
  483.              */
  484.             errmsg = "Invalid backup file (use ! to override)";
  485.             free(backup);
  486.             backup = NULL;    /* there is no backup file to delete */
  487.             goto nobackup;
  488.         }
  489.         remove(backup);        /* remove old backup, if present */
  490.         if ((bfd = open(backup, O_WRONLY | O_CREAT, 0666)) < 0)
  491.         {
  492.             /* 
  493.              * oops, no write/create permission here?
  494.              * try again in p_bdir directory. 
  495.              */
  496.             for (wp = fname + strlen(fname); wp >= fname; wp--)
  497.                 if (*wp == '/')
  498.                     break;
  499.             ++wp;
  500.             sprintf(buf, "%s/%s", p_bdir, wp);
  501.             free(backup);
  502.             if ((backup = modname(buf, ".bak")) == NULL)
  503.             {
  504.                 some_error = TRUE;
  505.                 goto nobackup;
  506.             }
  507.             if (!stat(backup, &new) &&
  508.                         new.st_dev == old.st_dev && new.st_ino == old.st_ino)
  509.             {
  510.                 errmsg = "Invalid backup file (use ! to override)";
  511.                 free(backup);
  512.                 backup = NULL;    /* there is no backup file to delete */
  513.                 goto nobackup;
  514.             }
  515.             remove(backup);
  516.             if ((bfd = open(backup, O_WRONLY | O_CREAT, 0666)) < 0)
  517.             {
  518.                 free(backup);
  519.                 backup = NULL;    /* there is no backup file to delete */
  520.                 errmsg = "Can't make backup file (use ! to override)";
  521.                 goto nobackup;
  522.             }
  523.         }
  524.         /* set file protection same as original file, but strip s-bit */
  525.         setperm(backup, perm & 0777);
  526.  
  527.         /* copy the file. */
  528.         while ((buflen = read(fd, buf, BUFSIZE)) > 0)
  529.         {
  530.             if (write_buf(bfd, buf, buflen) == -1)
  531.             {
  532.                 errmsg = "Can't write to backup file (use ! to override)";
  533.                 goto writeerr;
  534.             }
  535.         }
  536. writeerr:
  537.         close(bfd);
  538.         if (buflen < 0)
  539.             errmsg = "Can't read file for backup (use ! to override)";
  540. nobackup:
  541.         close(fd);
  542.     /* ignore errors when forceit is TRUE */
  543.         if ((some_error || errmsg) && !forceit)
  544.         {
  545.             retval = FALSE;
  546.             goto fail;
  547.         }
  548.         errmsg = NULL;
  549.     }
  550.         /* if forceit and the file was read-only: make it writable */
  551.     if (forceit && (old.st_uid == getuid()) && perm >= 0 && !(perm & 0200))
  552.      {
  553.         perm |= 0200;    
  554.         setperm(fname, perm);
  555.         made_writable = TRUE;
  556.             /* if we are writing to the current file, readonly makes no sense */
  557.         if (fname == Filename || fname == sFilename)
  558.             p_ro = FALSE;
  559.      }
  560. #else /* UNIX */
  561.  
  562. /*
  563.  * If we are not appending, the file exists, and the 'writebackup' or
  564.  * 'backup' option is set, make a backup.
  565.  * Do not make any backup, if "writebackup" and "backup" are 
  566.  * both switched off. This helps when editing large files on
  567.  * almost-full disks. (jw)
  568.  */
  569.     perm = getperm(fname);
  570.     if (perm < 0)
  571.         newfile = TRUE;
  572.     else if (isdir(fname) > 0)
  573.     {
  574.         errmsg = "is a directory";
  575.         goto fail;
  576.     }
  577.     if (!append && perm >= 0 && (p_wb || p_bk))
  578.     {
  579.         /*
  580.          * Form the backup file name - change path/fo.o.h to path/fo.o.h.bak
  581.          */
  582.         backup = modname(fname, ".bak");
  583.         if (backup == NULL)
  584.         {
  585.             if (!forceit)
  586.                 goto fail;
  587.         }
  588.         else
  589.         {
  590.             /*
  591.              * Delete any existing backup and move the current version to the backup.
  592.              * For safety, we don't remove the backup until the write has finished
  593.              * successfully. And if the 'backup' option is set, leave it around.
  594.              */
  595. #ifdef AMIGA
  596.             /*
  597.              * With MSDOS-compatible filesystems (crossdos, messydos) it is
  598.              * possible that the name of the backup file is the same as the
  599.              * original file. To avoid the chance of accidently deleting the
  600.              * original file (horror!) we lock it during the remove.
  601.              * This should not happen with ":w", because startscript() should
  602.              * detect this problem and set thisfile_sn, causing modname to
  603.              * return a correct ".bak" filename. This problem does exist with
  604.              * ":w filename", but then the original file will be somewhere else
  605.              * so the backup isn't really important. If autoscripting is off
  606.              * the rename may fail.
  607.              */
  608.             flock = Lock((UBYTE *)fname, (long)ACCESS_READ);
  609. #endif
  610.             remove(backup);
  611. #ifdef AMIGA
  612.             if (flock)
  613.                 UnLock(flock);
  614. #endif
  615.             len = rename(fname, backup);
  616.             if (len != 0)
  617.             {
  618.                 if (forceit)
  619.                 {
  620.                     free(backup);    /* don't do the rename below */
  621.                     backup = NULL;
  622.                 }
  623.                 else
  624.                 {
  625.                     errmsg = "Can't make backup file (use ! to override)";
  626.                     goto fail;
  627.                 }
  628.             }
  629.         }
  630.     }
  631. #endif /* UNIX */
  632.  
  633.         /* 
  634.          * We may try to open the file twice: If we can't write to the
  635.          * file and forceit is TRUE we delete the existing file and try to create
  636.          * a new one. If this still fails we may have lost the original file!
  637.          * (this may happen when the user reached his quotum for number of files).
  638.          * Appending will fail if the file does not exist and forceit is FALSE.
  639.          */
  640.     while ((fd = open(fname, O_WRONLY | (append ?
  641.                     (forceit ? (O_APPEND | O_CREAT) : O_APPEND) :
  642.                     (O_CREAT | O_TRUNC)), 0666)) < 0)
  643.      {
  644.         /*
  645.          * A forced write will try to create a new file if the old one is
  646.          * still readonly. This may also happen when the directory is
  647.          * read-only. In that case the remove() will fail.
  648.          */
  649.         if (!errmsg)
  650.         {
  651.             errmsg = "Can't open file for writing";
  652.             if (forceit)
  653.             {
  654. #ifdef UNIX
  655.                 /* we write to the file, thus it should be marked
  656.                                                     writable after all */
  657.                 perm |= 0200;        
  658.                 made_writable = TRUE;
  659.                 if (old.st_uid != getuid() || old.st_gid != getgid())
  660.                     perm &= 0777;
  661. #endif /* UNIX */
  662.                 if (!append)        /* don't remove when appending */
  663.                     remove(fname);
  664.                 continue;
  665.             }
  666.         }
  667. /*
  668.  * If we failed to open the file, we don't need a backup. Throw it away.
  669.  * If we moved or removed the original file try to put the backup in its place.
  670.  */
  671.          if (backup)
  672.         {
  673. #ifdef UNIX
  674.             struct stat st;
  675.  
  676.             /*
  677.              * There is a small chance that we removed the original, try
  678.              * to move the copy in its place.
  679.              * This won't work if the backup is in another file system!
  680.              * In that case we leave the copy around.
  681.              */
  682.             if (stat(fname, &st) < 0)    /* file does not exist */
  683.                 rename(backup, fname);    /* put the copy in its place */
  684.             if (stat(fname, &st) >= 0)    /* original file does exist */
  685.                 remove(backup);            /* throw away the copy */
  686. #else
  687.              rename(backup, fname);    /* try to put the original file back */
  688. #endif
  689.         }
  690.          goto fail;
  691.      }
  692.     errmsg = NULL;
  693.  
  694.     if (end > line_count)
  695.         end = line_count;
  696.     len = 0;
  697.     s = buffer;
  698.     nchars = 0;
  699.     for (lnum = start; lnum <= end; ++lnum)
  700.     {
  701.         /*
  702.          * The next while loop is done once for each character written.
  703.          * Keep it fast!
  704.          */
  705.         ptr = (u_char *)nr2ptr(lnum) - 1;
  706.         while ((c = *++ptr) != NUL)
  707.         {
  708.             if (c == NL)
  709.                 *s = NUL;        /* replace newlines with NULs */
  710.             else
  711.                 *s = c;
  712.             ++s;
  713.             if (++len != bufsize)
  714.                 continue;
  715.             if (write_buf(fd, buffer, bufsize) == -1)
  716.             {
  717.                 end = 0;                /* write error: break loop */
  718.                 break;
  719.             }
  720.             nchars += bufsize;
  721.             s = buffer;
  722.             len = 0;
  723.         }
  724.             /* write failed or last line has no EOL: stop here */
  725.         if (end == 0 || (p_bin && lnum == line_count && noendofline))
  726.             break;
  727.         if (p_tx)        /* write CR-NL */
  728.         {
  729.             *s = CR;
  730.             ++s;
  731.             if (++len == bufsize)
  732.             {
  733.                 if (write_buf(fd, buffer, bufsize) == -1)
  734.                 {
  735.                     end = 0;                /* write error: break loop */
  736.                     break;
  737.                 }
  738.                 nchars += bufsize;
  739.                 s = buffer;
  740.                 len = 0;
  741.             }
  742.         }
  743.         *s = NL;
  744.         ++s;
  745.         if (++len == bufsize && end)
  746.         {
  747.             if (write_buf(fd, buffer, bufsize) == -1)
  748.             {
  749.                 end = 0;                /* write error: break loop */
  750.                 break;
  751.             }
  752.             nchars += bufsize;
  753.             s = buffer;
  754.             len = 0;
  755.         }
  756.     }
  757.     if (len && end)
  758.     {
  759.         if (write_buf(fd, buffer, len) == -1)
  760.             end = 0;                /* write error */
  761.         nchars += len;
  762.     }
  763.  
  764.     if (close(fd) != 0)
  765.     {
  766.         errmsg = "Close failed";
  767.         goto fail;
  768.     }
  769. #ifdef UNIX
  770.     if (made_writable)
  771.         perm &= ~0200;            /* reset 'w' bit for security reasons */
  772. #endif
  773.     if (perm >= 0)
  774.         setperm(fname, perm);    /* set permissions of new file same as old file */
  775.  
  776.     if (end == 0)
  777.     {
  778.         errmsg = "write error (file system full?)";
  779.         goto fail;
  780.     }
  781.  
  782. #ifdef MSDOS        /* the screen may be messed up by the "insert disk
  783.                             in drive b: and hit return" message */
  784.     if (!exiting)
  785.         updateScreen(CLEAR);
  786. #endif
  787.  
  788.     lnum -= start;        /* compute number of written lines */
  789.     smsg("\"%s\"%s%s %ld line%s, %ld character%s",
  790.             fname,
  791.             newfile ? " [New File]" : " ",
  792. #ifdef MSDOS
  793.             p_tx ? "" : "[notextmode]",
  794. #else
  795.             p_tx ? "[textmode]" : "",
  796. #endif
  797.             (long)lnum, plural((long)lnum),
  798.             nchars, plural(nchars));
  799.     if (whole && start == 1 && end == line_count)    /* when written everything */
  800.     {
  801.         UNCHANGED;
  802.         NotEdited = FALSE;
  803.         startscript();        /* re-start auto script file */
  804.     }
  805.  
  806.     /*
  807.      * Remove the backup unless 'backup' option is set
  808.      */
  809.     if (!p_bk && backup != NULL && remove(backup) != 0)
  810.         emsg("Can't delete backup file");
  811.     
  812.     goto nofail;
  813.  
  814. fail:
  815. #ifdef MSDOS        /* the screen may be messed up by the "insert disk
  816.                             in drive b: and hit return" message */
  817.     updateScreen(CLEAR);
  818. #endif
  819. nofail:
  820.  
  821.     free((char *) backup);
  822.     free(buffer);
  823.  
  824.     if (errmsg != NULL)
  825.     {
  826.         filemess(fname, errmsg);
  827.         retval = FALSE;
  828.     }
  829.     return retval;
  830. }
  831.  
  832. /*
  833.  * write_buf: call write() to write a buffer
  834.  */
  835.     static int
  836. write_buf(fd, buf, len)
  837.     int        fd;
  838.     char    *buf;
  839.     int        len;
  840. {
  841.     int        wlen;
  842.  
  843.     while (len)
  844.     {
  845.         wlen = write(fd, buf, (size_t)len);
  846.         if (wlen <= 0)                /* error! */
  847.             return -1;
  848.         len -= wlen;
  849.         buf += wlen;
  850.     }
  851.     return 0;
  852. }
  853.  
  854. /*
  855.  * do_mlines() - process mode lines for the current file
  856.  *
  857.  * Returns immediately if the "ml" parameter isn't set.
  858.  */
  859. static void     chk_mline __ARGS((linenr_t));
  860.  
  861.     static void
  862. do_mlines()
  863. {
  864.     linenr_t        lnum;
  865.     int             nmlines;
  866.  
  867.     if (!p_ml || (nmlines = (int)p_mls) == 0)
  868.         return;
  869.  
  870.     for (lnum = 1; lnum <= line_count && lnum <= nmlines; ++lnum)
  871.         chk_mline(lnum);
  872.  
  873.     for (lnum = line_count; lnum > 0 && lnum > nmlines &&
  874.                             lnum > line_count - nmlines; --lnum)
  875.         chk_mline(lnum);
  876. }
  877.  
  878. /*
  879.  * chk_mline() - check a single line for a mode string
  880.  */
  881.     static void
  882. chk_mline(lnum)
  883.     linenr_t lnum;
  884. {
  885.     register char    *s;
  886.     register char    *e;
  887.     char            *cs;            /* local copy of any modeline found */
  888.     char            prev;
  889.     int                end;
  890.  
  891.     prev = ' ';
  892.     for (s = nr2ptr(lnum); *s != NUL; ++s)
  893.     {
  894.         if (isspace(prev) && (strncmp(s, "vi:", (size_t)3) == 0 || strncmp(s, "ex:", (size_t)3) == 0 || strncmp(s, "vim:", (size_t)4) == 0))
  895.         {
  896.             do
  897.                 ++s;
  898.             while (s[-1] != ':');
  899.             s = cs = strsave(s);
  900.             if (cs == NULL)
  901.                 break;
  902.             end = FALSE;
  903.             while (end == FALSE)
  904.             {
  905.                 while (*s == ' ' || *s == TAB)
  906.                     ++s;
  907.                 if (*s == NUL)
  908.                     break;
  909.                 for (e = s; (*e != ':' || *(e - 1) == '\\') && *e != NUL; ++e)
  910.                     ;
  911.                 if (*e == NUL)
  912.                     end = TRUE;
  913.                 *e = NUL;
  914.                 if (strncmp(s, "set ", (size_t)4) == 0) /* "vi:set opt opt opt: foo" */
  915.                 {
  916.                     doset(s + 4);
  917.                     break;
  918.                 }
  919.                 if (doset(s))        /* stop if error found */
  920.                     break;
  921.                 s = e + 1;
  922.             }
  923.             free(cs);
  924.             break;
  925.         }
  926.         prev = *s;
  927.     }
  928. }
  929.