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