home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / common / exf.c < prev    next >
Text File  |  1997-06-24  |  43KB  |  1,539 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1992, 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)exf.c    10.49 (Berkeley) 10/10/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/param.h>
  17. #include <sys/types.h>        /* XXX: param.h may not have included types.h */
  18. #include <sys/queue.h>
  19. #include <sys/stat.h>
  20.  
  21. /*
  22.  * We include <sys/file.h>, because the flock(2) and open(2) #defines
  23.  * were found there on historical systems.  We also include <fcntl.h>
  24.  * because the open(2) #defines are found there on newer systems.
  25.  */
  26. #include <sys/file.h>
  27.  
  28. #include <bitstring.h>
  29. #include <dirent.h>
  30. #include <errno.h>
  31. #include <fcntl.h>
  32. #include <limits.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <unistd.h>
  37.  
  38. #include "common.h"
  39.  
  40. static int    file_backup __P((SCR *, char *, char *));
  41. static void    file_cinit __P((SCR *));
  42. static void    file_comment __P((SCR *));
  43. static int    file_spath __P((SCR *, FREF *, struct stat *, int *));
  44.  
  45. /*
  46.  * file_add --
  47.  *    Insert a file name into the FREF list, if it doesn't already
  48.  *    appear in it.
  49.  *
  50.  * !!!
  51.  * The "if it doesn't already appear" changes vi's semantics slightly.  If
  52.  * you do a "vi foo bar", and then execute "next bar baz", the edit of bar
  53.  * will reflect the line/column of the previous edit session.  Historic nvi
  54.  * did not do this.  The change is a logical extension of the change where
  55.  * vi now remembers the last location in any file that it has ever edited,
  56.  * not just the previously edited file.
  57.  *
  58.  * PUBLIC: FREF *file_add __P((SCR *, CHAR_T *));
  59.  */
  60. FREF *
  61. file_add(sp, name)
  62.     SCR *sp;
  63.     CHAR_T *name;
  64. {
  65.     GS *gp;
  66.     FREF *frp, *tfrp;
  67.  
  68.     /*
  69.      * Return it if it already exists.  Note that we test against the
  70.      * user's name, whatever that happens to be, including if it's a
  71.      * temporary file.
  72.      *
  73.      * If the user added a file but was unable to initialize it, there
  74.      * can be file list entries where the name field is NULL.  Discard
  75.      * them the next time we see them.
  76.      */
  77.     gp = sp->gp;
  78.     if (name != NULL)
  79.         for (frp = gp->frefq.cqh_first;
  80.             frp != (FREF *)&gp->frefq; frp = frp->q.cqe_next) {
  81.             if (frp->name == NULL) {
  82.                 tfrp = frp->q.cqe_next;
  83.                 CIRCLEQ_REMOVE(&gp->frefq, frp, q);
  84.                 if (frp->name != NULL)
  85.                     free(frp->name);
  86.                 free(frp);
  87.                 frp = tfrp;
  88.                 continue;
  89.             }
  90.             if (!strcmp(frp->name, name))
  91.                 return (frp);
  92.         }
  93.  
  94.     /* Allocate and initialize the FREF structure. */
  95.     CALLOC(sp, frp, FREF *, 1, sizeof(FREF));
  96.     if (frp == NULL)
  97.         return (NULL);
  98.  
  99.     /*
  100.      * If no file name specified, or if the file name is a request
  101.      * for something temporary, file_init() will allocate the file
  102.      * name.  Temporary files are always ignored.
  103.      */
  104.     if (name != NULL && strcmp(name, TEMPORARY_FILE_STRING) &&
  105.         (frp->name = strdup(name)) == NULL) {
  106.         free(frp);
  107.         msgq(sp, M_SYSERR, NULL);
  108.         return (NULL);
  109.     }
  110.  
  111.     /* Append into the chain of file names. */
  112.     CIRCLEQ_INSERT_TAIL(&gp->frefq, frp, q);
  113.  
  114.     return (frp);
  115. }
  116.  
  117. /*
  118.  * file_init --
  119.  *    Start editing a file, based on the FREF structure.  If successsful,
  120.  *    let go of any previous file.  Don't release the previous file until
  121.  *    absolutely sure we have the new one.
  122.  *
  123.  * PUBLIC: int file_init __P((SCR *, FREF *, char *, int));
  124.  */
  125. int
  126. file_init(sp, frp, rcv_name, flags)
  127.     SCR *sp;
  128.     FREF *frp;
  129.     char *rcv_name;
  130.     int flags;
  131. {
  132.     EXF *ep;
  133.     RECNOINFO oinfo;
  134.     struct stat sb;
  135.     size_t psize;
  136.     int fd, exists, open_err, readonly;
  137.     char *oname, tname[MAXPATHLEN];
  138.  
  139.     open_err = readonly = 0;
  140.  
  141.     /*
  142.      * If the file is a recovery file, let the recovery code handle it.
  143.      * Clear the FR_RECOVER flag first -- the recovery code does set up,
  144.      * and then calls us!  If the recovery call fails, it's probably
  145.      * because the named file doesn't exist.  So, move boldly forward,
  146.      * presuming that there's an error message the user will get to see.
  147.      */
  148.     if (F_ISSET(frp, FR_RECOVER)) {
  149.         F_CLR(frp, FR_RECOVER);
  150.         return (rcv_read(sp, frp));
  151.     }
  152.  
  153.     /*
  154.      * Required FRP initialization; the only flag we keep is the
  155.      * cursor information.
  156.      */
  157.     F_CLR(frp, ~FR_CURSORSET);
  158.  
  159.     /*
  160.      * Required EXF initialization:
  161.      *    Flush the line caches.
  162.      *    Default recover mail file fd to -1.
  163.      *    Set initial EXF flag bits.
  164.      */
  165.     CALLOC_RET(sp, ep, EXF *, 1, sizeof(EXF));
  166.     ep->c_lno = ep->c_nlines = OOBLNO;
  167.     ep->rcv_fd = ep->fcntl_fd = -1;
  168.     F_SET(ep, F_FIRSTMODIFY);
  169.  
  170.     /*
  171.      * Scan the user's path to find the file that we're going to
  172.      * try and open.
  173.      */
  174.     if (file_spath(sp, frp, &sb, &exists))
  175.         return (1);
  176.  
  177.     /*
  178.      * If no name or backing file, for whatever reason, create a backing
  179.      * temporary file, saving the temp file name so we can later unlink
  180.      * it.  If the user never named this file, copy the temporary file name
  181.      * to the real name (we display that until the user renames it).
  182.      */
  183.     oname = frp->name;
  184.     if (LF_ISSET(FS_OPENERR) || oname == NULL || !exists) {
  185.         if (opts_empty(sp, O_DIRECTORY, 0))
  186.             goto err;
  187.         (void)snprintf(tname, sizeof(tname),
  188.             "%s/vi.XXXXXX", O_STR(sp, O_DIRECTORY));
  189.         if ((fd = mkstemp(tname)) == -1) {
  190. #if VI_DOSISH
  191.             /* try a shorter name... */
  192.             (void)snprintf(tname, sizeof(tname),
  193.                 "%s/VIXXXXXX", O_STR(sp, O_DIRECTORY));
  194.             if ((fd = mkstemp(tname)) == -1) {
  195. #endif
  196.             msgq(sp, M_SYSERR,
  197.                 "237|Unable to create temporary file");
  198.             goto err;
  199. #if VI_DOSISH
  200.             }
  201. #endif
  202.         }
  203.         (void)close(fd);
  204.  
  205.         if (frp->name == NULL)
  206.             F_SET(frp, FR_TMPFILE);
  207.         if ((frp->tname = strdup(tname)) == NULL ||
  208.             frp->name == NULL && (frp->name = strdup(tname)) == NULL) {
  209.             if (frp->tname != NULL)
  210.                 free(frp->tname);
  211.             msgq(sp, M_SYSERR, NULL);
  212.             (void)unlink(tname);
  213.             goto err;
  214.         }
  215.         oname = frp->tname;
  216.         psize = 1024;
  217.         if (!LF_ISSET(FS_OPENERR))
  218.             F_SET(frp, FR_NEWFILE);
  219.  
  220.         time(&ep->mtime);
  221.     } else {
  222.         /*
  223.          * XXX
  224.          * A seat of the pants calculation: try to keep the file in
  225.          * 15 pages or less.  Don't use a page size larger than 10K
  226.          * (vi should have good locality) or smaller than 1K.
  227.          */
  228.         psize = ((sb.st_size / 15) + 1023) / 1024;
  229.         if (psize > 10)
  230.             psize = 10;
  231.         if (psize == 0)
  232.             psize = 1;
  233.         psize *= 1024;
  234.  
  235.         F_SET(ep, F_DEVSET);
  236.         ep->mdev = sb.st_dev;
  237.         ep->minode = sb.st_ino;
  238.  
  239.         ep->mtime = sb.st_mtime;
  240.  
  241.         if (!S_ISREG(sb.st_mode))
  242.             msgq_str(sp, M_ERR, oname,
  243.                 "238|Warning: %s is not a regular file");
  244.     }
  245.  
  246.     /* Set up recovery. */
  247.     memset(&oinfo, 0, sizeof(RECNOINFO));
  248.     oinfo.bval = '\n';            /* Always set. */
  249.     oinfo.psize = psize;
  250.     oinfo.flags = F_ISSET(sp->gp, G_SNAPSHOT) ? R_SNAPSHOT : 0;
  251.     if (rcv_name == NULL) {
  252.         if (!rcv_tmp(sp, ep, frp->name))
  253.             oinfo.bfname = ep->rcv_path;
  254.     } else {
  255.         if ((ep->rcv_path = strdup(rcv_name)) == NULL) {
  256.             msgq(sp, M_SYSERR, NULL);
  257.             goto err;
  258.         }
  259.         oinfo.bfname = ep->rcv_path;
  260.         F_SET(ep, F_MODIFIED);
  261.     }
  262.  
  263.     /* Open a db structure. */
  264.     if ((ep->db = dbopen(rcv_name == NULL ? oname : NULL,
  265.         O_NONBLOCK | O_RDONLY,
  266.         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
  267.         DB_RECNO, &oinfo)) == NULL) {
  268.         msgq_str(sp,
  269.             M_SYSERR, rcv_name == NULL ? oname : rcv_name, "%s");
  270.         /*
  271.          * !!!
  272.          * Historically, vi permitted users to edit files that couldn't
  273.          * be read.  This isn't useful for single files from a command
  274.          * line, but it's quite useful for "vi *.c", since you can skip
  275.          * past files that you can't read.
  276.          */ 
  277.         open_err = 1;
  278.         goto oerr;
  279.     }
  280.  
  281.     /*
  282.      * Do the remaining things that can cause failure of the new file,
  283.      * mark and logging initialization.
  284.      */
  285.     if (mark_init(sp, ep) || log_init(sp, ep))
  286.         goto err;
  287.  
  288.     /*
  289.      * Set the alternate file name to be the file we're discarding.
  290.      *
  291.      * !!!
  292.      * Temporary files can't become alternate files, so there's no file
  293.      * name.  This matches historical practice, although it could only
  294.      * happen in historical vi as the result of the initial command, i.e.
  295.      * if vi was executed without a file name.
  296.      */
  297.     if (LF_ISSET(FS_SETALT))
  298.         set_alt_name(sp, sp->frp == NULL ||
  299.             F_ISSET(sp->frp, FR_TMPFILE) ? NULL : sp->frp->name);
  300.  
  301.     /*
  302.      * Close the previous file; if that fails, close the new one and run
  303.      * for the border.
  304.      *
  305.      * !!!
  306.      * There's a nasty special case.  If the user edits a temporary file,
  307.      * and then does an ":e! %", we need to re-initialize the backing
  308.      * file, but we can't change the name.  (It's worse -- we're dealing
  309.      * with *names* here, we can't even detect that it happened.)  Set a
  310.      * flag so that the file_end routine ignores the backing information
  311.      * of the old file if it happens to be the same as the new one.
  312.      *
  313.      * !!!
  314.      * Side-effect: after the call to file_end(), sp->frp may be NULL.
  315.      */
  316.     if (sp->ep != NULL) {
  317.         F_SET(frp, FR_DONTDELETE);
  318.         if (file_end(sp, NULL, LF_ISSET(FS_FORCE))) {
  319.             (void)file_end(sp, ep, 1);
  320.             goto err;
  321.         }
  322.         F_CLR(frp, FR_DONTDELETE);
  323.     }
  324.  
  325.     /*
  326.      * Lock the file; if it's a recovery file, it should already be
  327.      * locked.  Note, we acquire the lock after the previous file
  328.      * has been ended, so that we don't get an "already locked" error
  329.      * for ":edit!".
  330.      *
  331.      * XXX
  332.      * While the user can't interrupt us between the open and here,
  333.      * there's a race between the dbopen() and the lock.  Not much
  334.      * we can do about it.
  335.      *
  336.      * XXX
  337.      * We don't make a big deal of not being able to lock the file.  As
  338.      * locking rarely works over NFS, and often fails if the file was
  339.      * mmap(2)'d, it's far too common to do anything like print an error
  340.      * message, let alone make the file readonly.  At some future time,
  341.      * when locking is a little more reliable, this should change to be
  342.      * an error.
  343.      */
  344.     if (rcv_name == NULL)
  345.         switch (file_lock(sp, oname,
  346.             &ep->fcntl_fd, ep->db->fd(ep->db), 0)) {
  347.         case LOCK_FAILED:
  348.             F_SET(frp, FR_UNLOCKED);
  349.             break;
  350.         case LOCK_UNAVAIL:
  351.             readonly = 1;
  352.             msgq_str(sp, M_INFO, oname,
  353.                 "239|%s already locked, session is read-only");
  354.             break;
  355.         case LOCK_SUCCESS:
  356.             break;
  357.         }
  358.  
  359.     /*
  360.          * Historically, the readonly edit option was set per edit buffer in
  361.          * vi, unless the -R command-line option was specified or the program
  362.          * was executed as "view".  (Well, to be truthful, if the letter 'w'
  363.          * occurred anywhere in the program name, but let's not get into that.)
  364.      * So, the persistant readonly state has to be stored in the screen
  365.      * structure, and the edit option value toggles with the contents of
  366.      * the edit buffer.  If the persistant readonly flag is set, set the
  367.      * readonly edit option.
  368.      *
  369.      * Otherwise, try and figure out if a file is readonly.  This is a
  370.      * dangerous thing to do.  The kernel is the only arbiter of whether
  371.      * or not a file is writeable, and the best that a user program can
  372.      * do is guess.  Obvious loopholes are files that are on a file system
  373.      * mounted readonly (access catches this one on a few systems), or
  374.      * alternate protection mechanisms, ACL's for example, that we can't
  375.      * portably check.  Lots of fun, and only here because users whined.
  376.      *
  377.      * !!!
  378.      * Historic vi displayed the readonly message if none of the file
  379.      * write bits were set, or if an an access(2) call on the path
  380.      * failed.  This seems reasonable.  If the file is mode 444, root
  381.      * users may want to know that the owner of the file did not expect
  382.      * it to be written.
  383.      *
  384.      * Historic vi set the readonly bit if no write bits were set for
  385.      * a file, even if the access call would have succeeded.  This makes
  386.      * the superuser force the write even when vi expects that it will
  387.      * succeed.  I'm less supportive of this semantic, but it's historic
  388.      * practice and the conservative approach to vi'ing files as root.
  389.      *
  390.      * It would be nice if there was some way to update this when the user
  391.      * does a "^Z; chmod ...".  The problem is that we'd first have to
  392.      * distinguish between readonly bits set because of file permissions
  393.      * and those set for other reasons.  That's not too hard, but deciding
  394.      * when to reevaluate the permissions is trickier.  An alternative
  395.      * might be to turn off the readonly bit if the user forces a write
  396.      * and it succeeds.
  397.      *
  398.      * XXX
  399.      * Access(2) doesn't consider the effective uid/gid values.  This
  400.      * probably isn't a problem for vi when it's running standalone.
  401.      */
  402.     if (readonly || F_ISSET(sp, SC_READONLY) ||
  403.         !F_ISSET(frp, FR_NEWFILE) &&
  404.         (!(sb.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) ||
  405.         access(frp->name, W_OK)))
  406.         O_SET(sp, O_READONLY);
  407.     else
  408.         O_CLR(sp, O_READONLY);
  409.  
  410.     /* Switch... */
  411.     ++ep->refcnt;
  412.     sp->ep = ep;
  413.     sp->frp = frp;
  414.  
  415.     /* Set the initial cursor position, queue initial command. */
  416.     file_cinit(sp);
  417.  
  418.     /* Redraw the screen from scratch, schedule a welcome message. */
  419.     F_SET(sp, SC_SCR_REFORMAT | SC_STATUS);
  420.  
  421.     return (0);
  422.  
  423. err:    if (frp->name != NULL) {
  424.         free(frp->name);
  425.         frp->name = NULL;
  426.     }
  427.     if (frp->tname != NULL) {
  428.         (void)unlink(frp->tname);
  429.         free(frp->tname);
  430.         frp->tname = NULL;
  431.     }
  432.  
  433. oerr:    if (F_ISSET(ep, F_RCV_ON))
  434.         (void)unlink(ep->rcv_path);
  435.     if (ep->rcv_path != NULL) {
  436.         free(ep->rcv_path);
  437.         ep->rcv_path = NULL;
  438.     }
  439.     if (ep->db != NULL)
  440.         (void)ep->db->close(ep->db);
  441.     free(ep);
  442.  
  443.     return (open_err ?
  444.         file_init(sp, frp, rcv_name, flags | FS_OPENERR) : 1);
  445. }
  446.  
  447. /*
  448.  * file_spath --
  449.  *    Scan the user's path to find the file that we're going to
  450.  *    try and open.
  451.  */
  452. static int
  453. file_spath(sp, frp, sbp, existsp)
  454.     SCR *sp;
  455.     FREF *frp;
  456.     struct stat *sbp;
  457.     int *existsp;
  458. {
  459.     CHAR_T savech;
  460.     size_t len;
  461.     int found;
  462.     char *name, *p, *t, path[MAXPATHLEN];
  463.  
  464.     /*
  465.      * If the name is NULL or an explicit reference (i.e., the first
  466.      * component is . or ..) ignore the O_PATH option.
  467.      */
  468.     name = frp->name;
  469.     if (name == NULL) {
  470.         *existsp = 0;
  471.         return (0);
  472.     }
  473.     if (name[0] == '/' || name[0] == '.' &&
  474.         (name[1] == '/' || name[1] == '.' && name[2] == '/')) {
  475.         *existsp = !stat(name, sbp);
  476.         return (0);
  477.     }
  478.  
  479.     /* Try . */
  480.     if (!stat(name, sbp)) {
  481.         *existsp = 1;
  482.         return (0);
  483.     }
  484.  
  485.     /* Try the O_PATH option values. */
  486.     for (found = 0, p = t = O_STR(sp, O_PATH);; ++p)
  487.         if (*p == ':' || *p == '\0') {
  488.             if (t < p - 1) {
  489.                 savech = *p;
  490.                 *p = '\0';
  491.                 len = snprintf(path,
  492.                     sizeof(path), "%s/%s", t, name);
  493.                 *p = savech;
  494.                 if (!stat(path, sbp)) {
  495.                     found = 1;
  496.                     break;
  497.                 }
  498.             }
  499.             t = p + 1;
  500.             if (*p == '\0')
  501.                 break;
  502.         }
  503.  
  504.     /* If we found it, build a new pathname and discard the old one. */
  505.     if (found) {
  506.         MALLOC_RET(sp, p, char *, len + 1);
  507.         memcpy(p, path, len + 1);
  508.         free(frp->name);
  509.         frp->name = p;
  510.     }
  511.     *existsp = found;
  512.     return (0);
  513. }
  514.  
  515. /*
  516.  * file_cinit --
  517.  *    Set up the initial cursor position.
  518.  */
  519. static void
  520. file_cinit(sp)
  521.     SCR *sp;
  522. {
  523.     GS *gp;
  524.     MARK m;
  525.     size_t len;
  526.     int nb;
  527.  
  528.     /* Set some basic defaults. */
  529.     sp->lno = 1;
  530.     sp->cno = 0;
  531.  
  532.     /*
  533.      * Historically, initial commands (the -c option) weren't executed
  534.      * until a file was loaded, e.g. "vi +10 nofile", followed by an
  535.      * :edit or :tag command, would execute the +10 on the file loaded
  536.      * by the subsequent command, (assuming that it existed).  This
  537.      * applied as well to files loaded using the tag commands, and we
  538.      * follow that historic practice.  Also, all initial commands were
  539.      * ex commands and were always executed on the last line of the file.
  540.      *
  541.      * Otherwise, if no initial command for this file:
  542.      *    If in ex mode, move to the last line, first nonblank character.
  543.      *    If the file has previously been edited, move to the last known
  544.      *      position, and check it for validity.
  545.      *    Otherwise, move to the first line, first nonblank.
  546.      *
  547.      * This gets called by the file init code, because we may be in a
  548.      * file of ex commands and we want to execute them from the right
  549.      * location in the file.
  550.      */
  551.     nb = 0;
  552.     gp = sp->gp;
  553.     if (gp->c_option != NULL && !F_ISSET(sp->frp, FR_NEWFILE)) {
  554.         if (db_last(sp, &sp->lno))
  555.             return;
  556.         if (sp->lno == 0) {
  557.             sp->lno = 1;
  558.             sp->cno = 0;
  559.         }
  560.         if (ex_run_str(sp,
  561.             "-c option", gp->c_option, strlen(gp->c_option), 1, 1))
  562.             return;
  563.         gp->c_option = NULL;
  564.     } else if (F_ISSET(sp, SC_EX)) {
  565.         if (db_last(sp, &sp->lno))
  566.             return;
  567.         if (sp->lno == 0) {
  568.             sp->lno = 1;
  569.             sp->cno = 0;
  570.             return;
  571.         }
  572.         nb = 1;
  573.     } else {
  574.         if (F_ISSET(sp->frp, FR_CURSORSET)) {
  575.             sp->lno = sp->frp->lno;
  576.             sp->cno = sp->frp->cno;
  577.  
  578.             /* If returning to a file in vi, center the line. */
  579.              F_SET(sp, SC_SCR_CENTER);
  580.         } else {
  581.             if (O_ISSET(sp, O_COMMENT))
  582.                 file_comment(sp);
  583.             else
  584.                 sp->lno = 1;
  585.             nb = 1;
  586.         }
  587.         if (db_get(sp, sp->lno, 0, NULL, &len)) {
  588.             sp->lno = 1;
  589.             sp->cno = 0;
  590.             return;
  591.         }
  592.         if (!nb && sp->cno > len)
  593.             nb = 1;
  594.     }
  595.     if (nb) {
  596.         sp->cno = 0;
  597.         (void)nonblank(sp, sp->lno, &sp->cno);
  598.     }
  599.  
  600.     /*
  601.      * !!!
  602.      * The initial column is also the most attractive column.
  603.      */
  604.     sp->rcm = sp->cno;
  605.  
  606.     /*
  607.      * !!!
  608.      * Historically, vi initialized the absolute mark, but ex did not.
  609.      * Which meant, that if the first command in ex mode was "visual",
  610.      * or if an ex command was executed first (e.g. vi +10 file) vi was
  611.      * entered without the mark being initialized.  For consistency, if
  612.      * the file isn't empty, we initialize it for everyone, believing
  613.      * that it can't hurt, and is generally useful.  Not initializing it
  614.      * if the file is empty is historic practice, although it has always
  615.      * been possible to set (and use) marks in empty vi files.
  616.      */
  617.     m.lno = sp->lno;
  618.     m.cno = sp->cno;
  619.     (void)mark_set(sp, ABSMARK1, &m, 0);
  620. }
  621.  
  622. /*
  623.  * file_end --
  624.  *    Stop editing a file.
  625.  *
  626.  * PUBLIC: int file_end __P((SCR *, EXF *, int));
  627.  */
  628. int
  629. file_end(sp, ep, force)
  630.     SCR *sp;
  631.     EXF *ep;
  632.     int force;
  633. {
  634.     FREF *frp;
  635.  
  636.     /*
  637.      * !!!
  638.      * ep MAY NOT BE THE SAME AS sp->ep, DON'T USE THE LATTER.
  639.      * (If argument ep is NULL, use sp->ep.)
  640.      *
  641.      * If multiply referenced, just decrement the count and return.
  642.      */
  643.     if (ep == NULL)
  644.         ep = sp->ep;
  645.     if (--ep->refcnt != 0)
  646.         return (0);
  647.  
  648.     /*
  649.      *
  650.      * Clean up the FREF structure.
  651.      *
  652.      * Save the cursor location.
  653.      *
  654.      * XXX
  655.      * It would be cleaner to do this somewhere else, but by the time
  656.      * ex or vi knows that we're changing files it's already happened.
  657.      */
  658.     frp = sp->frp;
  659.     frp->lno = sp->lno;
  660.     frp->cno = sp->cno;
  661.     F_SET(frp, FR_CURSORSET);
  662.  
  663.     /*
  664.      * We may no longer need the temporary backing file, so clean it
  665.      * up.  We don't need the FREF structure either, if the file was
  666.      * never named, so lose it.
  667.      *
  668.      * !!!
  669.      * Re: FR_DONTDELETE, see the comment above in file_init().
  670.      * --- EMX: can't unlink an open file...
  671.      */
  672. #ifndef VI_DOSISH
  673.     if (!F_ISSET(frp, FR_DONTDELETE) && frp->tname != NULL) {
  674.         if (unlink(frp->tname))
  675.             msgq_str(sp, M_SYSERR, frp->tname, "240|%s: remove");
  676.         free(frp->tname);
  677.         frp->tname = NULL;
  678.         if (F_ISSET(frp, FR_TMPFILE)) {
  679.             CIRCLEQ_REMOVE(&sp->gp->frefq, frp, q);
  680.             if (frp->name != NULL)
  681.                 free(frp->name);
  682.             free(frp);
  683.         }
  684.         sp->frp = NULL;
  685.     }
  686. #endif
  687.  
  688.     /*
  689.      * Clean up the EXF structure.
  690.      *
  691.      * Close the db structure.
  692.      */
  693.     if (ep->db->close != NULL && ep->db->close(ep->db) && !force) {
  694.         msgq_str(sp, M_SYSERR, frp->name, "241|%s: close");
  695.         ++ep->refcnt;
  696.         return (1);
  697.     }
  698.  
  699. #if VI_DOSISH
  700.     /* We couldn't do this while it was open (EACCES)... */
  701.     if (!F_ISSET(frp, FR_DONTDELETE) && frp->tname != NULL) {
  702.         if (unlink(frp->tname))
  703.             msgq_str(sp, M_SYSERR, frp->tname, "240|%s: remove");
  704.         free(frp->tname);
  705.         frp->tname = NULL;
  706.         if (F_ISSET(frp, FR_TMPFILE)) {
  707.             CIRCLEQ_REMOVE(&sp->gp->frefq, frp, q);
  708.             if (frp->name != NULL)
  709.                 free(frp->name);
  710.             free(frp);
  711.         }
  712.         sp->frp = NULL;
  713.     }
  714. #endif
  715.  
  716.     /* COMMITTED TO THE CLOSE.  THERE'S NO GOING BACK... */
  717.  
  718.     /* Stop logging. */
  719.     (void)log_end(sp, ep);
  720.  
  721.     /* Free up any marks. */
  722.     (void)mark_end(sp, ep);
  723.  
  724.     /*
  725.      * Delete recovery files, close the open descriptor, free recovery
  726.      * memory.  See recover.c for a description of the protocol.
  727.      *
  728.      * XXX
  729.      * Unlink backup file first, we can detect that the recovery file
  730.      * doesn't reference anything when the user tries to recover it.
  731.      * There's a race, here, obviously, but it's fairly small.
  732.      * --- EMX: if the file is open it cannot be unlink()ed; rearrange
  733.      */
  734. #if VI_DOSISH
  735.     if (ep->fcntl_fd != -1)
  736.         (void)close(ep->fcntl_fd);
  737.     if (ep->rcv_fd != -1)
  738.         (void)close(ep->rcv_fd);
  739. #endif
  740.     if (!F_ISSET(ep, F_RCV_NORM)) {
  741.         if (ep->rcv_path != NULL && unlink(ep->rcv_path))
  742.             msgq_str(sp, M_SYSERR, ep->rcv_path, "242|%s: remove");
  743.         if (ep->rcv_mpath != NULL && unlink(ep->rcv_mpath))
  744.             msgq_str(sp, M_SYSERR, ep->rcv_mpath, "243|%s: remove");
  745.     }
  746. #ifndef VI_DOSISH
  747.     if (ep->fcntl_fd != -1)
  748.         (void)close(ep->fcntl_fd);
  749.     if (ep->rcv_fd != -1)
  750.         (void)close(ep->rcv_fd);
  751. #endif
  752.     if (ep->rcv_path != NULL)
  753.         free(ep->rcv_path);
  754.     if (ep->rcv_mpath != NULL)
  755.         free(ep->rcv_mpath);
  756.  
  757.     free(ep);
  758.     return (0);
  759. }
  760.  
  761. /*
  762.  * file_write --
  763.  *    Write the file to disk.  Historic vi had fairly convoluted
  764.  *    semantics for whether or not writes would happen.  That's
  765.  *    why all the flags.
  766.  *
  767.  * PUBLIC: int file_write __P((SCR *, MARK *, MARK *, char *, int));
  768.  */
  769. int
  770. file_write(sp, fm, tm, name, flags)
  771.     SCR *sp;
  772.     MARK *fm, *tm;
  773.     char *name;
  774.     int flags;
  775. {
  776.     enum { NEWFILE, OLDFILE } mtype;
  777.     struct stat sb;
  778.     EXF *ep;
  779.     FILE *fp;
  780.     FREF *frp;
  781.     MARK from, to;
  782.     size_t len;
  783.     u_long nlno, nch;
  784.     int fd, nf, noname, oflags, rval;
  785.     char *p, *s, *t, buf[MAXPATHLEN + 64];
  786.     const char *msgstr;
  787.  
  788.     ep = sp->ep;
  789.     frp = sp->frp;
  790.  
  791.     /*
  792.      * Writing '%', or naming the current file explicitly, has the
  793.      * same semantics as writing without a name.
  794.      */
  795.     if (name == NULL || !strcmp(name, frp->name)) {
  796.         noname = 1;
  797.         name = frp->name;
  798.     } else
  799.         noname = 0;
  800.  
  801.     /* Can't write files marked read-only, unless forced. */
  802.     if (!LF_ISSET(FS_FORCE) && noname && O_ISSET(sp, O_READONLY)) {
  803.         msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ?
  804.             "244|Read-only file, not written; use ! to override" :
  805.             "245|Read-only file, not written");
  806.         return (1);
  807.     }
  808.  
  809.     /* If not forced, not appending, and "writeany" not set ... */
  810.     if (!LF_ISSET(FS_FORCE | FS_APPEND) && !O_ISSET(sp, O_WRITEANY)) {
  811.         /* Don't overwrite anything but the original file. */
  812.         if ((!noname || F_ISSET(frp, FR_NAMECHANGE)) &&
  813.             !stat(name, &sb)) {
  814.             msgq_str(sp, M_ERR, name,
  815.                 LF_ISSET(FS_POSSIBLE) ?
  816.                 "246|%s exists, not written; use ! to override" :
  817.                 "247|%s exists, not written");
  818.             return (1);
  819.         }
  820.  
  821.         /*
  822.          * Don't write part of any existing file.  Only test for the
  823.          * original file, the previous test catches anything else.
  824.          */
  825.         if (!LF_ISSET(FS_ALL) && noname && !stat(name, &sb)) {
  826.             msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ?
  827.                 "248|Partial file, not written; use ! to override" :
  828.                 "249|Partial file, not written");
  829.             return (1);
  830.         }
  831.     }
  832.  
  833.     /*
  834.      * Figure out if the file already exists -- if it doesn't, we display
  835.      * the "new file" message.  The stat might not be necessary, but we
  836.      * just repeat it because it's easier than hacking the previous tests.
  837.      * The information is only used for the user message and modification
  838.      * time test, so we can ignore the obvious race condition.
  839.      *
  840.      * One final test.  If we're not forcing or appending the current file,
  841.      * and we have a saved modification time, object if the file changed
  842.      * since we last edited or wrote it, and make them force it.
  843.      */
  844.     if (stat(name, &sb))
  845.         mtype = NEWFILE;
  846.     else {
  847.         if (noname && !LF_ISSET(FS_FORCE | FS_APPEND) &&
  848.             (F_ISSET(ep, F_DEVSET) &&
  849. #if !VI_DOSISH
  850.             (sb.st_dev != ep->mdev || sb.st_ino != ep->minode) ||
  851. #endif
  852.             sb.st_mtime != ep->mtime)) {
  853.             msgq_str(sp, M_ERR, name, LF_ISSET(FS_POSSIBLE) ?
  854. "250|%s: file modified more recently than this copy; use ! to override" :
  855. "251|%s: file modified more recently than this copy");
  856.             return (1);
  857.         }
  858.  
  859.         mtype = OLDFILE;
  860.     }
  861.  
  862.     /* Set flags to create, write, and either append or truncate. */
  863.     oflags = O_CREAT | O_WRONLY |
  864.         (LF_ISSET(FS_APPEND) ? O_APPEND : O_TRUNC);
  865.  
  866.     /* Backup the file if requested. */
  867.     if (!opts_empty(sp, O_BACKUP, 1) &&
  868.         file_backup(sp, name, O_STR(sp, O_BACKUP)) && !LF_ISSET(FS_FORCE))
  869.         return (1);
  870.  
  871.     /* Open the file. */
  872.     SIGBLOCK;
  873.     if ((fd = open(name, oflags,
  874.         S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0) {
  875.         msgq_str(sp, M_SYSERR, name, "%s");
  876.         SIGUNBLOCK;
  877.         return (1);
  878.     }
  879.     SIGUNBLOCK;
  880.  
  881.     /* Try and get a lock. */
  882.     if (!noname && file_lock(sp, NULL, NULL, fd, 0) == LOCK_UNAVAIL)
  883.         msgq_str(sp, M_ERR, name,
  884.             "252|%s: write lock was unavailable");
  885.  
  886. #if __linux__
  887.     /*
  888.      * XXX
  889.      * In libc 4.5.x, fdopen(fd, "w") clears the O_APPEND flag (if set).
  890.      * This bug is fixed in libc 4.6.x.
  891.      *
  892.      * This code works around this problem for libc 4.5.x users.
  893.      * Note that this code is harmless if you're using libc 4.6.x.
  894.      */
  895.     if (LF_ISSET(FS_APPEND) && lseek(fd, (off_t)0, SEEK_END) < 0) {
  896.         msgq(sp, M_SYSERR, name);
  897.         return (1);
  898.     }
  899. #endif
  900.  
  901.     /*
  902.      * Use stdio for buffering.
  903.      *
  904.      * XXX
  905.      * SVR4.2 requires the fdopen mode exactly match the original open
  906.      * mode, i.e. you have to open with "a" if appending.
  907.      */
  908.     if ((fp = fdopen(fd, LF_ISSET(FS_APPEND) ? "a" : "w")) == NULL) {
  909.         msgq_str(sp, M_SYSERR, name, "%s");
  910.         (void)close(fd);
  911.         return (1);
  912.     }
  913.  
  914.     /* Build fake addresses, if necessary. */
  915.     if (fm == NULL) {
  916.         from.lno = 1;
  917.         from.cno = 0;
  918.         fm = &from;
  919.         if (db_last(sp, &to.lno))
  920.             return (1);
  921.         to.cno = 0;
  922.         tm = &to;
  923.     }
  924.  
  925.     rval = ex_writefp(sp, name, fp, fm, tm, &nlno, &nch, 0);
  926.  
  927.     /*
  928.      * Save the new last modification time -- even if the write fails
  929.      * we re-init the time.  That way the user can clean up the disk
  930.      * and rewrite without having to force it.
  931.      */
  932.     if (noname)
  933.         if (stat(name, &sb))
  934.             time(&ep->mtime);
  935.         else {
  936.             F_SET(ep, F_DEVSET);
  937.             ep->mdev = sb.st_dev;
  938.             ep->minode = sb.st_ino;
  939.  
  940.             ep->mtime = sb.st_mtime;
  941.         }
  942.  
  943.     /*
  944.      * If the write failed, complain loudly.  ex_writefp() has already
  945.      * complained about the actual error, reinforce it if data was lost.
  946.      */
  947.     if (rval) {
  948.         if (!LF_ISSET(FS_APPEND))
  949.             msgq_str(sp, M_ERR, name,
  950.                 "254|%s: WARNING: FILE TRUNCATED");
  951.         return (1);
  952.     }
  953.  
  954.     /*
  955.      * Once we've actually written the file, it doesn't matter that the
  956.      * file name was changed -- if it was, we've already whacked it.
  957.      */
  958.     F_CLR(frp, FR_NAMECHANGE);
  959.  
  960.     /*
  961.      * If wrote the entire file, and it wasn't by appending it to a file,
  962.      * clear the modified bit.  If the file was written to the original
  963.      * file name and the file is a temporary, set the "no exit" bit.  This
  964.      * permits the user to write the file and use it in the context of the
  965.      * filesystem, but still keeps them from discarding their changes by
  966.      * exiting.
  967.      */
  968.     if (LF_ISSET(FS_ALL) && !LF_ISSET(FS_APPEND)) {
  969.         F_CLR(ep, F_MODIFIED);
  970.         if (F_ISSET(frp, FR_TMPFILE))
  971.             if (noname)
  972.                 F_SET(frp, FR_TMPEXIT);
  973.             else
  974.                 F_CLR(frp, FR_TMPEXIT);
  975.     }
  976.  
  977.     p = msg_print(sp, name, &nf);
  978.     switch (mtype) {
  979.     case NEWFILE:
  980.         msgstr = msg_cat(sp,
  981.             "256|%s: new file: %lu lines, %lu characters", NULL);
  982.         len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch);
  983.         break;
  984.     case OLDFILE:
  985.         msgstr = msg_cat(sp, LF_ISSET(FS_APPEND) ?
  986.             "315|%s: appended: %lu lines, %lu characters" :
  987.             "257|%s: %lu lines, %lu characters", NULL);
  988.         len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch);
  989.         break;
  990.     default:
  991.         abort();
  992.     }
  993.  
  994.     /*
  995.      * There's a nasty problem with long path names.  Cscope and tags files
  996.      * can result in long paths and vi will request a continuation key from
  997.      * the user.  Unfortunately, the user has typed ahead, and chaos will
  998.      * result.  If we assume that the characters in the filenames only take
  999.      * a single screen column each, we can trim the filename.
  1000.      */
  1001.     s = buf;
  1002.     if (len >= sp->cols) {
  1003.         for (s = buf, t = buf + strlen(p); s < t &&
  1004.             (*s != '/' || len >= sp->cols - 3); ++s, --len);
  1005.         if (s == t)
  1006.             s = buf;
  1007.         else {
  1008.             *--s = '.';        /* Leading ellipses. */
  1009.             *--s = '.';
  1010.             *--s = '.';
  1011.         }
  1012.     }
  1013.     msgq(sp, M_INFO, s);
  1014.     if (nf)
  1015.         FREE_SPACE(sp, p, 0);
  1016.     return (0);
  1017. }
  1018.  
  1019. /*
  1020.  * file_backup --
  1021.  *    Backup the about-to-be-written file.
  1022.  *
  1023.  * XXX
  1024.  * We do the backup by copying the entire file.  It would be nice to do
  1025.  * a rename instead, but: (1) both files may not fit and we want to fail
  1026.  * before doing the rename; (2) the backup file may not be on the same
  1027.  * disk partition as the file being written; (3) there may be optional
  1028.  * file information (MACs, DACs, whatever) that we won't get right if we
  1029.  * recreate the file.  So, let's not risk it.
  1030.  */
  1031. static int
  1032. file_backup(sp, name, bname)
  1033.     SCR *sp;
  1034.     char *name, *bname;
  1035. {
  1036.     struct dirent *dp;
  1037.     struct stat sb;
  1038.     DIR *dirp;
  1039.     EXCMD cmd;
  1040.     off_t off;
  1041.     size_t blen;
  1042.     int flags, maxnum, nr, num, nw, rfd, wfd, version;
  1043.     char *bp, *estr, *p, *pct, *slash, *t, *wfname, buf[8192];
  1044.  
  1045.     rfd = wfd = -1;
  1046.     bp = estr = wfname = NULL;
  1047.  
  1048.     /*
  1049.      * Open the current file for reading.  Do this first, so that
  1050.      * we don't exec a shell before the most likely failure point.
  1051.      * If it doesn't exist, it's okay, there's just nothing to back
  1052.      * up.
  1053.      */
  1054.     errno = 0;
  1055.     if ((rfd = open(name, O_RDONLY, 0)) < 0) {
  1056.         if (errno == ENOENT)
  1057.             return (0);
  1058.         estr = name;
  1059.         goto err;
  1060.     }
  1061.  
  1062.     /*
  1063.      * If the name starts with an 'N' character, add a version number
  1064.      * to the name.  Strip the leading N from the string passed to the
  1065.      * expansion routines, for no particular reason.  It would be nice
  1066.      * to permit users to put the version number anywhere in the backup
  1067.      * name, but there isn't a special character that we can use in the
  1068.      * name, and giving a new character a special meaning leads to ugly
  1069.      * hacks both here and in the supporting ex routines.
  1070.      *
  1071.      * Shell and file name expand the option's value.
  1072.      */
  1073.     argv_init(sp, &cmd);
  1074.     ex_cinit(&cmd, 0, 0, 0, 0, 0, NULL);
  1075.     if (bname[0] == 'N') {
  1076.         version = 1;
  1077.         ++bname;
  1078.     } else
  1079.         version = 0;
  1080.     if (argv_exp2(sp, &cmd, bname, strlen(bname)))
  1081.         return (1);
  1082.  
  1083.     /*
  1084.      *  0 args: impossible.
  1085.      *  1 args: use it.
  1086.      * >1 args: object, too many args.
  1087.      */
  1088.     if (cmd.argc != 1) {
  1089.         msgq_str(sp, M_ERR, bname,
  1090.             "258|%s expanded into too many file names");
  1091.         (void)close(rfd);
  1092.         return (1);
  1093.     }
  1094.  
  1095.     /*
  1096.      * If appending a version number, read through the directory, looking
  1097.      * for file names that match the name followed by a number.  Make all
  1098.      * of the other % characters in name literal, so the user doesn't get
  1099.      * surprised and sscanf doesn't drop core indirecting through pointers
  1100.      * that don't exist.  If any such files are found, increment its number
  1101.      * by one.
  1102.      */
  1103.     if (version) {
  1104.         GET_SPACE_GOTO(sp, bp, blen, cmd.argv[0]->len * 2 + 50);
  1105.         for (t = bp, slash = NULL,
  1106.             p = cmd.argv[0]->bp; p[0] != '\0'; *t++ = *p++)
  1107.             if (p[0] == '%') {
  1108.                 if (p[1] != '%')
  1109.                     *t++ = '%';
  1110.             } else if (p[0] == '/')
  1111.                 slash = t;
  1112.         pct = t;
  1113.         *t++ = '%';
  1114.         *t++ = 'd';
  1115.         *t = '\0';
  1116.  
  1117.         if (slash == NULL) {
  1118.             dirp = opendir(".");
  1119.             p = bp;
  1120.         } else {
  1121.             *slash = '\0';
  1122.             dirp = opendir(bp);
  1123.             *slash = '/';
  1124.             p = slash + 1;
  1125.         }
  1126.         if (dirp == NULL) {
  1127.             estr = cmd.argv[0]->bp;
  1128.             goto err;
  1129.         }
  1130.  
  1131.         for (maxnum = 0; (dp = readdir(dirp)) != NULL;)
  1132.             if (sscanf(dp->d_name, p, &num) == 1 && num > maxnum)
  1133.                 maxnum = num;
  1134.         (void)closedir(dirp);
  1135.  
  1136.         /* Format the backup file name. */
  1137.         (void)snprintf(pct, blen - (pct - bp), "%d", maxnum + 1);
  1138.         wfname = bp;
  1139.     } else {
  1140.         bp = NULL;
  1141.         wfname = cmd.argv[0]->bp;
  1142.     }
  1143.     
  1144.     /* Open the backup file, avoiding lurkers. */
  1145.     if (stat(wfname, &sb) == 0) {
  1146.         if (!S_ISREG(sb.st_mode)) {
  1147.             msgq_str(sp, M_ERR, bname,
  1148.                 "259|%s: not a regular file");
  1149.             goto err;
  1150.         }
  1151.         if (sb.st_uid != getuid()) {
  1152.             msgq_str(sp, M_ERR, bname, "260|%s: not owned by you");
  1153.             goto err;
  1154.         }
  1155.         if (sb.st_mode & (S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) {
  1156.             msgq_str(sp, M_ERR, bname,
  1157.                "261|%s: accessible by a user other than the owner");
  1158.             goto err;
  1159.         }
  1160.         flags = O_TRUNC;
  1161.     } else
  1162.         flags = O_CREAT | O_EXCL;
  1163.     if ((wfd = open(wfname, flags | O_WRONLY, S_IRUSR | S_IWUSR)) < 0) {
  1164.         estr = bname;
  1165.         goto err;
  1166.     }
  1167.  
  1168.     /* Copy the file's current contents to its backup value. */
  1169.     while ((nr = read(rfd, buf, sizeof(buf))) > 0)
  1170.         for (off = 0; nr != 0; nr -= nw, off += nw)
  1171.             if ((nw = write(wfd, buf + off, nr)) < 0) {
  1172.                 estr = wfname;
  1173.                 goto err;
  1174.             }
  1175.     if (nr < 0) {
  1176.         estr = name;
  1177.         goto err;
  1178.     }
  1179.  
  1180.     if (close(rfd)) {
  1181.         estr = name;
  1182.         goto err;
  1183.     }
  1184.     if (close(wfd)) {
  1185.         estr = wfname;
  1186.         goto err;
  1187.     }
  1188.     if (bp != NULL)
  1189.         FREE_SPACE(sp, bp, blen);
  1190.     return (0);
  1191.  
  1192. alloc_err:
  1193. err:    if (rfd != -1)
  1194.         (void)close(rfd);
  1195.     if (wfd != -1) {
  1196.         (void)unlink(wfname);
  1197.         (void)close(wfd);
  1198.     }
  1199.     if (estr)
  1200.         msgq_str(sp, M_SYSERR, estr, "%s");
  1201.     if (bp != NULL)
  1202.         FREE_SPACE(sp, bp, blen);
  1203.     return (1);
  1204. }
  1205.  
  1206. /*
  1207.  * file_comment --
  1208.  *    Skip the first comment.
  1209.  */
  1210. static void
  1211. file_comment(sp)
  1212.     SCR *sp;
  1213. {
  1214.     recno_t lno;
  1215.     size_t len;
  1216.     char *p;
  1217.  
  1218.     for (lno = 1; !db_get(sp, lno, 0, &p, &len) && len == 0; ++lno);
  1219.     if (p == NULL)
  1220.         return;
  1221.     if (p[0] == '#') {
  1222.         F_SET(sp, SC_SCR_TOP);
  1223.         while (!db_get(sp, ++lno, 0, &p, &len))
  1224.             if (len < 1 || p[0] != '#') {
  1225.                 sp->lno = lno;
  1226.                 return;
  1227.             }
  1228.     } else if (len > 1 && p[0] == '/' && p[1] == '*') {
  1229.         F_SET(sp, SC_SCR_TOP);
  1230.         do {
  1231.             for (; len > 1; --len, ++p)
  1232.                 if (p[0] == '*' && p[1] == '/') {
  1233.                     sp->lno = lno;
  1234.                     return;
  1235.                 }
  1236.         } while (!db_get(sp, ++lno, 0, &p, &len));
  1237.     } else if (len > 1 && p[0] == '/' && p[1] == '/') {
  1238.         F_SET(sp, SC_SCR_TOP);
  1239.         p += 2;
  1240.         len -= 2;
  1241.         do {
  1242.             for (; len > 1; --len, ++p)
  1243.                 if (p[0] == '/' && p[1] == '/') {
  1244.                     sp->lno = lno;
  1245.                     return;
  1246.                 }
  1247.         } while (!db_get(sp, ++lno, 0, &p, &len));
  1248.     }
  1249. }
  1250.  
  1251. /*
  1252.  * file_m1 --
  1253.  *     First modification check routine.  The :next, :prev, :rewind, :tag,
  1254.  *    :tagpush, :tagpop, ^^ modifications check.
  1255.  *
  1256.  * PUBLIC: int file_m1 __P((SCR *, int, int));
  1257.  */
  1258. int
  1259. file_m1(sp, force, flags)
  1260.     SCR *sp;
  1261.     int force, flags;
  1262. {
  1263.     EXF *ep;
  1264.  
  1265.     ep = sp->ep;
  1266.  
  1267.     /* If no file loaded, return no modifications. */
  1268.     if (ep == NULL)
  1269.         return (0);
  1270.  
  1271.     /*
  1272.      * If the file has been modified, we'll want to write it back or
  1273.      * fail.  If autowrite is set, we'll write it back automatically,
  1274.      * unless force is also set.  Otherwise, we fail unless forced or
  1275.      * there's another open screen on this file.
  1276.      */
  1277.     if (F_ISSET(ep, F_MODIFIED))
  1278.         if (O_ISSET(sp, O_AUTOWRITE)) {
  1279.             if (!force && file_aw(sp, flags))
  1280.                 return (1);
  1281.         } else if (ep->refcnt <= 1 && !force) {
  1282.             msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ?
  1283. "262|File modified since last complete write; write or use ! to override" :
  1284. "263|File modified since last complete write; write or use :edit! to override");
  1285.             return (1);
  1286.         }
  1287.  
  1288.     return (file_m3(sp, force));
  1289. }
  1290.  
  1291. /*
  1292.  * file_m2 --
  1293.  *     Second modification check routine.  The :edit, :quit, :recover
  1294.  *    modifications check.
  1295.  *
  1296.  * PUBLIC: int file_m2 __P((SCR *, int));
  1297.  */
  1298. int
  1299. file_m2(sp, force)
  1300.     SCR *sp;
  1301.     int force;
  1302. {
  1303.     EXF *ep;
  1304.  
  1305.     ep = sp->ep;
  1306.  
  1307.     /* If no file loaded, return no modifications. */
  1308.     if (ep == NULL)
  1309.         return (0);
  1310.  
  1311.     /*
  1312.      * If the file has been modified, we'll want to fail, unless forced
  1313.      * or there's another open screen on this file.
  1314.      */
  1315.     if (F_ISSET(ep, F_MODIFIED) && ep->refcnt <= 1 && !force) {
  1316.         msgq(sp, M_ERR,
  1317. "264|File modified since last complete write; write or use ! to override");
  1318.         return (1);
  1319.     }
  1320.  
  1321.     return (file_m3(sp, force));
  1322. }
  1323.  
  1324. /*
  1325.  * file_m3 --
  1326.  *     Third modification check routine.
  1327.  *
  1328.  * PUBLIC: int file_m3 __P((SCR *, int));
  1329.  */
  1330. int
  1331. file_m3(sp, force)
  1332.     SCR *sp;
  1333.     int force;
  1334. {
  1335.     EXF *ep;
  1336.  
  1337.     ep = sp->ep;
  1338.  
  1339.     /* If no file loaded, return no modifications. */
  1340.     if (ep == NULL)
  1341.         return (0);
  1342.  
  1343.     /*
  1344.      * Don't exit while in a temporary files if the file was ever modified.
  1345.      * The problem is that if the user does a ":wq", we write and quit,
  1346.      * unlinking the temporary file.  Not what the user had in mind at all.
  1347.      * We permit writing to temporary files, so that user maps using file
  1348.      * system names work with temporary files.
  1349.      */
  1350.     if (F_ISSET(sp->frp, FR_TMPEXIT) && ep->refcnt <= 1 && !force) {
  1351.         msgq(sp, M_ERR,
  1352.             "265|File is a temporary; exit will discard modifications");
  1353.         return (1);
  1354.     }
  1355.     return (0);
  1356. }
  1357.  
  1358. /*
  1359.  * file_aw --
  1360.  *    Autowrite routine.  If modified, autowrite is set and the readonly bit
  1361.  *    is not set, write the file.  A routine so there's a place to put the
  1362.  *    comment.
  1363.  *
  1364.  * PUBLIC: int file_aw __P((SCR *, int));
  1365.  */
  1366. int
  1367. file_aw(sp, flags)
  1368.     SCR *sp;
  1369.     int flags;
  1370. {
  1371.     if (!F_ISSET(sp->ep, F_MODIFIED))
  1372.         return (0);
  1373.     if (!O_ISSET(sp, O_AUTOWRITE))
  1374.         return (0);
  1375.  
  1376.     /*
  1377.      * !!!
  1378.      * Historic 4BSD vi attempted to write the file if autowrite was set,
  1379.      * regardless of the writeability of the file (as defined by the file
  1380.      * readonly flag).  System V changed this as some point, not attempting
  1381.      * autowrite if the file was readonly.  This feels like a bug fix to
  1382.      * me (e.g. the principle of least surprise is violated if readonly is
  1383.      * set and vi writes the file), so I'm compatible with System V.
  1384.      */
  1385.     if (O_ISSET(sp, O_READONLY)) {
  1386.         msgq(sp, M_INFO,
  1387.             "266|File readonly, modifications not auto-written");
  1388.         return (1);
  1389.     }
  1390.     return (file_write(sp, NULL, NULL, NULL, flags));
  1391. }
  1392.  
  1393. /*
  1394.  * set_alt_name --
  1395.  *    Set the alternate pathname.
  1396.  *
  1397.  * Set the alternate pathname.  It's a routine because I wanted some place
  1398.  * to hang this comment.  The alternate pathname (normally referenced using
  1399.  * the special character '#' during file expansion and in the vi ^^ command)
  1400.  * is set by almost all ex commands that take file names as arguments.  The
  1401.  * rules go something like this:
  1402.  *
  1403.  *    1: If any ex command takes a file name as an argument (except for the
  1404.  *     :next command), the alternate pathname is set to that file name.
  1405.  *     This excludes the command ":e" and ":w !command" as no file name
  1406.  *       was specified.  Note, historically, the :source command did not set
  1407.  *     the alternate pathname.  It does in nvi, for consistency.
  1408.  *
  1409.  *    2: However, if any ex command sets the current pathname, e.g. the
  1410.  *     ":e file" or ":rew" commands succeed, then the alternate pathname
  1411.  *     is set to the previous file's current pathname, if it had one.
  1412.  *     This includes the ":file" command and excludes the ":e" command.
  1413.  *     So, by rule #1 and rule #2, if ":edit foo" fails, the alternate
  1414.  *     pathname will be "foo", if it succeeds, the alternate pathname will
  1415.  *     be the previous current pathname.  The ":e" command will not set
  1416.  *       the alternate or current pathnames regardless.
  1417.  *
  1418.  *    3: However, if it's a read or write command with a file argument and
  1419.  *     the current pathname has not yet been set, the file name becomes
  1420.  *     the current pathname, and the alternate pathname is unchanged.
  1421.  *
  1422.  * If the user edits a temporary file, there may be times when there is no
  1423.  * alternative file name.  A name argument of NULL turns it off.
  1424.  *
  1425.  * PUBLIC: void set_alt_name __P((SCR *, char *));
  1426.  */
  1427. void
  1428. set_alt_name(sp, name)
  1429.     SCR *sp;
  1430.     char *name;
  1431. {
  1432.     if (sp->alt_name != NULL)
  1433.         free(sp->alt_name);
  1434.     if (name == NULL)
  1435.         sp->alt_name = NULL;
  1436.     else if ((sp->alt_name = strdup(name)) == NULL)
  1437.         msgq(sp, M_SYSERR, NULL);
  1438. }
  1439.  
  1440. /*
  1441.  * file_lock --
  1442.  *    Get an exclusive lock on a file.
  1443.  *
  1444.  * XXX
  1445.  * The default locking is flock(2) style, not fcntl(2).  The latter is
  1446.  * known to fail badly on some systems, and its only advantage is that
  1447.  * it occasionally works over NFS.
  1448.  *
  1449.  * Furthermore, the semantics of fcntl(2) are wrong.  The problems are
  1450.  * two-fold: you can't close any file descriptor associated with the file
  1451.  * without losing all of the locks, and you can't get an exclusive lock
  1452.  * unless you have the file open for writing.  Someone ought to be shot,
  1453.  * but it's probably too late, they may already have reproduced.  To get
  1454.  * around these problems, nvi opens the files for writing when it can and
  1455.  * acquires a second file descriptor when it can't.  The recovery files
  1456.  * are examples of the former, they're always opened for writing.  The DB
  1457.  * files can't be opened for writing because the semantics of DB are that
  1458.  * files opened for writing are flushed back to disk when the DB session
  1459.  * is ended. So, in that case we have to acquire an extra file descriptor.
  1460.  *
  1461.  * PUBLIC: lockr_t file_lock __P((SCR *, char *, int *, int, int));
  1462.  */
  1463. lockr_t
  1464. file_lock(sp, name, fdp, fd, iswrite)
  1465.     SCR *sp;
  1466.     char *name;
  1467.     int *fdp, fd, iswrite;
  1468. {
  1469.     if (!O_ISSET(sp, O_LOCKFILES))
  1470.         return (LOCK_SUCCESS);
  1471.     
  1472. #ifdef HAVE_LOCK_FLOCK            /* Hurrah!  We've got flock(2). */
  1473.     /*
  1474.      * !!!
  1475.      * We need to distinguish a lock not being available for the file
  1476.      * from the file system not supporting locking.  Flock is documented
  1477.      * as returning EWOULDBLOCK; add EAGAIN for good measure, and assume
  1478.      * they are the former.  There's no portable way to do this.
  1479.      */
  1480.     errno = 0;
  1481.     return (flock(fd, LOCK_EX | LOCK_NB) ? errno == EAGAIN
  1482. #ifdef EWOULDBLOCK
  1483.         || errno == EWOULDBLOCK
  1484. #endif
  1485.         ? LOCK_UNAVAIL : LOCK_FAILED : LOCK_SUCCESS);
  1486. #endif
  1487. #ifdef HAVE_LOCK_FCNTL            /* Gag me.  We've got fcntl(2). */
  1488. {
  1489.     struct flock arg;
  1490.     int didopen, sverrno;
  1491.  
  1492.     arg.l_type = F_WRLCK;
  1493.     arg.l_whence = 0;        /* SEEK_SET */
  1494.     arg.l_start = arg.l_len = 0;
  1495.     arg.l_pid = 0;
  1496.  
  1497.     /*
  1498.      * If the file descriptor isn't opened for writing, it must fail.
  1499.      * If we fail because we can't get a read/write file descriptor,
  1500.      * we return LOCK_SUCCESS, believing that the file is readonly
  1501.      * and that will be sufficient to warn the user.
  1502.      */
  1503.     if (!iswrite) {
  1504.         if (name == NULL || fdp == NULL)
  1505.             return (LOCK_FAILED);
  1506.         if ((fd = open(name, O_RDWR, 0)) == -1)
  1507.             return (LOCK_SUCCESS);
  1508.         *fdp = fd;
  1509.         didopen = 1;
  1510.     }
  1511.  
  1512.     errno = 0;
  1513.     if (!fcntl(fd, F_SETLK, &arg))
  1514.         return (LOCK_SUCCESS);
  1515.     if (didopen) {
  1516.         sverrno = errno;
  1517.         (void)close(fd);
  1518.         errno = sverrno;
  1519.     }
  1520.  
  1521.     /*
  1522.      * !!!
  1523.      * We need to distinguish a lock not being available for the file
  1524.      * from the file system not supporting locking.  Fcntl is documented
  1525.      * as returning EACCESS and EAGAIN; add EWOULDBLOCK for good measure,
  1526.      * and assume they are the former.  There's no portable way to do this.
  1527.      */
  1528.     return (errno == EACCES || errno == EAGAIN
  1529. #ifdef EWOULDBLOCK
  1530.     || errno == EWOULDBLOCK
  1531. #endif
  1532.     ?  LOCK_UNAVAIL : LOCK_FAILED);
  1533. }
  1534. #endif
  1535. #if !defined(HAVE_LOCK_FLOCK) && !defined(HAVE_LOCK_FCNTL)
  1536.     return (LOCK_SUCCESS);
  1537. #endif
  1538. }
  1539.