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