(install-arch-indep): If cd etc makes output,
[bpt/emacs.git] / src / fileio.c
... / ...
CommitLineData
1/* File IO for GNU Emacs.
2 Copyright (C) 1985,86,87,88,93,94,95,96 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include <config.h>
22
23#include <sys/types.h>
24#include <sys/stat.h>
25
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#endif
29
30#if !defined (S_ISLNK) && defined (S_IFLNK)
31# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
32#endif
33
34#if !defined (S_ISREG) && defined (S_IFREG)
35# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
36#endif
37
38#ifdef VMS
39#include "vms-pwd.h"
40#else
41#include <pwd.h>
42#endif
43
44#ifdef MSDOS
45#include "msdos.h"
46#include <sys/param.h>
47#if __DJGPP__ >= 2
48#include <fcntl.h>
49#include <string.h>
50#endif
51#endif
52
53#include <ctype.h>
54
55#ifdef VMS
56#include "vmsdir.h"
57#include <perror.h>
58#include <stddef.h>
59#include <string.h>
60#endif
61
62#include <errno.h>
63
64#ifndef vax11c
65extern int errno;
66#endif
67
68extern char *strerror ();
69
70#ifdef APOLLO
71#include <sys/time.h>
72#endif
73
74#ifndef USG
75#ifndef VMS
76#ifndef BSD4_1
77#ifndef WINDOWSNT
78#define HAVE_FSYNC
79#endif
80#endif
81#endif
82#endif
83
84#include "lisp.h"
85#include "intervals.h"
86#include "buffer.h"
87#include "window.h"
88
89#ifdef WINDOWSNT
90#define NOMINMAX 1
91#include <windows.h>
92#include <stdlib.h>
93#include <fcntl.h>
94#endif /* not WINDOWSNT */
95
96#ifdef DOS_NT
97#define CORRECT_DIR_SEPS(s) \
98 do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \
99 else unixtodos_filename (s); \
100 } while (0)
101/* On Windows, drive letters must be alphabetic - on DOS, the Netware
102 redirector allows the six letters between 'Z' and 'a' as well. */
103#ifdef MSDOS
104#define IS_DRIVE(x) ((x) >= 'A' && (x) <= 'z')
105#endif
106#ifdef WINDOWSNT
107#define IS_DRIVE(x) isalpha (x)
108#endif
109#endif
110
111#ifdef VMS
112#include <file.h>
113#include <rmsdef.h>
114#include <fab.h>
115#include <nam.h>
116#endif
117
118#include "systime.h"
119
120#ifdef HPUX
121#include <netio.h>
122#ifndef HPUX8
123#ifndef HPUX9
124#include <errnet.h>
125#endif
126#endif
127#endif
128
129#ifndef O_WRONLY
130#define O_WRONLY 1
131#endif
132
133#ifndef O_RDONLY
134#define O_RDONLY 0
135#endif
136
137#define min(a, b) ((a) < (b) ? (a) : (b))
138#define max(a, b) ((a) > (b) ? (a) : (b))
139
140/* Nonzero during writing of auto-save files */
141int auto_saving;
142
143/* Set by auto_save_1 to mode of original file so Fwrite_region will create
144 a new file with the same mode as the original */
145int auto_save_mode_bits;
146
147/* Alist of elements (REGEXP . HANDLER) for file names
148 whose I/O is done with a special handler. */
149Lisp_Object Vfile_name_handler_alist;
150
151/* Format for auto-save files */
152Lisp_Object Vauto_save_file_format;
153
154/* Lisp functions for translating file formats */
155Lisp_Object Qformat_decode, Qformat_annotate_function;
156
157/* Functions to be called to process text properties in inserted file. */
158Lisp_Object Vafter_insert_file_functions;
159
160/* Functions to be called to create text property annotations for file. */
161Lisp_Object Vwrite_region_annotate_functions;
162
163/* During build_annotations, each time an annotation function is called,
164 this holds the annotations made by the previous functions. */
165Lisp_Object Vwrite_region_annotations_so_far;
166
167/* File name in which we write a list of all our auto save files. */
168Lisp_Object Vauto_save_list_file_name;
169
170/* Nonzero means, when reading a filename in the minibuffer,
171 start out by inserting the default directory into the minibuffer. */
172int insert_default_directory;
173
174/* On VMS, nonzero means write new files with record format stmlf.
175 Zero means use var format. */
176int vms_stmlf_recfm;
177
178/* On NT, specifies the directory separator character, used (eg.) when
179 expanding file names. This can be bound to / or \. */
180Lisp_Object Vdirectory_sep_char;
181
182/* These variables describe handlers that have "already" had a chance
183 to handle the current operation.
184
185 Vinhibit_file_name_handlers is a list of file name handlers.
186 Vinhibit_file_name_operation is the operation being handled.
187 If we try to handle that operation, we ignore those handlers. */
188
189static Lisp_Object Vinhibit_file_name_handlers;
190static Lisp_Object Vinhibit_file_name_operation;
191
192Lisp_Object Qfile_error, Qfile_already_exists;
193
194Lisp_Object Qfile_name_history;
195
196Lisp_Object Qcar_less_than_car;
197
198report_file_error (string, data)
199 char *string;
200 Lisp_Object data;
201{
202 Lisp_Object errstring;
203
204 errstring = build_string (strerror (errno));
205
206 /* System error messages are capitalized. Downcase the initial
207 unless it is followed by a slash. */
208 if (XSTRING (errstring)->data[1] != '/')
209 XSTRING (errstring)->data[0] = DOWNCASE (XSTRING (errstring)->data[0]);
210
211 while (1)
212 Fsignal (Qfile_error,
213 Fcons (build_string (string), Fcons (errstring, data)));
214}
215
216close_file_unwind (fd)
217 Lisp_Object fd;
218{
219 close (XFASTINT (fd));
220}
221
222/* Restore point, having saved it as a marker. */
223
224restore_point_unwind (location)
225 Lisp_Object location;
226{
227 SET_PT (marker_position (location));
228 Fset_marker (location, Qnil, Qnil);
229}
230\f
231Lisp_Object Qexpand_file_name;
232Lisp_Object Qsubstitute_in_file_name;
233Lisp_Object Qdirectory_file_name;
234Lisp_Object Qfile_name_directory;
235Lisp_Object Qfile_name_nondirectory;
236Lisp_Object Qunhandled_file_name_directory;
237Lisp_Object Qfile_name_as_directory;
238Lisp_Object Qcopy_file;
239Lisp_Object Qmake_directory_internal;
240Lisp_Object Qdelete_directory;
241Lisp_Object Qdelete_file;
242Lisp_Object Qrename_file;
243Lisp_Object Qadd_name_to_file;
244Lisp_Object Qmake_symbolic_link;
245Lisp_Object Qfile_exists_p;
246Lisp_Object Qfile_executable_p;
247Lisp_Object Qfile_readable_p;
248Lisp_Object Qfile_symlink_p;
249Lisp_Object Qfile_writable_p;
250Lisp_Object Qfile_directory_p;
251Lisp_Object Qfile_regular_p;
252Lisp_Object Qfile_accessible_directory_p;
253Lisp_Object Qfile_modes;
254Lisp_Object Qset_file_modes;
255Lisp_Object Qfile_newer_than_file_p;
256Lisp_Object Qinsert_file_contents;
257Lisp_Object Qwrite_region;
258Lisp_Object Qverify_visited_file_modtime;
259Lisp_Object Qset_visited_file_modtime;
260
261DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 2, 2, 0,
262 "Return FILENAME's handler function for OPERATION, if it has one.\n\
263Otherwise, return nil.\n\
264A file name is handled if one of the regular expressions in\n\
265`file-name-handler-alist' matches it.\n\n\
266If OPERATION equals `inhibit-file-name-operation', then we ignore\n\
267any handlers that are members of `inhibit-file-name-handlers',\n\
268but we still do run any other handlers. This lets handlers\n\
269use the standard functions without calling themselves recursively.")
270 (filename, operation)
271 Lisp_Object filename, operation;
272{
273 /* This function must not munge the match data. */
274 Lisp_Object chain, inhibited_handlers;
275
276 CHECK_STRING (filename, 0);
277
278 if (EQ (operation, Vinhibit_file_name_operation))
279 inhibited_handlers = Vinhibit_file_name_handlers;
280 else
281 inhibited_handlers = Qnil;
282
283 for (chain = Vfile_name_handler_alist; CONSP (chain);
284 chain = XCONS (chain)->cdr)
285 {
286 Lisp_Object elt;
287 elt = XCONS (chain)->car;
288 if (CONSP (elt))
289 {
290 Lisp_Object string;
291 string = XCONS (elt)->car;
292 if (STRINGP (string) && fast_string_match (string, filename) >= 0)
293 {
294 Lisp_Object handler, tem;
295
296 handler = XCONS (elt)->cdr;
297 tem = Fmemq (handler, inhibited_handlers);
298 if (NILP (tem))
299 return handler;
300 }
301 }
302
303 QUIT;
304 }
305 return Qnil;
306}
307\f
308DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory,
309 1, 1, 0,
310 "Return the directory component in file name FILENAME.\n\
311Return nil if FILENAME does not include a directory.\n\
312Otherwise return a directory spec.\n\
313Given a Unix syntax file name, returns a string ending in slash;\n\
314on VMS, perhaps instead a string ending in `:', `]' or `>'.")
315 (filename)
316 Lisp_Object filename;
317{
318 register unsigned char *beg;
319 register unsigned char *p;
320 Lisp_Object handler;
321
322 CHECK_STRING (filename, 0);
323
324 /* If the file name has special constructs in it,
325 call the corresponding file handler. */
326 handler = Ffind_file_name_handler (filename, Qfile_name_directory);
327 if (!NILP (handler))
328 return call2 (handler, Qfile_name_directory, filename);
329
330#ifdef FILE_SYSTEM_CASE
331 filename = FILE_SYSTEM_CASE (filename);
332#endif
333 beg = XSTRING (filename)->data;
334#ifdef DOS_NT
335 beg = strcpy (alloca (strlen (beg) + 1), beg);
336#endif
337 p = beg + XSTRING (filename)->size;
338
339 while (p != beg && !IS_DIRECTORY_SEP (p[-1])
340#ifdef VMS
341 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
342#endif /* VMS */
343#ifdef DOS_NT
344 /* only recognise drive specifier at beginning */
345 && !(p[-1] == ':' && p == beg + 2)
346#endif
347 ) p--;
348
349 if (p == beg)
350 return Qnil;
351#ifdef WINDOWSNT
352 /* We can consider the partial UNC name //machine to be a
353 directory name, but not just // on its own. */
354 if (p == beg + 1 && IS_DIRECTORY_SEP (p[-1]))
355 return Qnil;
356#endif
357#ifdef DOS_NT
358 /* Expansion of "c:" to drive and default directory. */
359 if (p == beg + 2 && beg[1] == ':')
360 {
361 /* MAXPATHLEN+1 is guaranteed to be enough space for getdefdir. */
362 unsigned char *res = alloca (MAXPATHLEN + 1);
363 if (getdefdir (toupper (*beg) - 'A' + 1, res))
364 {
365 if (!IS_DIRECTORY_SEP (res[strlen (res) - 1]))
366 strcat (res, "/");
367 beg = res;
368 p = beg + strlen (beg);
369 }
370 }
371 CORRECT_DIR_SEPS (beg);
372#endif /* DOS_NT */
373 return make_string (beg, p - beg);
374}
375
376DEFUN ("file-name-nondirectory", Ffile_name_nondirectory, Sfile_name_nondirectory,
377 1, 1, 0,
378 "Return file name FILENAME sans its directory.\n\
379For example, in a Unix-syntax file name,\n\
380this is everything after the last slash,\n\
381or the entire name if it contains no slash.")
382 (filename)
383 Lisp_Object filename;
384{
385 register unsigned char *beg, *p, *end;
386 Lisp_Object handler;
387
388 CHECK_STRING (filename, 0);
389
390 /* If the file name has special constructs in it,
391 call the corresponding file handler. */
392 handler = Ffind_file_name_handler (filename, Qfile_name_nondirectory);
393 if (!NILP (handler))
394 return call2 (handler, Qfile_name_nondirectory, filename);
395
396 beg = XSTRING (filename)->data;
397 end = p = beg + XSTRING (filename)->size;
398
399 while (p != beg && !IS_DIRECTORY_SEP (p[-1])
400#ifdef VMS
401 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
402#endif /* VMS */
403#ifdef DOS_NT
404 /* only recognise drive specifier at beginning */
405 && !(p[-1] == ':' && p == beg + 2)
406#endif
407 ) p--;
408
409 return make_string (p, end - p);
410}
411
412DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory, Sunhandled_file_name_directory, 1, 1, 0,
413 "Return a directly usable directory name somehow associated with FILENAME.\n\
414A `directly usable' directory name is one that may be used without the\n\
415intervention of any file handler.\n\
416If FILENAME is a directly usable file itself, return\n\
417(file-name-directory FILENAME).\n\
418The `call-process' and `start-process' functions use this function to\n\
419get a current directory to run processes in.")
420 (filename)
421 Lisp_Object filename;
422{
423 Lisp_Object handler;
424
425 /* If the file name has special constructs in it,
426 call the corresponding file handler. */
427 handler = Ffind_file_name_handler (filename, Qunhandled_file_name_directory);
428 if (!NILP (handler))
429 return call2 (handler, Qunhandled_file_name_directory, filename);
430
431 return Ffile_name_directory (filename);
432}
433
434\f
435char *
436file_name_as_directory (out, in)
437 char *out, *in;
438{
439 int size = strlen (in) - 1;
440
441 strcpy (out, in);
442
443#ifdef VMS
444 /* Is it already a directory string? */
445 if (in[size] == ':' || in[size] == ']' || in[size] == '>')
446 return out;
447 /* Is it a VMS directory file name? If so, hack VMS syntax. */
448 else if (! index (in, '/')
449 && ((size > 3 && ! strcmp (&in[size - 3], ".DIR"))
450 || (size > 3 && ! strcmp (&in[size - 3], ".dir"))
451 || (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4)
452 || ! strncmp (&in[size - 5], ".dir", 4))
453 && (in[size - 1] == '.' || in[size - 1] == ';')
454 && in[size] == '1')))
455 {
456 register char *p, *dot;
457 char brack;
458
459 /* x.dir -> [.x]
460 dir:x.dir --> dir:[x]
461 dir:[x]y.dir --> dir:[x.y] */
462 p = in + size;
463 while (p != in && *p != ':' && *p != '>' && *p != ']') p--;
464 if (p != in)
465 {
466 strncpy (out, in, p - in);
467 out[p - in] = '\0';
468 if (*p == ':')
469 {
470 brack = ']';
471 strcat (out, ":[");
472 }
473 else
474 {
475 brack = *p;
476 strcat (out, ".");
477 }
478 p++;
479 }
480 else
481 {
482 brack = ']';
483 strcpy (out, "[.");
484 }
485 dot = index (p, '.');
486 if (dot)
487 {
488 /* blindly remove any extension */
489 size = strlen (out) + (dot - p);
490 strncat (out, p, dot - p);
491 }
492 else
493 {
494 strcat (out, p);
495 size = strlen (out);
496 }
497 out[size++] = brack;
498 out[size] = '\0';
499 }
500#else /* not VMS */
501 /* For Unix syntax, Append a slash if necessary */
502 if (!IS_DIRECTORY_SEP (out[size]))
503 {
504 out[size + 1] = DIRECTORY_SEP;
505 out[size + 2] = '\0';
506 }
507#ifdef DOS_NT
508 CORRECT_DIR_SEPS (out);
509#endif
510#endif /* not VMS */
511 return out;
512}
513
514DEFUN ("file-name-as-directory", Ffile_name_as_directory,
515 Sfile_name_as_directory, 1, 1, 0,
516 "Return a string representing file FILENAME interpreted as a directory.\n\
517This operation exists because a directory is also a file, but its name as\n\
518a directory is different from its name as a file.\n\
519The result can be used as the value of `default-directory'\n\
520or passed as second argument to `expand-file-name'.\n\
521For a Unix-syntax file name, just appends a slash.\n\
522On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
523 (file)
524 Lisp_Object file;
525{
526 char *buf;
527 Lisp_Object handler;
528
529 CHECK_STRING (file, 0);
530 if (NILP (file))
531 return Qnil;
532
533 /* If the file name has special constructs in it,
534 call the corresponding file handler. */
535 handler = Ffind_file_name_handler (file, Qfile_name_as_directory);
536 if (!NILP (handler))
537 return call2 (handler, Qfile_name_as_directory, file);
538
539 buf = (char *) alloca (XSTRING (file)->size + 10);
540 return build_string (file_name_as_directory (buf, XSTRING (file)->data));
541}
542\f
543/*
544 * Convert from directory name to filename.
545 * On VMS:
546 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
547 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
548 * On UNIX, it's simple: just make sure there isn't a terminating /
549
550 * Value is nonzero if the string output is different from the input.
551 */
552
553directory_file_name (src, dst)
554 char *src, *dst;
555{
556 long slen;
557#ifdef VMS
558 long rlen;
559 char * ptr, * rptr;
560 char bracket;
561 struct FAB fab = cc$rms_fab;
562 struct NAM nam = cc$rms_nam;
563 char esa[NAM$C_MAXRSS];
564#endif /* VMS */
565
566 slen = strlen (src);
567#ifdef VMS
568 if (! index (src, '/')
569 && (src[slen - 1] == ']'
570 || src[slen - 1] == ':'
571 || src[slen - 1] == '>'))
572 {
573 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
574 fab.fab$l_fna = src;
575 fab.fab$b_fns = slen;
576 fab.fab$l_nam = &nam;
577 fab.fab$l_fop = FAB$M_NAM;
578
579 nam.nam$l_esa = esa;
580 nam.nam$b_ess = sizeof esa;
581 nam.nam$b_nop |= NAM$M_SYNCHK;
582
583 /* We call SYS$PARSE to handle such things as [--] for us. */
584 if (SYS$PARSE (&fab, 0, 0) == RMS$_NORMAL)
585 {
586 slen = nam.nam$b_esl;
587 if (esa[slen - 1] == ';' && esa[slen - 2] == '.')
588 slen -= 2;
589 esa[slen] = '\0';
590 src = esa;
591 }
592 if (src[slen - 1] != ']' && src[slen - 1] != '>')
593 {
594 /* what about when we have logical_name:???? */
595 if (src[slen - 1] == ':')
596 { /* Xlate logical name and see what we get */
597 ptr = strcpy (dst, src); /* upper case for getenv */
598 while (*ptr)
599 {
600 if ('a' <= *ptr && *ptr <= 'z')
601 *ptr -= 040;
602 ptr++;
603 }
604 dst[slen - 1] = 0; /* remove colon */
605 if (!(src = egetenv (dst)))
606 return 0;
607 /* should we jump to the beginning of this procedure?
608 Good points: allows us to use logical names that xlate
609 to Unix names,
610 Bad points: can be a problem if we just translated to a device
611 name...
612 For now, I'll punt and always expect VMS names, and hope for
613 the best! */
614 slen = strlen (src);
615 if (src[slen - 1] != ']' && src[slen - 1] != '>')
616 { /* no recursion here! */
617 strcpy (dst, src);
618 return 0;
619 }
620 }
621 else
622 { /* not a directory spec */
623 strcpy (dst, src);
624 return 0;
625 }
626 }
627 bracket = src[slen - 1];
628
629 /* If bracket is ']' or '>', bracket - 2 is the corresponding
630 opening bracket. */
631 ptr = index (src, bracket - 2);
632 if (ptr == 0)
633 { /* no opening bracket */
634 strcpy (dst, src);
635 return 0;
636 }
637 if (!(rptr = rindex (src, '.')))
638 rptr = ptr;
639 slen = rptr - src;
640 strncpy (dst, src, slen);
641 dst[slen] = '\0';
642 if (*rptr == '.')
643 {
644 dst[slen++] = bracket;
645 dst[slen] = '\0';
646 }
647 else
648 {
649 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
650 then translate the device and recurse. */
651 if (dst[slen - 1] == ':'
652 && dst[slen - 2] != ':' /* skip decnet nodes */
653 && strcmp (src + slen, "[000000]") == 0)
654 {
655 dst[slen - 1] = '\0';
656 if ((ptr = egetenv (dst))
657 && (rlen = strlen (ptr) - 1) > 0
658 && (ptr[rlen] == ']' || ptr[rlen] == '>')
659 && ptr[rlen - 1] == '.')
660 {
661 char * buf = (char *) alloca (strlen (ptr) + 1);
662 strcpy (buf, ptr);
663 buf[rlen - 1] = ']';
664 buf[rlen] = '\0';
665 return directory_file_name (buf, dst);
666 }
667 else
668 dst[slen - 1] = ':';
669 }
670 strcat (dst, "[000000]");
671 slen += 8;
672 }
673 rptr++;
674 rlen = strlen (rptr) - 1;
675 strncat (dst, rptr, rlen);
676 dst[slen + rlen] = '\0';
677 strcat (dst, ".DIR.1");
678 return 1;
679 }
680#endif /* VMS */
681 /* Process as Unix format: just remove any final slash.
682 But leave "/" unchanged; do not change it to "". */
683 strcpy (dst, src);
684#ifdef APOLLO
685 /* Handle // as root for apollo's. */
686 if ((slen > 2 && dst[slen - 1] == '/')
687 || (slen > 1 && dst[0] != '/' && dst[slen - 1] == '/'))
688 dst[slen - 1] = 0;
689#else
690 if (slen > 1
691 && IS_DIRECTORY_SEP (dst[slen - 1])
692#ifdef DOS_NT
693 && !IS_ANY_SEP (dst[slen - 2])
694#endif
695 )
696 dst[slen - 1] = 0;
697#endif
698#ifdef DOS_NT
699 CORRECT_DIR_SEPS (dst);
700#endif
701 return 1;
702}
703
704DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name,
705 1, 1, 0,
706 "Returns the file name of the directory named DIRECTORY.\n\
707This is the name of the file that holds the data for the directory DIRECTORY.\n\
708This operation exists because a directory is also a file, but its name as\n\
709a directory is different from its name as a file.\n\
710In Unix-syntax, this function just removes the final slash.\n\
711On VMS, given a VMS-syntax directory name such as \"[X.Y]\",\n\
712it returns a file name such as \"[X]Y.DIR.1\".")
713 (directory)
714 Lisp_Object directory;
715{
716 char *buf;
717 Lisp_Object handler;
718
719 CHECK_STRING (directory, 0);
720
721 if (NILP (directory))
722 return Qnil;
723
724 /* If the file name has special constructs in it,
725 call the corresponding file handler. */
726 handler = Ffind_file_name_handler (directory, Qdirectory_file_name);
727 if (!NILP (handler))
728 return call2 (handler, Qdirectory_file_name, directory);
729
730#ifdef VMS
731 /* 20 extra chars is insufficient for VMS, since we might perform a
732 logical name translation. an equivalence string can be up to 255
733 chars long, so grab that much extra space... - sss */
734 buf = (char *) alloca (XSTRING (directory)->size + 20 + 255);
735#else
736 buf = (char *) alloca (XSTRING (directory)->size + 20);
737#endif
738 directory_file_name (XSTRING (directory)->data, buf);
739 return build_string (buf);
740}
741
742DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0,
743 "Generate temporary file name (string) starting with PREFIX (a string).\n\
744The Emacs process number forms part of the result,\n\
745so there is no danger of generating a name being used by another process.")
746 (prefix)
747 Lisp_Object prefix;
748{
749 Lisp_Object val;
750#ifdef MSDOS
751 /* Don't use too many characters of the restricted 8+3 DOS
752 filename space. */
753 val = concat2 (prefix, build_string ("a.XXX"));
754#else
755 val = concat2 (prefix, build_string ("XXXXXX"));
756#endif
757 mktemp (XSTRING (val)->data);
758#ifdef DOS_NT
759 CORRECT_DIR_SEPS (XSTRING (val)->data);
760#endif
761 return val;
762}
763\f
764DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
765 "Convert filename NAME to absolute, and canonicalize it.\n\
766Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative\n\
767 (does not start with slash); if DEFAULT-DIRECTORY is nil or missing,\n\
768the current buffer's value of default-directory is used.\n\
769File name components that are `.' are removed, and \n\
770so are file name components followed by `..', along with the `..' itself;\n\
771note that these simplifications are done without checking the resulting\n\
772file names in the file system.\n\
773An initial `~/' expands to your home directory.\n\
774An initial `~USER/' expands to USER's home directory.\n\
775See also the function `substitute-in-file-name'.")
776 (name, default_directory)
777 Lisp_Object name, default_directory;
778{
779 unsigned char *nm;
780
781 register unsigned char *newdir, *p, *o;
782 int tlen;
783 unsigned char *target;
784 struct passwd *pw;
785#ifdef VMS
786 unsigned char * colon = 0;
787 unsigned char * close = 0;
788 unsigned char * slash = 0;
789 unsigned char * brack = 0;
790 int lbrack = 0, rbrack = 0;
791 int dots = 0;
792#endif /* VMS */
793#ifdef DOS_NT
794 int drive = 0;
795 int collapse_newdir = 1;
796#endif /* DOS_NT */
797 int length;
798 Lisp_Object handler;
799
800 CHECK_STRING (name, 0);
801
802 /* If the file name has special constructs in it,
803 call the corresponding file handler. */
804 handler = Ffind_file_name_handler (name, Qexpand_file_name);
805 if (!NILP (handler))
806 return call3 (handler, Qexpand_file_name, name, default_directory);
807
808 /* Use the buffer's default-directory if DEFAULT_DIRECTORY is omitted. */
809 if (NILP (default_directory))
810 default_directory = current_buffer->directory;
811 CHECK_STRING (default_directory, 1);
812
813 if (!NILP (default_directory))
814 {
815 handler = Ffind_file_name_handler (default_directory, Qexpand_file_name);
816 if (!NILP (handler))
817 return call3 (handler, Qexpand_file_name, name, default_directory);
818 }
819
820 o = XSTRING (default_directory)->data;
821
822 /* Make sure DEFAULT_DIRECTORY is properly expanded.
823 It would be better to do this down below where we actually use
824 default_directory. Unfortunately, calling Fexpand_file_name recursively
825 could invoke GC, and the strings might be relocated. This would
826 be annoying because we have pointers into strings lying around
827 that would need adjusting, and people would add new pointers to
828 the code and forget to adjust them, resulting in intermittent bugs.
829 Putting this call here avoids all that crud.
830
831 The EQ test avoids infinite recursion. */
832 if (! NILP (default_directory) && !EQ (default_directory, name)
833 /* Save time in some common cases - as long as default_directory
834 is not relative, it can be canonicalized with name below (if it
835 is needed at all) without requiring it to be expanded now. */
836#ifdef DOS_NT
837 /* Detect MSDOS file names with drive specifiers. */
838 && ! (IS_DRIVE (o[0]) && (IS_DEVICE_SEP (o[1]) && IS_DIRECTORY_SEP (o[2])))
839#ifdef WINDOWSNT
840 /* Detect Windows file names in UNC format. */
841 && ! (IS_DIRECTORY_SEP (o[0]) && IS_DIRECTORY_SEP (o[1]))
842#endif
843#else /* not DOS_NT */
844 /* Detect Unix absolute file names (/... alone is not absolute on
845 DOS or Windows). */
846 && ! (IS_DIRECTORY_SEP (o[0]))
847#endif /* not DOS_NT */
848 )
849 {
850 struct gcpro gcpro1;
851
852 GCPRO1 (name);
853 default_directory = Fexpand_file_name (default_directory, Qnil);
854 UNGCPRO;
855 }
856
857#ifdef VMS
858 /* Filenames on VMS are always upper case. */
859 name = Fupcase (name);
860#endif
861#ifdef FILE_SYSTEM_CASE
862 name = FILE_SYSTEM_CASE (name);
863#endif
864
865 nm = XSTRING (name)->data;
866
867#ifdef DOS_NT
868 /* We will force directory separators to be either all \ or /, so make
869 a local copy to modify, even if there ends up being no change. */
870 nm = strcpy (alloca (strlen (nm) + 1), nm);
871
872 /* Find and remove drive specifier if present; this makes nm absolute
873 even if the rest of the name appears to be relative. */
874 {
875 unsigned char *colon = rindex (nm, ':');
876
877 if (colon)
878 /* Only recognize colon as part of drive specifier if there is a
879 single alphabetic character preceeding the colon (and if the
880 character before the drive letter, if present, is a directory
881 separator); this is to support the remote system syntax used by
882 ange-ftp, and the "po:username" syntax for POP mailboxes. */
883 look_again:
884 if (nm == colon)
885 nm++;
886 else if (IS_DRIVE (colon[-1])
887 && (colon == nm + 1 || IS_DIRECTORY_SEP (colon[-2])))
888 {
889 drive = colon[-1];
890 nm = colon + 1;
891 }
892 else
893 {
894 while (--colon >= nm)
895 if (colon[0] == ':')
896 goto look_again;
897 }
898 }
899#endif /* DOS_NT */
900
901 /* Handle // and /~ in middle of file name
902 by discarding everything through the first / of that sequence. */
903 p = nm;
904 while (*p)
905 {
906 /* Since we are expecting the name to be absolute, we can assume
907 that each element starts with a "/". */
908
909 if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
910#if defined (APOLLO) || defined (WINDOWSNT)
911 /* // at start of filename is meaningful on Apollo
912 and WindowsNT systems */
913 && nm != p
914#endif /* APOLLO || WINDOWSNT */
915 )
916 nm = p + 1;
917
918 if (IS_DIRECTORY_SEP (p[0]) && p[1] == '~')
919 nm = p + 1;
920
921 p++;
922 }
923
924#ifdef WINDOWSNT
925 /* Discard any previous drive specifier if nm is now in UNC format. */
926 if (IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
927 {
928 drive = 0;
929 }
930#endif
931
932 /* If nm is absolute, look for /./ or /../ sequences; if none are
933 found, we can probably return right away. We will avoid allocating
934 a new string if name is already fully expanded. */
935 if (
936 IS_DIRECTORY_SEP (nm[0])
937#ifdef MSDOS
938 && drive
939#endif
940#ifdef WINDOWSNT
941 && (drive || IS_DIRECTORY_SEP (nm[1]))
942#endif
943#ifdef VMS
944 || index (nm, ':')
945#endif /* VMS */
946 )
947 {
948 /* If it turns out that the filename we want to return is just a
949 suffix of FILENAME, we don't need to go through and edit
950 things; we just need to construct a new string using data
951 starting at the middle of FILENAME. If we set lose to a
952 non-zero value, that means we've discovered that we can't do
953 that cool trick. */
954 int lose = 0;
955
956 p = nm;
957 while (*p)
958 {
959 /* Since we know the name is absolute, we can assume that each
960 element starts with a "/". */
961
962 /* "." and ".." are hairy. */
963 if (IS_DIRECTORY_SEP (p[0])
964 && p[1] == '.'
965 && (IS_DIRECTORY_SEP (p[2])
966 || p[2] == 0
967 || (p[2] == '.' && (IS_DIRECTORY_SEP (p[3])
968 || p[3] == 0))))
969 lose = 1;
970#ifdef VMS
971 if (p[0] == '\\')
972 lose = 1;
973 if (p[0] == '/') {
974 /* if dev:[dir]/, move nm to / */
975 if (!slash && p > nm && (brack || colon)) {
976 nm = (brack ? brack + 1 : colon + 1);
977 lbrack = rbrack = 0;
978 brack = 0;
979 colon = 0;
980 }
981 slash = p;
982 }
983 if (p[0] == '-')
984#ifndef VMS4_4
985 /* VMS pre V4.4,convert '-'s in filenames. */
986 if (lbrack == rbrack)
987 {
988 if (dots < 2) /* this is to allow negative version numbers */
989 p[0] = '_';
990 }
991 else
992#endif /* VMS4_4 */
993 if (lbrack > rbrack &&
994 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
995 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
996 lose = 1;
997#ifndef VMS4_4
998 else
999 p[0] = '_';
1000#endif /* VMS4_4 */
1001 /* count open brackets, reset close bracket pointer */
1002 if (p[0] == '[' || p[0] == '<')
1003 lbrack++, brack = 0;
1004 /* count close brackets, set close bracket pointer */
1005 if (p[0] == ']' || p[0] == '>')
1006 rbrack++, brack = p;
1007 /* detect ][ or >< */
1008 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
1009 lose = 1;
1010 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
1011 nm = p + 1, lose = 1;
1012 if (p[0] == ':' && (colon || slash))
1013 /* if dev1:[dir]dev2:, move nm to dev2: */
1014 if (brack)
1015 {
1016 nm = brack + 1;
1017 brack = 0;
1018 }
1019 /* if /name/dev:, move nm to dev: */
1020 else if (slash)
1021 nm = slash + 1;
1022 /* if node::dev:, move colon following dev */
1023 else if (colon && colon[-1] == ':')
1024 colon = p;
1025 /* if dev1:dev2:, move nm to dev2: */
1026 else if (colon && colon[-1] != ':')
1027 {
1028 nm = colon + 1;
1029 colon = 0;
1030 }
1031 if (p[0] == ':' && !colon)
1032 {
1033 if (p[1] == ':')
1034 p++;
1035 colon = p;
1036 }
1037 if (lbrack == rbrack)
1038 if (p[0] == ';')
1039 dots = 2;
1040 else if (p[0] == '.')
1041 dots++;
1042#endif /* VMS */
1043 p++;
1044 }
1045 if (!lose)
1046 {
1047#ifdef VMS
1048 if (index (nm, '/'))
1049 return build_string (sys_translate_unix (nm));
1050#endif /* VMS */
1051#ifdef DOS_NT
1052 /* Make sure directories are all separated with / or \ as
1053 desired, but avoid allocation of a new string when not
1054 required. */
1055 CORRECT_DIR_SEPS (nm);
1056#ifdef WINDOWSNT
1057 if (IS_DIRECTORY_SEP (nm[1]))
1058 {
1059 if (strcmp (nm, XSTRING (name)->data) != 0)
1060 name = build_string (nm);
1061 }
1062 else
1063#endif
1064 /* drive must be set, so this is okay */
1065 if (strcmp (nm - 2, XSTRING (name)->data) != 0)
1066 {
1067 name = make_string (nm - 2, p - nm + 2);
1068 XSTRING (name)->data[0] = drive;
1069 XSTRING (name)->data[1] = ':';
1070 }
1071 return name;
1072#else /* not DOS_NT */
1073 if (nm == XSTRING (name)->data)
1074 return name;
1075 return build_string (nm);
1076#endif /* not DOS_NT */
1077 }
1078 }
1079
1080 /* At this point, nm might or might not be an absolute file name. We
1081 need to expand ~ or ~user if present, otherwise prefix nm with
1082 default_directory if nm is not absolute, and finally collapse /./
1083 and /foo/../ sequences.
1084
1085 We set newdir to be the appropriate prefix if one is needed:
1086 - the relevant user directory if nm starts with ~ or ~user
1087 - the specified drive's working dir (DOS/NT only) if nm does not
1088 start with /
1089 - the value of default_directory.
1090
1091 Note that these prefixes are not guaranteed to be absolute (except
1092 for the working dir of a drive). Therefore, to ensure we always
1093 return an absolute name, if the final prefix is not absolute we
1094 append it to the current working directory. */
1095
1096 newdir = 0;
1097
1098 if (nm[0] == '~') /* prefix ~ */
1099 {
1100 if (IS_DIRECTORY_SEP (nm[1])
1101#ifdef VMS
1102 || nm[1] == ':'
1103#endif /* VMS */
1104 || nm[1] == 0) /* ~ by itself */
1105 {
1106 if (!(newdir = (unsigned char *) egetenv ("HOME")))
1107 newdir = (unsigned char *) "";
1108 nm++;
1109#ifdef DOS_NT
1110 collapse_newdir = 0;
1111#endif
1112#ifdef VMS
1113 nm++; /* Don't leave the slash in nm. */
1114#endif /* VMS */
1115 }
1116 else /* ~user/filename */
1117 {
1118 for (p = nm; *p && (!IS_DIRECTORY_SEP (*p)
1119#ifdef VMS
1120 && *p != ':'
1121#endif /* VMS */
1122 ); p++);
1123 o = (unsigned char *) alloca (p - nm + 1);
1124 bcopy ((char *) nm, o, p - nm);
1125 o [p - nm] = 0;
1126
1127 pw = (struct passwd *) getpwnam (o + 1);
1128 if (pw)
1129 {
1130 newdir = (unsigned char *) pw -> pw_dir;
1131#ifdef VMS
1132 nm = p + 1; /* skip the terminator */
1133#else
1134 nm = p;
1135#ifdef DOS_NT
1136 collapse_newdir = 0;
1137#endif
1138#endif /* VMS */
1139 }
1140
1141 /* If we don't find a user of that name, leave the name
1142 unchanged; don't move nm forward to p. */
1143 }
1144 }
1145
1146#ifdef DOS_NT
1147 /* On DOS and Windows, nm is absolute if a drive name was specified;
1148 use the drive's current directory as the prefix if needed. */
1149 if (!newdir && drive)
1150 {
1151 /* Get default directory if needed to make nm absolute. */
1152 if (!IS_DIRECTORY_SEP (nm[0]))
1153 {
1154 newdir = alloca (MAXPATHLEN + 1);
1155 if (!getdefdir (toupper (drive) - 'A' + 1, newdir))
1156 newdir = NULL;
1157 }
1158 if (!newdir)
1159 {
1160 /* Either nm starts with /, or drive isn't mounted. */
1161 newdir = alloca (4);
1162 newdir[0] = drive;
1163 newdir[1] = ':';
1164 newdir[2] = '/';
1165 newdir[3] = 0;
1166 }
1167 }
1168#endif /* DOS_NT */
1169
1170 /* Finally, if no prefix has been specified and nm is not absolute,
1171 then it must be expanded relative to default_directory. */
1172
1173 if (1
1174#ifndef DOS_NT
1175 /* /... alone is not absolute on DOS and Windows. */
1176 && !IS_DIRECTORY_SEP (nm[0])
1177#endif
1178#ifdef WINDOWSNT
1179 && !(IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
1180#endif
1181#ifdef VMS
1182 && !index (nm, ':')
1183#endif
1184 && !newdir)
1185 {
1186 newdir = XSTRING (default_directory)->data;
1187 }
1188
1189#ifdef DOS_NT
1190 if (newdir)
1191 {
1192 /* First ensure newdir is an absolute name. */
1193 if (
1194 /* Detect MSDOS file names with drive specifiers. */
1195 ! (IS_DRIVE (newdir[0])
1196 && IS_DEVICE_SEP (newdir[1]) && IS_DIRECTORY_SEP (newdir[2]))
1197#ifdef WINDOWSNT
1198 /* Detect Windows file names in UNC format. */
1199 && ! (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1]))
1200#endif
1201 )
1202 {
1203 /* Effectively, let newdir be (expand-file-name newdir cwd).
1204 Because of the admonition against calling expand-file-name
1205 when we have pointers into lisp strings, we accomplish this
1206 indirectly by prepending newdir to nm if necessary, and using
1207 cwd (or the wd of newdir's drive) as the new newdir. */
1208
1209 if (IS_DRIVE (newdir[0]) && newdir[1] == ':')
1210 {
1211 drive = newdir[0];
1212 newdir += 2;
1213 }
1214 if (!IS_DIRECTORY_SEP (nm[0]))
1215 {
1216 char * tmp = alloca (strlen (newdir) + strlen (nm) + 2);
1217 file_name_as_directory (tmp, newdir);
1218 strcat (tmp, nm);
1219 nm = tmp;
1220 }
1221 newdir = alloca (MAXPATHLEN + 1);
1222 if (drive)
1223 {
1224 if (!getdefdir (toupper (drive) - 'A' + 1, newdir))
1225 newdir = "/";
1226 }
1227 else
1228 getwd (newdir);
1229 }
1230
1231 /* Strip off drive name from prefix, if present. */
1232 if (IS_DRIVE (newdir[0]) && newdir[1] == ':')
1233 {
1234 drive = newdir[0];
1235 newdir += 2;
1236 }
1237
1238 /* Keep only a prefix from newdir if nm starts with slash
1239 (//server/share for UNC, nothing otherwise). */
1240 if (IS_DIRECTORY_SEP (nm[0]) && collapse_newdir)
1241 {
1242#ifdef WINDOWSNT
1243 if (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1]))
1244 {
1245 newdir = strcpy (alloca (strlen (newdir) + 1), newdir);
1246 p = newdir + 2;
1247 while (*p && !IS_DIRECTORY_SEP (*p)) p++;
1248 p++;
1249 while (*p && !IS_DIRECTORY_SEP (*p)) p++;
1250 *p = 0;
1251 }
1252 else
1253#endif
1254 newdir = "";
1255 }
1256 }
1257#endif /* DOS_NT */
1258
1259 if (newdir)
1260 {
1261 /* Get rid of any slash at the end of newdir, unless newdir is
1262 just // (an incomplete UNC name). */
1263 length = strlen (newdir);
1264 if (IS_DIRECTORY_SEP (newdir[length - 1])
1265#ifdef WINDOWSNT
1266 && !(length == 2 && IS_DIRECTORY_SEP (newdir[0]))
1267#endif
1268 )
1269 {
1270 unsigned char *temp = (unsigned char *) alloca (length);
1271 bcopy (newdir, temp, length - 1);
1272 temp[length - 1] = 0;
1273 newdir = temp;
1274 }
1275 tlen = length + 1;
1276 }
1277 else
1278 tlen = 0;
1279
1280 /* Now concatenate the directory and name to new space in the stack frame */
1281 tlen += strlen (nm) + 1;
1282#ifdef DOS_NT
1283 /* Add reserved space for drive name. (The Microsoft x86 compiler
1284 produces incorrect code if the following two lines are combined.) */
1285 target = (unsigned char *) alloca (tlen + 2);
1286 target += 2;
1287#else /* not DOS_NT */
1288 target = (unsigned char *) alloca (tlen);
1289#endif /* not DOS_NT */
1290 *target = 0;
1291
1292 if (newdir)
1293 {
1294#ifndef VMS
1295 if (nm[0] == 0 || IS_DIRECTORY_SEP (nm[0]))
1296 strcpy (target, newdir);
1297 else
1298#endif
1299 file_name_as_directory (target, newdir);
1300 }
1301
1302 strcat (target, nm);
1303#ifdef VMS
1304 if (index (target, '/'))
1305 strcpy (target, sys_translate_unix (target));
1306#endif /* VMS */
1307
1308 /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */
1309
1310 /* Now canonicalize by removing /. and /foo/.. if they appear. */
1311
1312 p = target;
1313 o = target;
1314
1315 while (*p)
1316 {
1317#ifdef VMS
1318 if (*p != ']' && *p != '>' && *p != '-')
1319 {
1320 if (*p == '\\')
1321 p++;
1322 *o++ = *p++;
1323 }
1324 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
1325 /* brackets are offset from each other by 2 */
1326 {
1327 p += 2;
1328 if (*p != '.' && *p != '-' && o[-1] != '.')
1329 /* convert [foo][bar] to [bar] */
1330 while (o[-1] != '[' && o[-1] != '<')
1331 o--;
1332 else if (*p == '-' && *o != '.')
1333 *--p = '.';
1334 }
1335 else if (p[0] == '-' && o[-1] == '.' &&
1336 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1337 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1338 {
1339 do
1340 o--;
1341 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1342 if (p[1] == '.') /* foo.-.bar ==> bar. */
1343 p += 2;
1344 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1345 p++, o--;
1346 /* else [foo.-] ==> [-] */
1347 }
1348 else
1349 {
1350#ifndef VMS4_4
1351 if (*p == '-' &&
1352 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
1353 p[1] != ']' && p[1] != '>' && p[1] != '.')
1354 *p = '_';
1355#endif /* VMS4_4 */
1356 *o++ = *p++;
1357 }
1358#else /* not VMS */
1359 if (!IS_DIRECTORY_SEP (*p))
1360 {
1361 *o++ = *p++;
1362 }
1363 else if (IS_DIRECTORY_SEP (p[0]) && IS_DIRECTORY_SEP (p[1])
1364#if defined (APOLLO) || defined (WINDOWSNT)
1365 /* // at start of filename is meaningful in Apollo
1366 and WindowsNT systems */
1367 && o != target
1368#endif /* APOLLO || WINDOWSNT */
1369 )
1370 {
1371 o = target;
1372 p++;
1373 }
1374 else if (IS_DIRECTORY_SEP (p[0])
1375 && p[1] == '.'
1376 && (IS_DIRECTORY_SEP (p[2])
1377 || p[2] == 0))
1378 {
1379 /* If "/." is the entire filename, keep the "/". Otherwise,
1380 just delete the whole "/.". */
1381 if (o == target && p[2] == '\0')
1382 *o++ = *p;
1383 p += 2;
1384 }
1385 else if (IS_DIRECTORY_SEP (p[0]) && p[1] == '.' && p[2] == '.'
1386 /* `/../' is the "superroot" on certain file systems. */
1387 && o != target
1388 && (IS_DIRECTORY_SEP (p[3]) || p[3] == 0))
1389 {
1390 while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
1391 ;
1392 p += 3;
1393 }
1394 else
1395 {
1396 *o++ = *p++;
1397 }
1398#endif /* not VMS */
1399 }
1400
1401#ifdef DOS_NT
1402 /* At last, set drive name. */
1403#ifdef WINDOWSNT
1404 /* Except for network file name. */
1405 if (!(IS_DIRECTORY_SEP (target[0]) && IS_DIRECTORY_SEP (target[1])))
1406#endif /* WINDOWSNT */
1407 {
1408 if (!drive) abort ();
1409 target -= 2;
1410 target[0] = drive;
1411 target[1] = ':';
1412 }
1413 CORRECT_DIR_SEPS (target);
1414#endif /* DOS_NT */
1415
1416 return make_string (target, o - target);
1417}
1418
1419#if 0
1420/* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'. */
1421DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
1422 "Convert FILENAME to absolute, and canonicalize it.\n\
1423Second arg DEFAULT is directory to start with if FILENAME is relative\n\
1424 (does not start with slash); if DEFAULT is nil or missing,\n\
1425the current buffer's value of default-directory is used.\n\
1426Filenames containing `.' or `..' as components are simplified;\n\
1427initial `~/' expands to your home directory.\n\
1428See also the function `substitute-in-file-name'.")
1429 (name, defalt)
1430 Lisp_Object name, defalt;
1431{
1432 unsigned char *nm;
1433
1434 register unsigned char *newdir, *p, *o;
1435 int tlen;
1436 unsigned char *target;
1437 struct passwd *pw;
1438 int lose;
1439#ifdef VMS
1440 unsigned char * colon = 0;
1441 unsigned char * close = 0;
1442 unsigned char * slash = 0;
1443 unsigned char * brack = 0;
1444 int lbrack = 0, rbrack = 0;
1445 int dots = 0;
1446#endif /* VMS */
1447
1448 CHECK_STRING (name, 0);
1449
1450#ifdef VMS
1451 /* Filenames on VMS are always upper case. */
1452 name = Fupcase (name);
1453#endif
1454
1455 nm = XSTRING (name)->data;
1456
1457 /* If nm is absolute, flush ...// and detect /./ and /../.
1458 If no /./ or /../ we can return right away. */
1459 if (
1460 nm[0] == '/'
1461#ifdef VMS
1462 || index (nm, ':')
1463#endif /* VMS */
1464 )
1465 {
1466 p = nm;
1467 lose = 0;
1468 while (*p)
1469 {
1470 if (p[0] == '/' && p[1] == '/'
1471#ifdef APOLLO
1472 /* // at start of filename is meaningful on Apollo system */
1473 && nm != p
1474#endif /* APOLLO */
1475 )
1476 nm = p + 1;
1477 if (p[0] == '/' && p[1] == '~')
1478 nm = p + 1, lose = 1;
1479 if (p[0] == '/' && p[1] == '.'
1480 && (p[2] == '/' || p[2] == 0
1481 || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
1482 lose = 1;
1483#ifdef VMS
1484 if (p[0] == '\\')
1485 lose = 1;
1486 if (p[0] == '/') {
1487 /* if dev:[dir]/, move nm to / */
1488 if (!slash && p > nm && (brack || colon)) {
1489 nm = (brack ? brack + 1 : colon + 1);
1490 lbrack = rbrack = 0;
1491 brack = 0;
1492 colon = 0;
1493 }
1494 slash = p;
1495 }
1496 if (p[0] == '-')
1497#ifndef VMS4_4
1498 /* VMS pre V4.4,convert '-'s in filenames. */
1499 if (lbrack == rbrack)
1500 {
1501 if (dots < 2) /* this is to allow negative version numbers */
1502 p[0] = '_';
1503 }
1504 else
1505#endif /* VMS4_4 */
1506 if (lbrack > rbrack &&
1507 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
1508 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
1509 lose = 1;
1510#ifndef VMS4_4
1511 else
1512 p[0] = '_';
1513#endif /* VMS4_4 */
1514 /* count open brackets, reset close bracket pointer */
1515 if (p[0] == '[' || p[0] == '<')
1516 lbrack++, brack = 0;
1517 /* count close brackets, set close bracket pointer */
1518 if (p[0] == ']' || p[0] == '>')
1519 rbrack++, brack = p;
1520 /* detect ][ or >< */
1521 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
1522 lose = 1;
1523 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
1524 nm = p + 1, lose = 1;
1525 if (p[0] == ':' && (colon || slash))
1526 /* if dev1:[dir]dev2:, move nm to dev2: */
1527 if (brack)
1528 {
1529 nm = brack + 1;
1530 brack = 0;
1531 }
1532 /* If /name/dev:, move nm to dev: */
1533 else if (slash)
1534 nm = slash + 1;
1535 /* If node::dev:, move colon following dev */
1536 else if (colon && colon[-1] == ':')
1537 colon = p;
1538 /* If dev1:dev2:, move nm to dev2: */
1539 else if (colon && colon[-1] != ':')
1540 {
1541 nm = colon + 1;
1542 colon = 0;
1543 }
1544 if (p[0] == ':' && !colon)
1545 {
1546 if (p[1] == ':')
1547 p++;
1548 colon = p;
1549 }
1550 if (lbrack == rbrack)
1551 if (p[0] == ';')
1552 dots = 2;
1553 else if (p[0] == '.')
1554 dots++;
1555#endif /* VMS */
1556 p++;
1557 }
1558 if (!lose)
1559 {
1560#ifdef VMS
1561 if (index (nm, '/'))
1562 return build_string (sys_translate_unix (nm));
1563#endif /* VMS */
1564 if (nm == XSTRING (name)->data)
1565 return name;
1566 return build_string (nm);
1567 }
1568 }
1569
1570 /* Now determine directory to start with and put it in NEWDIR */
1571
1572 newdir = 0;
1573
1574 if (nm[0] == '~') /* prefix ~ */
1575 if (nm[1] == '/'
1576#ifdef VMS
1577 || nm[1] == ':'
1578#endif /* VMS */
1579 || nm[1] == 0)/* ~/filename */
1580 {
1581 if (!(newdir = (unsigned char *) egetenv ("HOME")))
1582 newdir = (unsigned char *) "";
1583 nm++;
1584#ifdef VMS
1585 nm++; /* Don't leave the slash in nm. */
1586#endif /* VMS */
1587 }
1588 else /* ~user/filename */
1589 {
1590 /* Get past ~ to user */
1591 unsigned char *user = nm + 1;
1592 /* Find end of name. */
1593 unsigned char *ptr = (unsigned char *) index (user, '/');
1594 int len = ptr ? ptr - user : strlen (user);
1595#ifdef VMS
1596 unsigned char *ptr1 = index (user, ':');
1597 if (ptr1 != 0 && ptr1 - user < len)
1598 len = ptr1 - user;
1599#endif /* VMS */
1600 /* Copy the user name into temp storage. */
1601 o = (unsigned char *) alloca (len + 1);
1602 bcopy ((char *) user, o, len);
1603 o[len] = 0;
1604
1605 /* Look up the user name. */
1606 pw = (struct passwd *) getpwnam (o + 1);
1607 if (!pw)
1608 error ("\"%s\" isn't a registered user", o + 1);
1609
1610 newdir = (unsigned char *) pw->pw_dir;
1611
1612 /* Discard the user name from NM. */
1613 nm += len;
1614 }
1615
1616 if (nm[0] != '/'
1617#ifdef VMS
1618 && !index (nm, ':')
1619#endif /* not VMS */
1620 && !newdir)
1621 {
1622 if (NILP (defalt))
1623 defalt = current_buffer->directory;
1624 CHECK_STRING (defalt, 1);
1625 newdir = XSTRING (defalt)->data;
1626 }
1627
1628 /* Now concatenate the directory and name to new space in the stack frame */
1629
1630 tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1;
1631 target = (unsigned char *) alloca (tlen);
1632 *target = 0;
1633
1634 if (newdir)
1635 {
1636#ifndef VMS
1637 if (nm[0] == 0 || nm[0] == '/')
1638 strcpy (target, newdir);
1639 else
1640#endif
1641 file_name_as_directory (target, newdir);
1642 }
1643
1644 strcat (target, nm);
1645#ifdef VMS
1646 if (index (target, '/'))
1647 strcpy (target, sys_translate_unix (target));
1648#endif /* VMS */
1649
1650 /* Now canonicalize by removing /. and /foo/.. if they appear */
1651
1652 p = target;
1653 o = target;
1654
1655 while (*p)
1656 {
1657#ifdef VMS
1658 if (*p != ']' && *p != '>' && *p != '-')
1659 {
1660 if (*p == '\\')
1661 p++;
1662 *o++ = *p++;
1663 }
1664 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
1665 /* brackets are offset from each other by 2 */
1666 {
1667 p += 2;
1668 if (*p != '.' && *p != '-' && o[-1] != '.')
1669 /* convert [foo][bar] to [bar] */
1670 while (o[-1] != '[' && o[-1] != '<')
1671 o--;
1672 else if (*p == '-' && *o != '.')
1673 *--p = '.';
1674 }
1675 else if (p[0] == '-' && o[-1] == '.' &&
1676 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1677 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1678 {
1679 do
1680 o--;
1681 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1682 if (p[1] == '.') /* foo.-.bar ==> bar. */
1683 p += 2;
1684 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1685 p++, o--;
1686 /* else [foo.-] ==> [-] */
1687 }
1688 else
1689 {
1690#ifndef VMS4_4
1691 if (*p == '-' &&
1692 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
1693 p[1] != ']' && p[1] != '>' && p[1] != '.')
1694 *p = '_';
1695#endif /* VMS4_4 */
1696 *o++ = *p++;
1697 }
1698#else /* not VMS */
1699 if (*p != '/')
1700 {
1701 *o++ = *p++;
1702 }
1703 else if (!strncmp (p, "//", 2)
1704#ifdef APOLLO
1705 /* // at start of filename is meaningful in Apollo system */
1706 && o != target
1707#endif /* APOLLO */
1708 )
1709 {
1710 o = target;
1711 p++;
1712 }
1713 else if (p[0] == '/' && p[1] == '.' &&
1714 (p[2] == '/' || p[2] == 0))
1715 p += 2;
1716 else if (!strncmp (p, "/..", 3)
1717 /* `/../' is the "superroot" on certain file systems. */
1718 && o != target
1719 && (p[3] == '/' || p[3] == 0))
1720 {
1721 while (o != target && *--o != '/')
1722 ;
1723#ifdef APOLLO
1724 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
1725 ++o;
1726 else
1727#endif /* APOLLO */
1728 if (o == target && *o == '/')
1729 ++o;
1730 p += 3;
1731 }
1732 else
1733 {
1734 *o++ = *p++;
1735 }
1736#endif /* not VMS */
1737 }
1738
1739 return make_string (target, o - target);
1740}
1741#endif
1742\f
1743DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name,
1744 Ssubstitute_in_file_name, 1, 1, 0,
1745 "Substitute environment variables referred to in FILENAME.\n\
1746`$FOO' where FOO is an environment variable name means to substitute\n\
1747the value of that variable. The variable name should be terminated\n\
1748with a character not a letter, digit or underscore; otherwise, enclose\n\
1749the entire variable name in braces.\n\
1750If `/~' appears, all of FILENAME through that `/' is discarded.\n\n\
1751On VMS, `$' substitution is not done; this function does little and only\n\
1752duplicates what `expand-file-name' does.")
1753 (filename)
1754 Lisp_Object filename;
1755{
1756 unsigned char *nm;
1757
1758 register unsigned char *s, *p, *o, *x, *endp;
1759 unsigned char *target;
1760 int total = 0;
1761 int substituted = 0;
1762 unsigned char *xnm;
1763 Lisp_Object handler;
1764
1765 CHECK_STRING (filename, 0);
1766
1767 /* If the file name has special constructs in it,
1768 call the corresponding file handler. */
1769 handler = Ffind_file_name_handler (filename, Qsubstitute_in_file_name);
1770 if (!NILP (handler))
1771 return call2 (handler, Qsubstitute_in_file_name, filename);
1772
1773 nm = XSTRING (filename)->data;
1774#ifdef DOS_NT
1775 nm = strcpy (alloca (strlen (nm) + 1), nm);
1776 CORRECT_DIR_SEPS (nm);
1777 substituted = (strcmp (nm, XSTRING (filename)->data) != 0);
1778#endif
1779 endp = nm + XSTRING (filename)->size;
1780
1781 /* If /~ or // appears, discard everything through first slash. */
1782
1783 for (p = nm; p != endp; p++)
1784 {
1785 if ((p[0] == '~'
1786#if defined (APOLLO) || defined (WINDOWSNT)
1787 /* // at start of file name is meaningful in Apollo and
1788 WindowsNT systems */
1789 || (IS_DIRECTORY_SEP (p[0]) && p - 1 != nm)
1790#else /* not (APOLLO || WINDOWSNT) */
1791 || IS_DIRECTORY_SEP (p[0])
1792#endif /* not (APOLLO || WINDOWSNT) */
1793 )
1794 && p != nm
1795 && (0
1796#ifdef VMS
1797 || p[-1] == ':' || p[-1] == ']' || p[-1] == '>'
1798#endif /* VMS */
1799 || IS_DIRECTORY_SEP (p[-1])))
1800 {
1801 nm = p;
1802 substituted = 1;
1803 }
1804#ifdef DOS_NT
1805 /* see comment in expand-file-name about drive specifiers */
1806 else if (IS_DRIVE (p[0]) && p[1] == ':'
1807 && p > nm && IS_DIRECTORY_SEP (p[-1]))
1808 {
1809 nm = p;
1810 substituted = 1;
1811 }
1812#endif /* DOS_NT */
1813 }
1814
1815#ifdef VMS
1816 return build_string (nm);
1817#else
1818
1819 /* See if any variables are substituted into the string
1820 and find the total length of their values in `total' */
1821
1822 for (p = nm; p != endp;)
1823 if (*p != '$')
1824 p++;
1825 else
1826 {
1827 p++;
1828 if (p == endp)
1829 goto badsubst;
1830 else if (*p == '$')
1831 {
1832 /* "$$" means a single "$" */
1833 p++;
1834 total -= 1;
1835 substituted = 1;
1836 continue;
1837 }
1838 else if (*p == '{')
1839 {
1840 o = ++p;
1841 while (p != endp && *p != '}') p++;
1842 if (*p != '}') goto missingclose;
1843 s = p;
1844 }
1845 else
1846 {
1847 o = p;
1848 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1849 s = p;
1850 }
1851
1852 /* Copy out the variable name */
1853 target = (unsigned char *) alloca (s - o + 1);
1854 strncpy (target, o, s - o);
1855 target[s - o] = 0;
1856#ifdef DOS_NT
1857 strupr (target); /* $home == $HOME etc. */
1858#endif /* DOS_NT */
1859
1860 /* Get variable value */
1861 o = (unsigned char *) egetenv (target);
1862 if (!o) goto badvar;
1863 total += strlen (o);
1864 substituted = 1;
1865 }
1866
1867 if (!substituted)
1868 return filename;
1869
1870 /* If substitution required, recopy the string and do it */
1871 /* Make space in stack frame for the new copy */
1872 xnm = (unsigned char *) alloca (XSTRING (filename)->size + total + 1);
1873 x = xnm;
1874
1875 /* Copy the rest of the name through, replacing $ constructs with values */
1876 for (p = nm; *p;)
1877 if (*p != '$')
1878 *x++ = *p++;
1879 else
1880 {
1881 p++;
1882 if (p == endp)
1883 goto badsubst;
1884 else if (*p == '$')
1885 {
1886 *x++ = *p++;
1887 continue;
1888 }
1889 else if (*p == '{')
1890 {
1891 o = ++p;
1892 while (p != endp && *p != '}') p++;
1893 if (*p != '}') goto missingclose;
1894 s = p++;
1895 }
1896 else
1897 {
1898 o = p;
1899 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1900 s = p;
1901 }
1902
1903 /* Copy out the variable name */
1904 target = (unsigned char *) alloca (s - o + 1);
1905 strncpy (target, o, s - o);
1906 target[s - o] = 0;
1907#ifdef DOS_NT
1908 strupr (target); /* $home == $HOME etc. */
1909#endif /* DOS_NT */
1910
1911 /* Get variable value */
1912 o = (unsigned char *) egetenv (target);
1913 if (!o)
1914 goto badvar;
1915
1916 strcpy (x, o);
1917 x += strlen (o);
1918 }
1919
1920 *x = 0;
1921
1922 /* If /~ or // appears, discard everything through first slash. */
1923
1924 for (p = xnm; p != x; p++)
1925 if ((p[0] == '~'
1926#if defined (APOLLO) || defined (WINDOWSNT)
1927 || (IS_DIRECTORY_SEP (p[0]) && p - 1 != xnm)
1928#else /* not (APOLLO || WINDOWSNT) */
1929 || IS_DIRECTORY_SEP (p[0])
1930#endif /* not (APOLLO || WINDOWSNT) */
1931 )
1932 && p != nm && IS_DIRECTORY_SEP (p[-1]))
1933 xnm = p;
1934#ifdef DOS_NT
1935 else if (IS_DRIVE (p[0]) && p[1] == ':'
1936 && p > nm && IS_DIRECTORY_SEP (p[-1]))
1937 xnm = p;
1938#endif
1939
1940 return make_string (xnm, x - xnm);
1941
1942 badsubst:
1943 error ("Bad format environment-variable substitution");
1944 missingclose:
1945 error ("Missing \"}\" in environment-variable substitution");
1946 badvar:
1947 error ("Substituting nonexistent environment variable \"%s\"", target);
1948
1949 /* NOTREACHED */
1950#endif /* not VMS */
1951}
1952\f
1953/* A slightly faster and more convenient way to get
1954 (directory-file-name (expand-file-name FOO)). */
1955
1956Lisp_Object
1957expand_and_dir_to_file (filename, defdir)
1958 Lisp_Object filename, defdir;
1959{
1960 register Lisp_Object absname;
1961
1962 absname = Fexpand_file_name (filename, defdir);
1963#ifdef VMS
1964 {
1965 register int c = XSTRING (absname)->data[XSTRING (absname)->size - 1];
1966 if (c == ':' || c == ']' || c == '>')
1967 absname = Fdirectory_file_name (absname);
1968 }
1969#else
1970 /* Remove final slash, if any (unless this is the root dir).
1971 stat behaves differently depending! */
1972 if (XSTRING (absname)->size > 1
1973 && IS_DIRECTORY_SEP (XSTRING (absname)->data[XSTRING (absname)->size - 1])
1974 && !IS_DEVICE_SEP (XSTRING (absname)->data[XSTRING (absname)->size-2]))
1975 /* We cannot take shortcuts; they might be wrong for magic file names. */
1976 absname = Fdirectory_file_name (absname);
1977#endif
1978 return absname;
1979}
1980\f
1981/* Signal an error if the file ABSNAME already exists.
1982 If INTERACTIVE is nonzero, ask the user whether to proceed,
1983 and bypass the error if the user says to go ahead.
1984 QUERYSTRING is a name for the action that is being considered
1985 to alter the file.
1986 *STATPTR is used to store the stat information if the file exists.
1987 If the file does not exist, STATPTR->st_mode is set to 0. */
1988
1989void
1990barf_or_query_if_file_exists (absname, querystring, interactive, statptr)
1991 Lisp_Object absname;
1992 unsigned char *querystring;
1993 int interactive;
1994 struct stat *statptr;
1995{
1996 register Lisp_Object tem;
1997 struct stat statbuf;
1998 struct gcpro gcpro1;
1999
2000 /* stat is a good way to tell whether the file exists,
2001 regardless of what access permissions it has. */
2002 if (stat (XSTRING (absname)->data, &statbuf) >= 0)
2003 {
2004 if (! interactive)
2005 Fsignal (Qfile_already_exists,
2006 Fcons (build_string ("File already exists"),
2007 Fcons (absname, Qnil)));
2008 GCPRO1 (absname);
2009 tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
2010 XSTRING (absname)->data, querystring));
2011 UNGCPRO;
2012 if (NILP (tem))
2013 Fsignal (Qfile_already_exists,
2014 Fcons (build_string ("File already exists"),
2015 Fcons (absname, Qnil)));
2016 if (statptr)
2017 *statptr = statbuf;
2018 }
2019 else
2020 {
2021 if (statptr)
2022 statptr->st_mode = 0;
2023 }
2024 return;
2025}
2026
2027DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4,
2028 "fCopy file: \nFCopy %s to file: \np\nP",
2029 "Copy FILE to NEWNAME. Both args must be strings.\n\
2030Signals a `file-already-exists' error if file NEWNAME already exists,\n\
2031unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\
2032A number as third arg means request confirmation if NEWNAME already exists.\n\
2033This is what happens in interactive use with M-x.\n\
2034Fourth arg KEEP-TIME non-nil means give the new file the same\n\
2035last-modified time as the old one. (This works on only some systems.)\n\
2036A prefix arg makes KEEP-TIME non-nil.")
2037 (file, newname, ok_if_already_exists, keep_date)
2038 Lisp_Object file, newname, ok_if_already_exists, keep_date;
2039{
2040 int ifd, ofd, n;
2041 char buf[16 * 1024];
2042 struct stat st, out_st;
2043 Lisp_Object handler;
2044 struct gcpro gcpro1, gcpro2;
2045 int count = specpdl_ptr - specpdl;
2046 int input_file_statable_p;
2047
2048 GCPRO2 (file, newname);
2049 CHECK_STRING (file, 0);
2050 CHECK_STRING (newname, 1);
2051 file = Fexpand_file_name (file, Qnil);
2052 newname = Fexpand_file_name (newname, Qnil);
2053
2054 /* If the input file name has special constructs in it,
2055 call the corresponding file handler. */
2056 handler = Ffind_file_name_handler (file, Qcopy_file);
2057 /* Likewise for output file name. */
2058 if (NILP (handler))
2059 handler = Ffind_file_name_handler (newname, Qcopy_file);
2060 if (!NILP (handler))
2061 RETURN_UNGCPRO (call5 (handler, Qcopy_file, file, newname,
2062 ok_if_already_exists, keep_date));
2063
2064 if (NILP (ok_if_already_exists)
2065 || INTEGERP (ok_if_already_exists))
2066 barf_or_query_if_file_exists (newname, "copy to it",
2067 INTEGERP (ok_if_already_exists), &out_st);
2068 else if (stat (XSTRING (newname)->data, &out_st) < 0)
2069 out_st.st_mode = 0;
2070
2071 ifd = open (XSTRING (file)->data, O_RDONLY);
2072 if (ifd < 0)
2073 report_file_error ("Opening input file", Fcons (file, Qnil));
2074
2075 record_unwind_protect (close_file_unwind, make_number (ifd));
2076
2077 /* We can only copy regular files and symbolic links. Other files are not
2078 copyable by us. */
2079 input_file_statable_p = (fstat (ifd, &st) >= 0);
2080
2081#ifndef MSDOS
2082 if (out_st.st_mode != 0
2083 && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
2084 {
2085 errno = 0;
2086 report_file_error ("Input and output files are the same",
2087 Fcons (file, Fcons (newname, Qnil)));
2088 }
2089#endif
2090
2091#if defined (S_ISREG) && defined (S_ISLNK)
2092 if (input_file_statable_p)
2093 {
2094 if (!(S_ISREG (st.st_mode)) && !(S_ISLNK (st.st_mode)))
2095 {
2096#if defined (EISDIR)
2097 /* Get a better looking error message. */
2098 errno = EISDIR;
2099#endif /* EISDIR */
2100 report_file_error ("Non-regular file", Fcons (file, Qnil));
2101 }
2102 }
2103#endif /* S_ISREG && S_ISLNK */
2104
2105#ifdef VMS
2106 /* Create the copy file with the same record format as the input file */
2107 ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
2108#else
2109#ifdef MSDOS
2110 /* System's default file type was set to binary by _fmode in emacs.c. */
2111 ofd = creat (XSTRING (newname)->data, S_IREAD | S_IWRITE);
2112#else /* not MSDOS */
2113 ofd = creat (XSTRING (newname)->data, 0666);
2114#endif /* not MSDOS */
2115#endif /* VMS */
2116 if (ofd < 0)
2117 report_file_error ("Opening output file", Fcons (newname, Qnil));
2118
2119 record_unwind_protect (close_file_unwind, make_number (ofd));
2120
2121 immediate_quit = 1;
2122 QUIT;
2123 while ((n = read (ifd, buf, sizeof buf)) > 0)
2124 if (write (ofd, buf, n) != n)
2125 report_file_error ("I/O error", Fcons (newname, Qnil));
2126 immediate_quit = 0;
2127
2128 /* Closing the output clobbers the file times on some systems. */
2129 if (close (ofd) < 0)
2130 report_file_error ("I/O error", Fcons (newname, Qnil));
2131
2132 if (input_file_statable_p)
2133 {
2134 if (!NILP (keep_date))
2135 {
2136 EMACS_TIME atime, mtime;
2137 EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
2138 EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
2139 if (set_file_times (XSTRING (newname)->data, atime, mtime))
2140 report_file_error ("I/O error", Fcons (newname, Qnil));
2141 }
2142#ifndef MSDOS
2143 chmod (XSTRING (newname)->data, st.st_mode & 07777);
2144#else /* MSDOS */
2145#if defined (__DJGPP__) && __DJGPP__ > 1
2146 /* In DJGPP v2.0 and later, fstat usually returns true file mode bits,
2147 and if it can't, it tells so. Otherwise, under MSDOS we usually
2148 get only the READ bit, which will make the copied file read-only,
2149 so it's better not to chmod at all. */
2150 if ((_djstat_flags & _STFAIL_WRITEBIT) == 0)
2151 chmod (XSTRING (newname)->data, st.st_mode & 07777);
2152#endif /* DJGPP version 2 or newer */
2153#endif /* MSDOS */
2154 }
2155
2156 close (ifd);
2157
2158 /* Discard the unwind protects. */
2159 specpdl_ptr = specpdl + count;
2160
2161 UNGCPRO;
2162 return Qnil;
2163}
2164\f
2165DEFUN ("make-directory-internal", Fmake_directory_internal,
2166 Smake_directory_internal, 1, 1, 0,
2167 "Create a new directory named DIRECTORY.")
2168 (directory)
2169 Lisp_Object directory;
2170{
2171 unsigned char *dir;
2172 Lisp_Object handler;
2173
2174 CHECK_STRING (directory, 0);
2175 directory = Fexpand_file_name (directory, Qnil);
2176
2177 handler = Ffind_file_name_handler (directory, Qmake_directory_internal);
2178 if (!NILP (handler))
2179 return call2 (handler, Qmake_directory_internal, directory);
2180
2181 dir = XSTRING (directory)->data;
2182
2183#ifdef WINDOWSNT
2184 if (mkdir (dir) != 0)
2185#else
2186 if (mkdir (dir, 0777) != 0)
2187#endif
2188 report_file_error ("Creating directory", Flist (1, &directory));
2189
2190 return Qnil;
2191}
2192
2193DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
2194 "Delete the directory named DIRECTORY.")
2195 (directory)
2196 Lisp_Object directory;
2197{
2198 unsigned char *dir;
2199 Lisp_Object handler;
2200
2201 CHECK_STRING (directory, 0);
2202 directory = Fdirectory_file_name (Fexpand_file_name (directory, Qnil));
2203 dir = XSTRING (directory)->data;
2204
2205 handler = Ffind_file_name_handler (directory, Qdelete_directory);
2206 if (!NILP (handler))
2207 return call2 (handler, Qdelete_directory, directory);
2208
2209 if (rmdir (dir) != 0)
2210 report_file_error ("Removing directory", Flist (1, &directory));
2211
2212 return Qnil;
2213}
2214
2215DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
2216 "Delete file named FILENAME.\n\
2217If file has multiple names, it continues to exist with the other names.")
2218 (filename)
2219 Lisp_Object filename;
2220{
2221 Lisp_Object handler;
2222 CHECK_STRING (filename, 0);
2223 filename = Fexpand_file_name (filename, Qnil);
2224
2225 handler = Ffind_file_name_handler (filename, Qdelete_file);
2226 if (!NILP (handler))
2227 return call2 (handler, Qdelete_file, filename);
2228
2229 if (0 > unlink (XSTRING (filename)->data))
2230 report_file_error ("Removing old name", Flist (1, &filename));
2231 return Qnil;
2232}
2233
2234static Lisp_Object
2235internal_delete_file_1 (ignore)
2236 Lisp_Object ignore;
2237{
2238 return Qt;
2239}
2240
2241/* Delete file FILENAME, returning 1 if successful and 0 if failed. */
2242
2243int
2244internal_delete_file (filename)
2245 Lisp_Object filename;
2246{
2247 return NILP (internal_condition_case_1 (Fdelete_file, filename,
2248 Qt, internal_delete_file_1));
2249}
2250\f
2251DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
2252 "fRename file: \nFRename %s to file: \np",
2253 "Rename FILE as NEWNAME. Both args strings.\n\
2254If file has names other than FILE, it continues to have those names.\n\
2255Signals a `file-already-exists' error if a file NEWNAME already exists\n\
2256unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
2257A number as third arg means request confirmation if NEWNAME already exists.\n\
2258This is what happens in interactive use with M-x.")
2259 (file, newname, ok_if_already_exists)
2260 Lisp_Object file, newname, ok_if_already_exists;
2261{
2262#ifdef NO_ARG_ARRAY
2263 Lisp_Object args[2];
2264#endif
2265 Lisp_Object handler;
2266 struct gcpro gcpro1, gcpro2;
2267
2268 GCPRO2 (file, newname);
2269 CHECK_STRING (file, 0);
2270 CHECK_STRING (newname, 1);
2271 file = Fexpand_file_name (file, Qnil);
2272 newname = Fexpand_file_name (newname, Qnil);
2273
2274 /* If the file name has special constructs in it,
2275 call the corresponding file handler. */
2276 handler = Ffind_file_name_handler (file, Qrename_file);
2277 if (NILP (handler))
2278 handler = Ffind_file_name_handler (newname, Qrename_file);
2279 if (!NILP (handler))
2280 RETURN_UNGCPRO (call4 (handler, Qrename_file,
2281 file, newname, ok_if_already_exists));
2282
2283 if (NILP (ok_if_already_exists)
2284 || INTEGERP (ok_if_already_exists))
2285 barf_or_query_if_file_exists (newname, "rename to it",
2286 INTEGERP (ok_if_already_exists), 0);
2287#ifndef BSD4_1
2288 if (0 > rename (XSTRING (file)->data, XSTRING (newname)->data))
2289#else
2290 if (0 > link (XSTRING (file)->data, XSTRING (newname)->data)
2291 || 0 > unlink (XSTRING (file)->data))
2292#endif
2293 {
2294 if (errno == EXDEV)
2295 {
2296 Fcopy_file (file, newname,
2297 /* We have already prompted if it was an integer,
2298 so don't have copy-file prompt again. */
2299 NILP (ok_if_already_exists) ? Qnil : Qt, Qt);
2300 Fdelete_file (file);
2301 }
2302 else
2303#ifdef NO_ARG_ARRAY
2304 {
2305 args[0] = file;
2306 args[1] = newname;
2307 report_file_error ("Renaming", Flist (2, args));
2308 }
2309#else
2310 report_file_error ("Renaming", Flist (2, &file));
2311#endif
2312 }
2313 UNGCPRO;
2314 return Qnil;
2315}
2316
2317DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3,
2318 "fAdd name to file: \nFName to add to %s: \np",
2319 "Give FILE additional name NEWNAME. Both args strings.\n\
2320Signals a `file-already-exists' error if a file NEWNAME already exists\n\
2321unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
2322A number as third arg means request confirmation if NEWNAME already exists.\n\
2323This is what happens in interactive use with M-x.")
2324 (file, newname, ok_if_already_exists)
2325 Lisp_Object file, newname, ok_if_already_exists;
2326{
2327#ifdef NO_ARG_ARRAY
2328 Lisp_Object args[2];
2329#endif
2330 Lisp_Object handler;
2331 struct gcpro gcpro1, gcpro2;
2332
2333 GCPRO2 (file, newname);
2334 CHECK_STRING (file, 0);
2335 CHECK_STRING (newname, 1);
2336 file = Fexpand_file_name (file, Qnil);
2337 newname = Fexpand_file_name (newname, Qnil);
2338
2339 /* If the file name has special constructs in it,
2340 call the corresponding file handler. */
2341 handler = Ffind_file_name_handler (file, Qadd_name_to_file);
2342 if (!NILP (handler))
2343 RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, file,
2344 newname, ok_if_already_exists));
2345
2346 /* If the new name has special constructs in it,
2347 call the corresponding file handler. */
2348 handler = Ffind_file_name_handler (newname, Qadd_name_to_file);
2349 if (!NILP (handler))
2350 RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, file,
2351 newname, ok_if_already_exists));
2352
2353 if (NILP (ok_if_already_exists)
2354 || INTEGERP (ok_if_already_exists))
2355 barf_or_query_if_file_exists (newname, "make it a new name",
2356 INTEGERP (ok_if_already_exists), 0);
2357#ifdef WINDOWSNT
2358 /* Windows does not support this operation. */
2359 report_file_error ("Adding new name", Flist (2, &file));
2360#else /* not WINDOWSNT */
2361
2362 unlink (XSTRING (newname)->data);
2363 if (0 > link (XSTRING (file)->data, XSTRING (newname)->data))
2364 {
2365#ifdef NO_ARG_ARRAY
2366 args[0] = file;
2367 args[1] = newname;
2368 report_file_error ("Adding new name", Flist (2, args));
2369#else
2370 report_file_error ("Adding new name", Flist (2, &file));
2371#endif
2372 }
2373#endif /* not WINDOWSNT */
2374
2375 UNGCPRO;
2376 return Qnil;
2377}
2378
2379#ifdef S_IFLNK
2380DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
2381 "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",
2382 "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\
2383Signals a `file-already-exists' error if a file LINKNAME already exists\n\
2384unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
2385A number as third arg means request confirmation if LINKNAME already exists.\n\
2386This happens for interactive use with M-x.")
2387 (filename, linkname, ok_if_already_exists)
2388 Lisp_Object filename, linkname, ok_if_already_exists;
2389{
2390#ifdef NO_ARG_ARRAY
2391 Lisp_Object args[2];
2392#endif
2393 Lisp_Object handler;
2394 struct gcpro gcpro1, gcpro2;
2395
2396 GCPRO2 (filename, linkname);
2397 CHECK_STRING (filename, 0);
2398 CHECK_STRING (linkname, 1);
2399 /* If the link target has a ~, we must expand it to get
2400 a truly valid file name. Otherwise, do not expand;
2401 we want to permit links to relative file names. */
2402 if (XSTRING (filename)->data[0] == '~')
2403 filename = Fexpand_file_name (filename, Qnil);
2404 linkname = Fexpand_file_name (linkname, Qnil);
2405
2406 /* If the file name has special constructs in it,
2407 call the corresponding file handler. */
2408 handler = Ffind_file_name_handler (filename, Qmake_symbolic_link);
2409 if (!NILP (handler))
2410 RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
2411 linkname, ok_if_already_exists));
2412
2413 /* If the new link name has special constructs in it,
2414 call the corresponding file handler. */
2415 handler = Ffind_file_name_handler (linkname, Qmake_symbolic_link);
2416 if (!NILP (handler))
2417 RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
2418 linkname, ok_if_already_exists));
2419
2420 if (NILP (ok_if_already_exists)
2421 || INTEGERP (ok_if_already_exists))
2422 barf_or_query_if_file_exists (linkname, "make it a link",
2423 INTEGERP (ok_if_already_exists), 0);
2424 if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
2425 {
2426 /* If we didn't complain already, silently delete existing file. */
2427 if (errno == EEXIST)
2428 {
2429 unlink (XSTRING (linkname)->data);
2430 if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
2431 {
2432 UNGCPRO;
2433 return Qnil;
2434 }
2435 }
2436
2437#ifdef NO_ARG_ARRAY
2438 args[0] = filename;
2439 args[1] = linkname;
2440 report_file_error ("Making symbolic link", Flist (2, args));
2441#else
2442 report_file_error ("Making symbolic link", Flist (2, &filename));
2443#endif
2444 }
2445 UNGCPRO;
2446 return Qnil;
2447}
2448#endif /* S_IFLNK */
2449
2450#ifdef VMS
2451
2452DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
2453 2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
2454 "Define the job-wide logical name NAME to have the value STRING.\n\
2455If STRING is nil or a null string, the logical name NAME is deleted.")
2456 (name, string)
2457 Lisp_Object name;
2458 Lisp_Object string;
2459{
2460 CHECK_STRING (name, 0);
2461 if (NILP (string))
2462 delete_logical_name (XSTRING (name)->data);
2463 else
2464 {
2465 CHECK_STRING (string, 1);
2466
2467 if (XSTRING (string)->size == 0)
2468 delete_logical_name (XSTRING (name)->data);
2469 else
2470 define_logical_name (XSTRING (name)->data, XSTRING (string)->data);
2471 }
2472
2473 return string;
2474}
2475#endif /* VMS */
2476
2477#ifdef HPUX_NET
2478
2479DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
2480 "Open a network connection to PATH using LOGIN as the login string.")
2481 (path, login)
2482 Lisp_Object path, login;
2483{
2484 int netresult;
2485
2486 CHECK_STRING (path, 0);
2487 CHECK_STRING (login, 0);
2488
2489 netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
2490
2491 if (netresult == -1)
2492 return Qnil;
2493 else
2494 return Qt;
2495}
2496#endif /* HPUX_NET */
2497\f
2498DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
2499 1, 1, 0,
2500 "Return t if file FILENAME specifies an absolute file name.\n\
2501On Unix, this is a name starting with a `/' or a `~'.")
2502 (filename)
2503 Lisp_Object filename;
2504{
2505 unsigned char *ptr;
2506
2507 CHECK_STRING (filename, 0);
2508 ptr = XSTRING (filename)->data;
2509 if (IS_DIRECTORY_SEP (*ptr) || *ptr == '~'
2510#ifdef VMS
2511/* ??? This criterion is probably wrong for '<'. */
2512 || index (ptr, ':') || index (ptr, '<')
2513 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
2514 && ptr[1] != '.')
2515#endif /* VMS */
2516#ifdef DOS_NT
2517 || (IS_DRIVE (*ptr) && ptr[1] == ':' && IS_DIRECTORY_SEP (ptr[2]))
2518#endif
2519 )
2520 return Qt;
2521 else
2522 return Qnil;
2523}
2524\f
2525/* Return nonzero if file FILENAME exists and can be executed. */
2526
2527static int
2528check_executable (filename)
2529 char *filename;
2530{
2531#ifdef DOS_NT
2532 int len = strlen (filename);
2533 char *suffix;
2534 struct stat st;
2535 if (stat (filename, &st) < 0)
2536 return 0;
2537#ifdef WINDOWSNT
2538 return ((st.st_mode & S_IEXEC) != 0);
2539#else
2540 return (S_ISREG (st.st_mode)
2541 && len >= 5
2542 && (stricmp ((suffix = filename + len-4), ".com") == 0
2543 || stricmp (suffix, ".exe") == 0
2544 || stricmp (suffix, ".bat") == 0)
2545 || (st.st_mode & S_IFMT) == S_IFDIR);
2546#endif /* not WINDOWSNT */
2547#else /* not DOS_NT */
2548#ifdef HAVE_EACCESS
2549 return (eaccess (filename, 1) >= 0);
2550#else
2551 /* Access isn't quite right because it uses the real uid
2552 and we really want to test with the effective uid.
2553 But Unix doesn't give us a right way to do it. */
2554 return (access (filename, 1) >= 0);
2555#endif
2556#endif /* not DOS_NT */
2557}
2558
2559/* Return nonzero if file FILENAME exists and can be written. */
2560
2561static int
2562check_writable (filename)
2563 char *filename;
2564{
2565#ifdef MSDOS
2566 struct stat st;
2567 if (stat (filename, &st) < 0)
2568 return 0;
2569 return (st.st_mode & S_IWRITE || (st.st_mode & S_IFMT) == S_IFDIR);
2570#else /* not MSDOS */
2571#ifdef HAVE_EACCESS
2572 return (eaccess (filename, 2) >= 0);
2573#else
2574 /* Access isn't quite right because it uses the real uid
2575 and we really want to test with the effective uid.
2576 But Unix doesn't give us a right way to do it.
2577 Opening with O_WRONLY could work for an ordinary file,
2578 but would lose for directories. */
2579 return (access (filename, 2) >= 0);
2580#endif
2581#endif /* not MSDOS */
2582}
2583
2584DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
2585 "Return t if file FILENAME exists. (This does not mean you can read it.)\n\
2586See also `file-readable-p' and `file-attributes'.")
2587 (filename)
2588 Lisp_Object filename;
2589{
2590 Lisp_Object absname;
2591 Lisp_Object handler;
2592 struct stat statbuf;
2593
2594 CHECK_STRING (filename, 0);
2595 absname = Fexpand_file_name (filename, Qnil);
2596
2597 /* If the file name has special constructs in it,
2598 call the corresponding file handler. */
2599 handler = Ffind_file_name_handler (absname, Qfile_exists_p);
2600 if (!NILP (handler))
2601 return call2 (handler, Qfile_exists_p, absname);
2602
2603 return (stat (XSTRING (absname)->data, &statbuf) >= 0) ? Qt : Qnil;
2604}
2605
2606DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
2607 "Return t if FILENAME can be executed by you.\n\
2608For a directory, this means you can access files in that directory.")
2609 (filename)
2610 Lisp_Object filename;
2611
2612{
2613 Lisp_Object absname;
2614 Lisp_Object handler;
2615
2616 CHECK_STRING (filename, 0);
2617 absname = Fexpand_file_name (filename, Qnil);
2618
2619 /* If the file name has special constructs in it,
2620 call the corresponding file handler. */
2621 handler = Ffind_file_name_handler (absname, Qfile_executable_p);
2622 if (!NILP (handler))
2623 return call2 (handler, Qfile_executable_p, absname);
2624
2625 return (check_executable (XSTRING (absname)->data) ? Qt : Qnil);
2626}
2627
2628DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
2629 "Return t if file FILENAME exists and you can read it.\n\
2630See also `file-exists-p' and `file-attributes'.")
2631 (filename)
2632 Lisp_Object filename;
2633{
2634 Lisp_Object absname;
2635 Lisp_Object handler;
2636 int desc;
2637
2638 CHECK_STRING (filename, 0);
2639 absname = Fexpand_file_name (filename, Qnil);
2640
2641 /* If the file name has special constructs in it,
2642 call the corresponding file handler. */
2643 handler = Ffind_file_name_handler (absname, Qfile_readable_p);
2644 if (!NILP (handler))
2645 return call2 (handler, Qfile_readable_p, absname);
2646
2647#ifdef DOS_NT
2648 /* Under MS-DOS and Windows, open does not work for directories. */
2649 if (access (XSTRING (absname)->data, 0) == 0)
2650 return Qt;
2651 return Qnil;
2652#else /* not DOS_NT */
2653 desc = open (XSTRING (absname)->data, O_RDONLY);
2654 if (desc < 0)
2655 return Qnil;
2656 close (desc);
2657 return Qt;
2658#endif /* not DOS_NT */
2659}
2660
2661/* Having this before file-symlink-p mysteriously caused it to be forgotten
2662 on the RT/PC. */
2663DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
2664 "Return t if file FILENAME can be written or created by you.")
2665 (filename)
2666 Lisp_Object filename;
2667{
2668 Lisp_Object absname, dir;
2669 Lisp_Object handler;
2670 struct stat statbuf;
2671
2672 CHECK_STRING (filename, 0);
2673 absname = Fexpand_file_name (filename, Qnil);
2674
2675 /* If the file name has special constructs in it,
2676 call the corresponding file handler. */
2677 handler = Ffind_file_name_handler (absname, Qfile_writable_p);
2678 if (!NILP (handler))
2679 return call2 (handler, Qfile_writable_p, absname);
2680
2681 if (stat (XSTRING (absname)->data, &statbuf) >= 0)
2682 return (check_writable (XSTRING (absname)->data)
2683 ? Qt : Qnil);
2684 dir = Ffile_name_directory (absname);
2685#ifdef VMS
2686 if (!NILP (dir))
2687 dir = Fdirectory_file_name (dir);
2688#endif /* VMS */
2689#ifdef MSDOS
2690 if (!NILP (dir))
2691 dir = Fdirectory_file_name (dir);
2692#endif /* MSDOS */
2693 return (check_writable (!NILP (dir) ? (char *) XSTRING (dir)->data : "")
2694 ? Qt : Qnil);
2695}
2696\f
2697DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
2698 "Return non-nil if file FILENAME is the name of a symbolic link.\n\
2699The value is the name of the file to which it is linked.\n\
2700Otherwise returns nil.")
2701 (filename)
2702 Lisp_Object filename;
2703{
2704#ifdef S_IFLNK
2705 char *buf;
2706 int bufsize;
2707 int valsize;
2708 Lisp_Object val;
2709 Lisp_Object handler;
2710
2711 CHECK_STRING (filename, 0);
2712 filename = Fexpand_file_name (filename, Qnil);
2713
2714 /* If the file name has special constructs in it,
2715 call the corresponding file handler. */
2716 handler = Ffind_file_name_handler (filename, Qfile_symlink_p);
2717 if (!NILP (handler))
2718 return call2 (handler, Qfile_symlink_p, filename);
2719
2720 bufsize = 100;
2721 while (1)
2722 {
2723 buf = (char *) xmalloc (bufsize);
2724 bzero (buf, bufsize);
2725 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
2726 if (valsize < bufsize) break;
2727 /* Buffer was not long enough */
2728 xfree (buf);
2729 bufsize *= 2;
2730 }
2731 if (valsize == -1)
2732 {
2733 xfree (buf);
2734 return Qnil;
2735 }
2736 val = make_string (buf, valsize);
2737 xfree (buf);
2738 return val;
2739#else /* not S_IFLNK */
2740 return Qnil;
2741#endif /* not S_IFLNK */
2742}
2743
2744DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
2745 "Return t if file FILENAME is the name of a directory as a file.\n\
2746A directory name spec may be given instead; then the value is t\n\
2747if the directory so specified exists and really is a directory.")
2748 (filename)
2749 Lisp_Object filename;
2750{
2751 register Lisp_Object absname;
2752 struct stat st;
2753 Lisp_Object handler;
2754
2755 absname = expand_and_dir_to_file (filename, current_buffer->directory);
2756
2757 /* If the file name has special constructs in it,
2758 call the corresponding file handler. */
2759 handler = Ffind_file_name_handler (absname, Qfile_directory_p);
2760 if (!NILP (handler))
2761 return call2 (handler, Qfile_directory_p, absname);
2762
2763 if (stat (XSTRING (absname)->data, &st) < 0)
2764 return Qnil;
2765 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2766}
2767
2768DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
2769 "Return t if file FILENAME is the name of a directory as a file,\n\
2770and files in that directory can be opened by you. In order to use a\n\
2771directory as a buffer's current directory, this predicate must return true.\n\
2772A directory name spec may be given instead; then the value is t\n\
2773if the directory so specified exists and really is a readable and\n\
2774searchable directory.")
2775 (filename)
2776 Lisp_Object filename;
2777{
2778 Lisp_Object handler;
2779 int tem;
2780 struct gcpro gcpro1;
2781
2782 /* If the file name has special constructs in it,
2783 call the corresponding file handler. */
2784 handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p);
2785 if (!NILP (handler))
2786 return call2 (handler, Qfile_accessible_directory_p, filename);
2787
2788 /* It's an unlikely combination, but yes we really do need to gcpro:
2789 Suppose that file-accessible-directory-p has no handler, but
2790 file-directory-p does have a handler; this handler causes a GC which
2791 relocates the string in `filename'; and finally file-directory-p
2792 returns non-nil. Then we would end up passing a garbaged string
2793 to file-executable-p. */
2794 GCPRO1 (filename);
2795 tem = (NILP (Ffile_directory_p (filename))
2796 || NILP (Ffile_executable_p (filename)));
2797 UNGCPRO;
2798 return tem ? Qnil : Qt;
2799}
2800
2801DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0,
2802 "Return t if file FILENAME is the name of a regular file.\n\
2803This is the sort of file that holds an ordinary stream of data bytes.")
2804 (filename)
2805 Lisp_Object filename;
2806{
2807 register Lisp_Object absname;
2808 struct stat st;
2809 Lisp_Object handler;
2810
2811 absname = expand_and_dir_to_file (filename, current_buffer->directory);
2812
2813 /* If the file name has special constructs in it,
2814 call the corresponding file handler. */
2815 handler = Ffind_file_name_handler (absname, Qfile_regular_p);
2816 if (!NILP (handler))
2817 return call2 (handler, Qfile_regular_p, absname);
2818
2819 if (stat (XSTRING (absname)->data, &st) < 0)
2820 return Qnil;
2821 return (st.st_mode & S_IFMT) == S_IFREG ? Qt : Qnil;
2822}
2823\f
2824DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2825 "Return mode bits of file named FILENAME, as an integer.")
2826 (filename)
2827 Lisp_Object filename;
2828{
2829 Lisp_Object absname;
2830 struct stat st;
2831 Lisp_Object handler;
2832
2833 absname = expand_and_dir_to_file (filename, current_buffer->directory);
2834
2835 /* If the file name has special constructs in it,
2836 call the corresponding file handler. */
2837 handler = Ffind_file_name_handler (absname, Qfile_modes);
2838 if (!NILP (handler))
2839 return call2 (handler, Qfile_modes, absname);
2840
2841 if (stat (XSTRING (absname)->data, &st) < 0)
2842 return Qnil;
2843#ifdef MSDOS
2844 if (check_executable (XSTRING (absname)->data))
2845 st.st_mode |= S_IEXEC;
2846#endif /* MSDOS */
2847
2848 return make_number (st.st_mode & 07777);
2849}
2850
2851DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2852 "Set mode bits of file named FILENAME to MODE (an integer).\n\
2853Only the 12 low bits of MODE are used.")
2854 (filename, mode)
2855 Lisp_Object filename, mode;
2856{
2857 Lisp_Object absname;
2858 Lisp_Object handler;
2859
2860 absname = Fexpand_file_name (filename, current_buffer->directory);
2861 CHECK_NUMBER (mode, 1);
2862
2863 /* If the file name has special constructs in it,
2864 call the corresponding file handler. */
2865 handler = Ffind_file_name_handler (absname, Qset_file_modes);
2866 if (!NILP (handler))
2867 return call3 (handler, Qset_file_modes, absname, mode);
2868
2869 if (chmod (XSTRING (absname)->data, XINT (mode)) < 0)
2870 report_file_error ("Doing chmod", Fcons (absname, Qnil));
2871
2872 return Qnil;
2873}
2874
2875DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
2876 "Set the file permission bits for newly created files.\n\
2877The argument MODE should be an integer; only the low 9 bits are used.\n\
2878This setting is inherited by subprocesses.")
2879 (mode)
2880 Lisp_Object mode;
2881{
2882 CHECK_NUMBER (mode, 0);
2883
2884 umask ((~ XINT (mode)) & 0777);
2885
2886 return Qnil;
2887}
2888
2889DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
2890 "Return the default file protection for created files.\n\
2891The value is an integer.")
2892 ()
2893{
2894 int realmask;
2895 Lisp_Object value;
2896
2897 realmask = umask (0);
2898 umask (realmask);
2899
2900 XSETINT (value, (~ realmask) & 0777);
2901 return value;
2902}
2903\f
2904#ifdef unix
2905
2906DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2907 "Tell Unix to finish all pending disk updates.")
2908 ()
2909{
2910 sync ();
2911 return Qnil;
2912}
2913
2914#endif /* unix */
2915
2916DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2917 "Return t if file FILE1 is newer than file FILE2.\n\
2918If FILE1 does not exist, the answer is nil;\n\
2919otherwise, if FILE2 does not exist, the answer is t.")
2920 (file1, file2)
2921 Lisp_Object file1, file2;
2922{
2923 Lisp_Object absname1, absname2;
2924 struct stat st;
2925 int mtime1;
2926 Lisp_Object handler;
2927 struct gcpro gcpro1, gcpro2;
2928
2929 CHECK_STRING (file1, 0);
2930 CHECK_STRING (file2, 0);
2931
2932 absname1 = Qnil;
2933 GCPRO2 (absname1, file2);
2934 absname1 = expand_and_dir_to_file (file1, current_buffer->directory);
2935 absname2 = expand_and_dir_to_file (file2, current_buffer->directory);
2936 UNGCPRO;
2937
2938 /* If the file name has special constructs in it,
2939 call the corresponding file handler. */
2940 handler = Ffind_file_name_handler (absname1, Qfile_newer_than_file_p);
2941 if (NILP (handler))
2942 handler = Ffind_file_name_handler (absname2, Qfile_newer_than_file_p);
2943 if (!NILP (handler))
2944 return call3 (handler, Qfile_newer_than_file_p, absname1, absname2);
2945
2946 if (stat (XSTRING (absname1)->data, &st) < 0)
2947 return Qnil;
2948
2949 mtime1 = st.st_mtime;
2950
2951 if (stat (XSTRING (absname2)->data, &st) < 0)
2952 return Qt;
2953
2954 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2955}
2956\f
2957#ifdef DOS_NT
2958Lisp_Object Qfind_buffer_file_type;
2959#endif /* DOS_NT */
2960
2961DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
2962 1, 5, 0,
2963 "Insert contents of file FILENAME after point.\n\
2964Returns list of absolute file name and length of data inserted.\n\
2965If second argument VISIT is non-nil, the buffer's visited filename\n\
2966and last save file modtime are set, and it is marked unmodified.\n\
2967If visiting and the file does not exist, visiting is completed\n\
2968before the error is signaled.\n\n\
2969The optional third and fourth arguments BEG and END\n\
2970specify what portion of the file to insert.\n\
2971If VISIT is non-nil, BEG and END must be nil.\n\
2972If optional fifth argument REPLACE is non-nil,\n\
2973it means replace the current buffer contents (in the accessible portion)\n\
2974with the file contents. This is better than simply deleting and inserting\n\
2975the whole thing because (1) it preserves some marker positions\n\
2976and (2) it puts less data in the undo list.")
2977 (filename, visit, beg, end, replace)
2978 Lisp_Object filename, visit, beg, end, replace;
2979{
2980 struct stat st;
2981 register int fd;
2982 register int inserted = 0;
2983 register int how_much;
2984 int count = specpdl_ptr - specpdl;
2985 struct gcpro gcpro1, gcpro2, gcpro3;
2986 Lisp_Object handler, val, insval;
2987 Lisp_Object p;
2988 int total;
2989 int not_regular = 0;
2990
2991 if (current_buffer->base_buffer && ! NILP (visit))
2992 error ("Cannot do file visiting in an indirect buffer");
2993
2994 if (!NILP (current_buffer->read_only))
2995 Fbarf_if_buffer_read_only ();
2996
2997 val = Qnil;
2998 p = Qnil;
2999
3000 GCPRO3 (filename, val, p);
3001
3002 CHECK_STRING (filename, 0);
3003 filename = Fexpand_file_name (filename, Qnil);
3004
3005 /* If the file name has special constructs in it,
3006 call the corresponding file handler. */
3007 handler = Ffind_file_name_handler (filename, Qinsert_file_contents);
3008 if (!NILP (handler))
3009 {
3010 val = call6 (handler, Qinsert_file_contents, filename,
3011 visit, beg, end, replace);
3012 goto handled;
3013 }
3014
3015 fd = -1;
3016
3017#ifndef APOLLO
3018 if (stat (XSTRING (filename)->data, &st) < 0)
3019#else
3020 if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0
3021 || fstat (fd, &st) < 0)
3022#endif /* not APOLLO */
3023 {
3024 if (fd >= 0) close (fd);
3025 badopen:
3026 if (NILP (visit))
3027 report_file_error ("Opening input file", Fcons (filename, Qnil));
3028 st.st_mtime = -1;
3029 how_much = 0;
3030 goto notfound;
3031 }
3032
3033#ifdef S_IFREG
3034 /* This code will need to be changed in order to work on named
3035 pipes, and it's probably just not worth it. So we should at
3036 least signal an error. */
3037 if (!S_ISREG (st.st_mode))
3038 {
3039 if (NILP (visit))
3040 Fsignal (Qfile_error,
3041 Fcons (build_string ("not a regular file"),
3042 Fcons (filename, Qnil)));
3043
3044 not_regular = 1;
3045 goto notfound;
3046 }
3047#endif
3048
3049 if (fd < 0)
3050 if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0)
3051 goto badopen;
3052
3053 /* Replacement should preserve point as it preserves markers. */
3054 if (!NILP (replace))
3055 record_unwind_protect (restore_point_unwind, Fpoint_marker ());
3056
3057 record_unwind_protect (close_file_unwind, make_number (fd));
3058
3059 /* Supposedly happens on VMS. */
3060 if (st.st_size < 0)
3061 error ("File size is negative");
3062
3063 if (!NILP (beg) || !NILP (end))
3064 if (!NILP (visit))
3065 error ("Attempt to visit less than an entire file");
3066
3067 if (!NILP (beg))
3068 CHECK_NUMBER (beg, 0);
3069 else
3070 XSETFASTINT (beg, 0);
3071
3072 if (!NILP (end))
3073 CHECK_NUMBER (end, 0);
3074 else
3075 {
3076 XSETINT (end, st.st_size);
3077 if (XINT (end) != st.st_size)
3078 error ("maximum buffer size exceeded");
3079 }
3080
3081 /* If requested, replace the accessible part of the buffer
3082 with the file contents. Avoid replacing text at the
3083 beginning or end of the buffer that matches the file contents;
3084 that preserves markers pointing to the unchanged parts. */
3085#ifdef DOS_NT
3086 /* On MSDOS, replace mode doesn't really work, except for binary files,
3087 and it's not worth supporting just for them. */
3088 if (!NILP (replace))
3089 {
3090 replace = Qnil;
3091 XSETFASTINT (beg, 0);
3092 XSETFASTINT (end, st.st_size);
3093 del_range_1 (BEGV, ZV, 0);
3094 }
3095#else /* not DOS_NT */
3096 if (!NILP (replace))
3097 {
3098 unsigned char buffer[1 << 14];
3099 int same_at_start = BEGV;
3100 int same_at_end = ZV;
3101 int overlap;
3102
3103 immediate_quit = 1;
3104 QUIT;
3105 /* Count how many chars at the start of the file
3106 match the text at the beginning of the buffer. */
3107 while (1)
3108 {
3109 int nread, bufpos;
3110
3111 nread = read (fd, buffer, sizeof buffer);
3112 if (nread < 0)
3113 error ("IO error reading %s: %s",
3114 XSTRING (filename)->data, strerror (errno));
3115 else if (nread == 0)
3116 break;
3117 bufpos = 0;
3118 while (bufpos < nread && same_at_start < ZV
3119 && FETCH_CHAR (same_at_start) == buffer[bufpos])
3120 same_at_start++, bufpos++;
3121 /* If we found a discrepancy, stop the scan.
3122 Otherwise loop around and scan the next bufferful. */
3123 if (bufpos != nread)
3124 break;
3125 }
3126 immediate_quit = 0;
3127 /* If the file matches the buffer completely,
3128 there's no need to replace anything. */
3129 if (same_at_start - BEGV == st.st_size)
3130 {
3131 close (fd);
3132 specpdl_ptr--;
3133 /* Truncate the buffer to the size of the file. */
3134 del_range_1 (same_at_start, same_at_end, 0);
3135 goto handled;
3136 }
3137 immediate_quit = 1;
3138 QUIT;
3139 /* Count how many chars at the end of the file
3140 match the text at the end of the buffer. */
3141 while (1)
3142 {
3143 int total_read, nread, bufpos, curpos, trial;
3144
3145 /* At what file position are we now scanning? */
3146 curpos = st.st_size - (ZV - same_at_end);
3147 /* If the entire file matches the buffer tail, stop the scan. */
3148 if (curpos == 0)
3149 break;
3150 /* How much can we scan in the next step? */
3151 trial = min (curpos, sizeof buffer);
3152 if (lseek (fd, curpos - trial, 0) < 0)
3153 report_file_error ("Setting file position",
3154 Fcons (filename, Qnil));
3155
3156 total_read = 0;
3157 while (total_read < trial)
3158 {
3159 nread = read (fd, buffer + total_read, trial - total_read);
3160 if (nread <= 0)
3161 error ("IO error reading %s: %s",
3162 XSTRING (filename)->data, strerror (errno));
3163 total_read += nread;
3164 }
3165 /* Scan this bufferful from the end, comparing with
3166 the Emacs buffer. */
3167 bufpos = total_read;
3168 /* Compare with same_at_start to avoid counting some buffer text
3169 as matching both at the file's beginning and at the end. */
3170 while (bufpos > 0 && same_at_end > same_at_start
3171 && FETCH_CHAR (same_at_end - 1) == buffer[bufpos - 1])
3172 same_at_end--, bufpos--;
3173 /* If we found a discrepancy, stop the scan.
3174 Otherwise loop around and scan the preceding bufferful. */
3175 if (bufpos != 0)
3176 break;
3177 /* If display current starts at beginning of line,
3178 keep it that way. */
3179 if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
3180 XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
3181 }
3182 immediate_quit = 0;
3183
3184 /* Don't try to reuse the same piece of text twice. */
3185 overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV);
3186 if (overlap > 0)
3187 same_at_end += overlap;
3188
3189 /* Arrange to read only the nonmatching middle part of the file. */
3190 XSETFASTINT (beg, same_at_start - BEGV);
3191 XSETFASTINT (end, st.st_size - (ZV - same_at_end));
3192
3193 del_range_1 (same_at_start, same_at_end, 0);
3194 /* Insert from the file at the proper position. */
3195 SET_PT (same_at_start);
3196 }
3197#endif /* not DOS_NT */
3198
3199 total = XINT (end) - XINT (beg);
3200
3201 {
3202 register Lisp_Object temp;
3203
3204 /* Make sure point-max won't overflow after this insertion. */
3205 XSETINT (temp, total);
3206 if (total != XINT (temp))
3207 error ("maximum buffer size exceeded");
3208 }
3209
3210 if (NILP (visit) && total > 0)
3211 prepare_to_modify_buffer (point, point);
3212
3213 move_gap (point);
3214 if (GAP_SIZE < total)
3215 make_gap (total - GAP_SIZE);
3216
3217 if (XINT (beg) != 0 || !NILP (replace))
3218 {
3219 if (lseek (fd, XINT (beg), 0) < 0)
3220 report_file_error ("Setting file position", Fcons (filename, Qnil));
3221 }
3222
3223 how_much = 0;
3224 while (inserted < total)
3225 {
3226 /* try is reserved in some compilers (Microsoft C) */
3227 int trytry = min (total - inserted, 64 << 10);
3228 int this;
3229
3230 /* Allow quitting out of the actual I/O. */
3231 immediate_quit = 1;
3232 QUIT;
3233 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, trytry);
3234 immediate_quit = 0;
3235
3236 if (this <= 0)
3237 {
3238 how_much = this;
3239 break;
3240 }
3241
3242 GPT += this;
3243 GAP_SIZE -= this;
3244 ZV += this;
3245 Z += this;
3246 inserted += this;
3247 }
3248
3249#ifdef DOS_NT
3250 /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
3251 /* Determine file type from name and remove LFs from CR-LFs if the file
3252 is deemed to be a text file. */
3253 {
3254 current_buffer->buffer_file_type
3255 = call1 (Qfind_buffer_file_type, filename);
3256 if (NILP (current_buffer->buffer_file_type))
3257 {
3258 int reduced_size
3259 = inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
3260 ZV -= reduced_size;
3261 Z -= reduced_size;
3262 GPT -= reduced_size;
3263 GAP_SIZE += reduced_size;
3264 inserted -= reduced_size;
3265 }
3266 }
3267#endif /* DOS_NT */
3268
3269 if (inserted > 0)
3270 {
3271 record_insert (point, inserted);
3272
3273 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
3274 offset_intervals (current_buffer, point, inserted);
3275 MODIFF++;
3276 }
3277
3278 close (fd);
3279
3280 /* Discard the unwind protect for closing the file. */
3281 specpdl_ptr--;
3282
3283 if (how_much < 0)
3284 error ("IO error reading %s: %s",
3285 XSTRING (filename)->data, strerror (errno));
3286
3287 notfound:
3288 handled:
3289
3290 if (!NILP (visit))
3291 {
3292 if (!EQ (current_buffer->undo_list, Qt))
3293 current_buffer->undo_list = Qnil;
3294#ifdef APOLLO
3295 stat (XSTRING (filename)->data, &st);
3296#endif
3297
3298 if (NILP (handler))
3299 {
3300 current_buffer->modtime = st.st_mtime;
3301 current_buffer->filename = filename;
3302 }
3303
3304 SAVE_MODIFF = MODIFF;
3305 current_buffer->auto_save_modified = MODIFF;
3306 XSETFASTINT (current_buffer->save_length, Z - BEG);
3307#ifdef CLASH_DETECTION
3308 if (NILP (handler))
3309 {
3310 if (!NILP (current_buffer->file_truename))
3311 unlock_file (current_buffer->file_truename);
3312 unlock_file (filename);
3313 }
3314#endif /* CLASH_DETECTION */
3315 if (not_regular)
3316 Fsignal (Qfile_error,
3317 Fcons (build_string ("not a regular file"),
3318 Fcons (filename, Qnil)));
3319
3320 /* If visiting nonexistent file, return nil. */
3321 if (current_buffer->modtime == -1)
3322 report_file_error ("Opening input file", Fcons (filename, Qnil));
3323 }
3324
3325 /* Decode file format */
3326 if (inserted > 0)
3327 {
3328 insval = call3 (Qformat_decode,
3329 Qnil, make_number (inserted), visit);
3330 CHECK_NUMBER (insval, 0);
3331 inserted = XFASTINT (insval);
3332 }
3333
3334 if (inserted > 0 && NILP (visit) && total > 0)
3335 signal_after_change (point, 0, inserted);
3336
3337 if (inserted > 0)
3338 {
3339 p = Vafter_insert_file_functions;
3340 while (!NILP (p))
3341 {
3342 insval = call1 (Fcar (p), make_number (inserted));
3343 if (!NILP (insval))
3344 {
3345 CHECK_NUMBER (insval, 0);
3346 inserted = XFASTINT (insval);
3347 }
3348 QUIT;
3349 p = Fcdr (p);
3350 }
3351 }
3352
3353 if (NILP (val))
3354 val = Fcons (filename,
3355 Fcons (make_number (inserted),
3356 Qnil));
3357
3358 RETURN_UNGCPRO (unbind_to (count, val));
3359}
3360\f
3361static Lisp_Object build_annotations ();
3362
3363/* If build_annotations switched buffers, switch back to BUF.
3364 Kill the temporary buffer that was selected in the meantime. */
3365
3366static Lisp_Object
3367build_annotations_unwind (buf)
3368 Lisp_Object buf;
3369{
3370 Lisp_Object tembuf;
3371
3372 if (XBUFFER (buf) == current_buffer)
3373 return Qnil;
3374 tembuf = Fcurrent_buffer ();
3375 Fset_buffer (buf);
3376 Fkill_buffer (tembuf);
3377 return Qnil;
3378}
3379
3380DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 6,
3381 "r\nFWrite region to file: ",
3382 "Write current region into specified file.\n\
3383When called from a program, takes three arguments:\n\
3384START, END and FILENAME. START and END are buffer positions.\n\
3385Optional fourth argument APPEND if non-nil means\n\
3386 append to existing file contents (if any).\n\
3387Optional fifth argument VISIT if t means\n\
3388 set the last-save-file-modtime of buffer to this file's modtime\n\
3389 and mark buffer not modified.\n\
3390If VISIT is a string, it is a second file name;\n\
3391 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
3392 VISIT is also the file name to lock and unlock for clash detection.\n\
3393If VISIT is neither t nor nil nor a string,\n\
3394 that means do not print the \"Wrote file\" message.\n\
3395The optional sixth arg LOCKNAME, if non-nil, specifies the name to\n\
3396 use for locking and unlocking, overriding FILENAME and VISIT.\n\
3397Kludgy feature: if START is a string, then that string is written\n\
3398to the file, instead of any buffer contents, and END is ignored.")
3399 (start, end, filename, append, visit, lockname)
3400 Lisp_Object start, end, filename, append, visit, lockname;
3401{
3402 register int desc;
3403 int failure;
3404 int save_errno;
3405 unsigned char *fn;
3406 struct stat st;
3407 int tem;
3408 int count = specpdl_ptr - specpdl;
3409 int count1;
3410#ifdef VMS
3411 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
3412#endif /* VMS */
3413 Lisp_Object handler;
3414 Lisp_Object visit_file;
3415 Lisp_Object annotations;
3416 int visiting, quietly;
3417 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
3418 struct buffer *given_buffer;
3419#ifdef DOS_NT
3420 int buffer_file_type
3421 = NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
3422#endif /* DOS_NT */
3423
3424 if (current_buffer->base_buffer && ! NILP (visit))
3425 error ("Cannot do file visiting in an indirect buffer");
3426
3427 if (!NILP (start) && !STRINGP (start))
3428 validate_region (&start, &end);
3429
3430 GCPRO3 (filename, visit, lockname);
3431 filename = Fexpand_file_name (filename, Qnil);
3432 if (STRINGP (visit))
3433 visit_file = Fexpand_file_name (visit, Qnil);
3434 else
3435 visit_file = filename;
3436 UNGCPRO;
3437
3438 visiting = (EQ (visit, Qt) || STRINGP (visit));
3439 quietly = !NILP (visit);
3440
3441 annotations = Qnil;
3442
3443 if (NILP (lockname))
3444 lockname = visit_file;
3445
3446 GCPRO5 (start, filename, annotations, visit_file, lockname);
3447
3448 /* If the file name has special constructs in it,
3449 call the corresponding file handler. */
3450 handler = Ffind_file_name_handler (filename, Qwrite_region);
3451 /* If FILENAME has no handler, see if VISIT has one. */
3452 if (NILP (handler) && STRINGP (visit))
3453 handler = Ffind_file_name_handler (visit, Qwrite_region);
3454
3455 if (!NILP (handler))
3456 {
3457 Lisp_Object val;
3458 val = call6 (handler, Qwrite_region, start, end,
3459 filename, append, visit);
3460
3461 if (visiting)
3462 {
3463 SAVE_MODIFF = MODIFF;
3464 XSETFASTINT (current_buffer->save_length, Z - BEG);
3465 current_buffer->filename = visit_file;
3466 }
3467 UNGCPRO;
3468 return val;
3469 }
3470
3471 /* Special kludge to simplify auto-saving. */
3472 if (NILP (start))
3473 {
3474 XSETFASTINT (start, BEG);
3475 XSETFASTINT (end, Z);
3476 }
3477
3478 record_unwind_protect (build_annotations_unwind, Fcurrent_buffer ());
3479 count1 = specpdl_ptr - specpdl;
3480
3481 given_buffer = current_buffer;
3482 annotations = build_annotations (start, end);
3483 if (current_buffer != given_buffer)
3484 {
3485 start = BEGV;
3486 end = ZV;
3487 }
3488
3489#ifdef CLASH_DETECTION
3490 if (!auto_saving)
3491 lock_file (lockname);
3492#endif /* CLASH_DETECTION */
3493
3494 fn = XSTRING (filename)->data;
3495 desc = -1;
3496 if (!NILP (append))
3497#ifdef DOS_NT
3498 desc = open (fn, O_WRONLY | buffer_file_type);
3499#else /* not DOS_NT */
3500 desc = open (fn, O_WRONLY);
3501#endif /* not DOS_NT */
3502
3503 if (desc < 0)
3504#ifdef VMS
3505 if (auto_saving) /* Overwrite any previous version of autosave file */
3506 {
3507 vms_truncate (fn); /* if fn exists, truncate to zero length */
3508 desc = open (fn, O_RDWR);
3509 if (desc < 0)
3510 desc = creat_copy_attrs (STRINGP (current_buffer->filename)
3511 ? XSTRING (current_buffer->filename)->data : 0,
3512 fn);
3513 }
3514 else /* Write to temporary name and rename if no errors */
3515 {
3516 Lisp_Object temp_name;
3517 temp_name = Ffile_name_directory (filename);
3518
3519 if (!NILP (temp_name))
3520 {
3521 temp_name = Fmake_temp_name (concat2 (temp_name,
3522 build_string ("$$SAVE$$")));
3523 fname = XSTRING (filename)->data;
3524 fn = XSTRING (temp_name)->data;
3525 desc = creat_copy_attrs (fname, fn);
3526 if (desc < 0)
3527 {
3528 /* If we can't open the temporary file, try creating a new
3529 version of the original file. VMS "creat" creates a
3530 new version rather than truncating an existing file. */
3531 fn = fname;
3532 fname = 0;
3533 desc = creat (fn, 0666);
3534#if 0 /* This can clobber an existing file and fail to replace it,
3535 if the user runs out of space. */
3536 if (desc < 0)
3537 {
3538 /* We can't make a new version;
3539 try to truncate and rewrite existing version if any. */
3540 vms_truncate (fn);
3541 desc = open (fn, O_RDWR);
3542 }
3543#endif
3544 }
3545 }
3546 else
3547 desc = creat (fn, 0666);
3548 }
3549#else /* not VMS */
3550#ifdef DOS_NT
3551 desc = open (fn,
3552 O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type,
3553 S_IREAD | S_IWRITE);
3554#else /* not DOS_NT */
3555 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
3556#endif /* not DOS_NT */
3557#endif /* not VMS */
3558
3559 UNGCPRO;
3560
3561 if (desc < 0)
3562 {
3563#ifdef CLASH_DETECTION
3564 save_errno = errno;
3565 if (!auto_saving) unlock_file (lockname);
3566 errno = save_errno;
3567#endif /* CLASH_DETECTION */
3568 report_file_error ("Opening output file", Fcons (filename, Qnil));
3569 }
3570
3571 record_unwind_protect (close_file_unwind, make_number (desc));
3572
3573 if (!NILP (append))
3574 if (lseek (desc, 0, 2) < 0)
3575 {
3576#ifdef CLASH_DETECTION
3577 if (!auto_saving) unlock_file (lockname);
3578#endif /* CLASH_DETECTION */
3579 report_file_error ("Lseek error", Fcons (filename, Qnil));
3580 }
3581
3582#ifdef VMS
3583/*
3584 * Kludge Warning: The VMS C RTL likes to insert carriage returns
3585 * if we do writes that don't end with a carriage return. Furthermore
3586 * it cannot handle writes of more then 16K. The modified
3587 * version of "sys_write" in SYSDEP.C (see comment there) copes with
3588 * this EXCEPT for the last record (iff it doesn't end with a carriage
3589 * return). This implies that if your buffer doesn't end with a carriage
3590 * return, you get one free... tough. However it also means that if
3591 * we make two calls to sys_write (a la the following code) you can
3592 * get one at the gap as well. The easiest way to fix this (honest)
3593 * is to move the gap to the next newline (or the end of the buffer).
3594 * Thus this change.
3595 *
3596 * Yech!
3597 */
3598 if (GPT > BEG && GPT_ADDR[-1] != '\n')
3599 move_gap (find_next_newline (GPT, 1));
3600#endif
3601
3602 failure = 0;
3603 immediate_quit = 1;
3604
3605 if (STRINGP (start))
3606 {
3607 failure = 0 > a_write (desc, XSTRING (start)->data,
3608 XSTRING (start)->size, 0, &annotations);
3609 save_errno = errno;
3610 }
3611 else if (XINT (start) != XINT (end))
3612 {
3613 int nwritten = 0;
3614 if (XINT (start) < GPT)
3615 {
3616 register int end1 = XINT (end);
3617 tem = XINT (start);
3618 failure = 0 > a_write (desc, &FETCH_CHAR (tem),
3619 min (GPT, end1) - tem, tem, &annotations);
3620 nwritten += min (GPT, end1) - tem;
3621 save_errno = errno;
3622 }
3623
3624 if (XINT (end) > GPT && !failure)
3625 {
3626 tem = XINT (start);
3627 tem = max (tem, GPT);
3628 failure = 0 > a_write (desc, &FETCH_CHAR (tem), XINT (end) - tem,
3629 tem, &annotations);
3630 nwritten += XINT (end) - tem;
3631 save_errno = errno;
3632 }
3633 }
3634 else
3635 {
3636 /* If file was empty, still need to write the annotations */
3637 failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
3638 save_errno = errno;
3639 }
3640
3641 immediate_quit = 0;
3642
3643#ifdef HAVE_FSYNC
3644 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
3645 Disk full in NFS may be reported here. */
3646 /* mib says that closing the file will try to write as fast as NFS can do
3647 it, and that means the fsync here is not crucial for autosave files. */
3648 if (!auto_saving && fsync (desc) < 0)
3649 {
3650 /* If fsync fails with EINTR, don't treat that as serious. */
3651 if (errno != EINTR)
3652 failure = 1, save_errno = errno;
3653 }
3654#endif
3655
3656 /* Spurious "file has changed on disk" warnings have been
3657 observed on Suns as well.
3658 It seems that `close' can change the modtime, under nfs.
3659
3660 (This has supposedly been fixed in Sunos 4,
3661 but who knows about all the other machines with NFS?) */
3662#if 0
3663
3664 /* On VMS and APOLLO, must do the stat after the close
3665 since closing changes the modtime. */
3666#ifndef VMS
3667#ifndef APOLLO
3668 /* Recall that #if defined does not work on VMS. */
3669#define FOO
3670 fstat (desc, &st);
3671#endif
3672#endif
3673#endif
3674
3675 /* NFS can report a write failure now. */
3676 if (close (desc) < 0)
3677 failure = 1, save_errno = errno;
3678
3679#ifdef VMS
3680 /* If we wrote to a temporary name and had no errors, rename to real name. */
3681 if (fname)
3682 {
3683 if (!failure)
3684 failure = (rename (fn, fname) != 0), save_errno = errno;
3685 fn = fname;
3686 }
3687#endif /* VMS */
3688
3689#ifndef FOO
3690 stat (fn, &st);
3691#endif
3692 /* Discard the unwind protect for close_file_unwind. */
3693 specpdl_ptr = specpdl + count1;
3694 /* Restore the original current buffer. */
3695 visit_file = unbind_to (count, visit_file);
3696
3697#ifdef CLASH_DETECTION
3698 if (!auto_saving)
3699 unlock_file (lockname);
3700#endif /* CLASH_DETECTION */
3701
3702 /* Do this before reporting IO error
3703 to avoid a "file has changed on disk" warning on
3704 next attempt to save. */
3705 if (visiting)
3706 current_buffer->modtime = st.st_mtime;
3707
3708 if (failure)
3709 error ("IO error writing %s: %s", fn, strerror (save_errno));
3710
3711 if (visiting)
3712 {
3713 SAVE_MODIFF = MODIFF;
3714 XSETFASTINT (current_buffer->save_length, Z - BEG);
3715 current_buffer->filename = visit_file;
3716 update_mode_lines++;
3717 }
3718 else if (quietly)
3719 return Qnil;
3720
3721 if (!auto_saving)
3722 message ("Wrote %s", XSTRING (visit_file)->data);
3723
3724 return Qnil;
3725}
3726
3727Lisp_Object merge ();
3728
3729DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
3730 "Return t if (car A) is numerically less than (car B).")
3731 (a, b)
3732 Lisp_Object a, b;
3733{
3734 return Flss (Fcar (a), Fcar (b));
3735}
3736
3737/* Build the complete list of annotations appropriate for writing out
3738 the text between START and END, by calling all the functions in
3739 write-region-annotate-functions and merging the lists they return.
3740 If one of these functions switches to a different buffer, we assume
3741 that buffer contains altered text. Therefore, the caller must
3742 make sure to restore the current buffer in all cases,
3743 as save-excursion would do. */
3744
3745static Lisp_Object
3746build_annotations (start, end)
3747 Lisp_Object start, end;
3748{
3749 Lisp_Object annotations;
3750 Lisp_Object p, res;
3751 struct gcpro gcpro1, gcpro2;
3752
3753 annotations = Qnil;
3754 p = Vwrite_region_annotate_functions;
3755 GCPRO2 (annotations, p);
3756 while (!NILP (p))
3757 {
3758 struct buffer *given_buffer = current_buffer;
3759 Vwrite_region_annotations_so_far = annotations;
3760 res = call2 (Fcar (p), start, end);
3761 /* If the function makes a different buffer current,
3762 assume that means this buffer contains altered text to be output.
3763 Reset START and END from the buffer bounds
3764 and discard all previous annotations because they should have
3765 been dealt with by this function. */
3766 if (current_buffer != given_buffer)
3767 {
3768 start = BEGV;
3769 end = ZV;
3770 annotations = Qnil;
3771 }
3772 Flength (res); /* Check basic validity of return value */
3773 annotations = merge (annotations, res, Qcar_less_than_car);
3774 p = Fcdr (p);
3775 }
3776
3777 /* Now do the same for annotation functions implied by the file-format */
3778 if (auto_saving && (!EQ (Vauto_save_file_format, Qt)))
3779 p = Vauto_save_file_format;
3780 else
3781 p = current_buffer->file_format;
3782 while (!NILP (p))
3783 {
3784 struct buffer *given_buffer = current_buffer;
3785 Vwrite_region_annotations_so_far = annotations;
3786 res = call3 (Qformat_annotate_function, Fcar (p), start, end);
3787 if (current_buffer != given_buffer)
3788 {
3789 start = BEGV;
3790 end = ZV;
3791 annotations = Qnil;
3792 }
3793 Flength (res);
3794 annotations = merge (annotations, res, Qcar_less_than_car);
3795 p = Fcdr (p);
3796 }
3797 UNGCPRO;
3798 return annotations;
3799}
3800
3801/* Write to descriptor DESC the LEN characters starting at ADDR,
3802 assuming they start at position POS in the buffer.
3803 Intersperse with them the annotations from *ANNOT
3804 (those which fall within the range of positions POS to POS + LEN),
3805 each at its appropriate position.
3806
3807 Modify *ANNOT by discarding elements as we output them.
3808 The return value is negative in case of system call failure. */
3809
3810int
3811a_write (desc, addr, len, pos, annot)
3812 int desc;
3813 register char *addr;
3814 register int len;
3815 int pos;
3816 Lisp_Object *annot;
3817{
3818 Lisp_Object tem;
3819 int nextpos;
3820 int lastpos = pos + len;
3821
3822 while (NILP (*annot) || CONSP (*annot))
3823 {
3824 tem = Fcar_safe (Fcar (*annot));
3825 if (INTEGERP (tem) && XINT (tem) >= pos && XFASTINT (tem) <= lastpos)
3826 nextpos = XFASTINT (tem);
3827 else
3828 return e_write (desc, addr, lastpos - pos);
3829 if (nextpos > pos)
3830 {
3831 if (0 > e_write (desc, addr, nextpos - pos))
3832 return -1;
3833 addr += nextpos - pos;
3834 pos = nextpos;
3835 }
3836 tem = Fcdr (Fcar (*annot));
3837 if (STRINGP (tem))
3838 {
3839 if (0 > e_write (desc, XSTRING (tem)->data, XSTRING (tem)->size))
3840 return -1;
3841 }
3842 *annot = Fcdr (*annot);
3843 }
3844}
3845
3846int
3847e_write (desc, addr, len)
3848 int desc;
3849 register char *addr;
3850 register int len;
3851{
3852 char buf[16 * 1024];
3853 register char *p, *end;
3854
3855 if (!EQ (current_buffer->selective_display, Qt))
3856 return write (desc, addr, len) - len;
3857 else
3858 {
3859 p = buf;
3860 end = p + sizeof buf;
3861 while (len--)
3862 {
3863 if (p == end)
3864 {
3865 if (write (desc, buf, sizeof buf) != sizeof buf)
3866 return -1;
3867 p = buf;
3868 }
3869 *p = *addr++;
3870 if (*p++ == '\015')
3871 p[-1] = '\n';
3872 }
3873 if (p != buf)
3874 if (write (desc, buf, p - buf) != p - buf)
3875 return -1;
3876 }
3877 return 0;
3878}
3879
3880DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
3881 Sverify_visited_file_modtime, 1, 1, 0,
3882 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
3883This means that the file has not been changed since it was visited or saved.")
3884 (buf)
3885 Lisp_Object buf;
3886{
3887 struct buffer *b;
3888 struct stat st;
3889 Lisp_Object handler;
3890
3891 CHECK_BUFFER (buf, 0);
3892 b = XBUFFER (buf);
3893
3894 if (!STRINGP (b->filename)) return Qt;
3895 if (b->modtime == 0) return Qt;
3896
3897 /* If the file name has special constructs in it,
3898 call the corresponding file handler. */
3899 handler = Ffind_file_name_handler (b->filename,
3900 Qverify_visited_file_modtime);
3901 if (!NILP (handler))
3902 return call2 (handler, Qverify_visited_file_modtime, buf);
3903
3904 if (stat (XSTRING (b->filename)->data, &st) < 0)
3905 {
3906 /* If the file doesn't exist now and didn't exist before,
3907 we say that it isn't modified, provided the error is a tame one. */
3908 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
3909 st.st_mtime = -1;
3910 else
3911 st.st_mtime = 0;
3912 }
3913 if (st.st_mtime == b->modtime
3914 /* If both are positive, accept them if they are off by one second. */
3915 || (st.st_mtime > 0 && b->modtime > 0
3916 && (st.st_mtime == b->modtime + 1
3917 || st.st_mtime == b->modtime - 1)))
3918 return Qt;
3919 return Qnil;
3920}
3921
3922DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
3923 Sclear_visited_file_modtime, 0, 0, 0,
3924 "Clear out records of last mod time of visited file.\n\
3925Next attempt to save will certainly not complain of a discrepancy.")
3926 ()
3927{
3928 current_buffer->modtime = 0;
3929 return Qnil;
3930}
3931
3932DEFUN ("visited-file-modtime", Fvisited_file_modtime,
3933 Svisited_file_modtime, 0, 0, 0,
3934 "Return the current buffer's recorded visited file modification time.\n\
3935The value is a list of the form (HIGH . LOW), like the time values\n\
3936that `file-attributes' returns.")
3937 ()
3938{
3939 return long_to_cons ((unsigned long) current_buffer->modtime);
3940}
3941
3942DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
3943 Sset_visited_file_modtime, 0, 1, 0,
3944 "Update buffer's recorded modification time from the visited file's time.\n\
3945Useful if the buffer was not read from the file normally\n\
3946or if the file itself has been changed for some known benign reason.\n\
3947An argument specifies the modification time value to use\n\
3948\(instead of that of the visited file), in the form of a list\n\
3949\(HIGH . LOW) or (HIGH LOW).")
3950 (time_list)
3951 Lisp_Object time_list;
3952{
3953 if (!NILP (time_list))
3954 current_buffer->modtime = cons_to_long (time_list);
3955 else
3956 {
3957 register Lisp_Object filename;
3958 struct stat st;
3959 Lisp_Object handler;
3960
3961 filename = Fexpand_file_name (current_buffer->filename, Qnil);
3962
3963 /* If the file name has special constructs in it,
3964 call the corresponding file handler. */
3965 handler = Ffind_file_name_handler (filename, Qset_visited_file_modtime);
3966 if (!NILP (handler))
3967 /* The handler can find the file name the same way we did. */
3968 return call2 (handler, Qset_visited_file_modtime, Qnil);
3969 else if (stat (XSTRING (filename)->data, &st) >= 0)
3970 current_buffer->modtime = st.st_mtime;
3971 }
3972
3973 return Qnil;
3974}
3975\f
3976Lisp_Object
3977auto_save_error ()
3978{
3979 ring_bell ();
3980 message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
3981 Fsleep_for (make_number (1), Qnil);
3982 message ("Autosaving...error!for %s", XSTRING (current_buffer->name)->data);
3983 Fsleep_for (make_number (1), Qnil);
3984 message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
3985 Fsleep_for (make_number (1), Qnil);
3986 return Qnil;
3987}
3988
3989Lisp_Object
3990auto_save_1 ()
3991{
3992 unsigned char *fn;
3993 struct stat st;
3994
3995 /* Get visited file's mode to become the auto save file's mode. */
3996 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
3997 /* But make sure we can overwrite it later! */
3998 auto_save_mode_bits = st.st_mode | 0600;
3999 else
4000 auto_save_mode_bits = 0666;
4001
4002 return
4003 Fwrite_region (Qnil, Qnil,
4004 current_buffer->auto_save_file_name,
4005 Qnil, Qlambda, Qnil);
4006}
4007
4008static Lisp_Object
4009do_auto_save_unwind (desc) /* used as unwind-protect function */
4010 Lisp_Object desc;
4011{
4012 auto_saving = 0;
4013 if (XINT (desc) >= 0)
4014 close (XINT (desc));
4015 return Qnil;
4016}
4017
4018DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
4019 "Auto-save all buffers that need it.\n\
4020This is all buffers that have auto-saving enabled\n\
4021and are changed since last auto-saved.\n\
4022Auto-saving writes the buffer into a file\n\
4023so that your editing is not lost if the system crashes.\n\
4024This file is not the file you visited; that changes only when you save.\n\
4025Normally we run the normal hook `auto-save-hook' before saving.\n\n\
4026A non-nil NO-MESSAGE argument means do not print any message if successful.\n\
4027A non-nil CURRENT-ONLY argument means save only current buffer.")
4028 (no_message, current_only)
4029 Lisp_Object no_message, current_only;
4030{
4031 struct buffer *old = current_buffer, *b;
4032 Lisp_Object tail, buf;
4033 int auto_saved = 0;
4034 char *omessage = echo_area_glyphs;
4035 int omessage_length = echo_area_glyphs_length;
4036 extern int minibuf_level;
4037 int do_handled_files;
4038 Lisp_Object oquit;
4039 int listdesc;
4040 int count = specpdl_ptr - specpdl;
4041 int *ptr;
4042
4043 /* Ordinarily don't quit within this function,
4044 but don't make it impossible to quit (in case we get hung in I/O). */
4045 oquit = Vquit_flag;
4046 Vquit_flag = Qnil;
4047
4048 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
4049 point to non-strings reached from Vbuffer_alist. */
4050
4051 if (minibuf_level)
4052 no_message = Qt;
4053
4054 if (!NILP (Vrun_hooks))
4055 call1 (Vrun_hooks, intern ("auto-save-hook"));
4056
4057 if (STRINGP (Vauto_save_list_file_name))
4058 {
4059 Lisp_Object listfile;
4060 listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
4061#ifdef DOS_NT
4062 listdesc = open (XSTRING (listfile)->data,
4063 O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
4064 S_IREAD | S_IWRITE);
4065#else /* not DOS_NT */
4066 listdesc = creat (XSTRING (listfile)->data, 0666);
4067#endif /* not DOS_NT */
4068 }
4069 else
4070 listdesc = -1;
4071
4072 /* Arrange to close that file whether or not we get an error.
4073 Also reset auto_saving to 0. */
4074 record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
4075
4076 auto_saving = 1;
4077
4078 /* First, save all files which don't have handlers. If Emacs is
4079 crashing, the handlers may tweak what is causing Emacs to crash
4080 in the first place, and it would be a shame if Emacs failed to
4081 autosave perfectly ordinary files because it couldn't handle some
4082 ange-ftp'd file. */
4083 for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
4084 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
4085 {
4086 buf = XCONS (XCONS (tail)->car)->cdr;
4087 b = XBUFFER (buf);
4088
4089 /* Record all the buffers that have auto save mode
4090 in the special file that lists them. For each of these buffers,
4091 Record visited name (if any) and auto save name. */
4092 if (STRINGP (b->auto_save_file_name)
4093 && listdesc >= 0 && do_handled_files == 0)
4094 {
4095 if (!NILP (b->filename))
4096 {
4097 write (listdesc, XSTRING (b->filename)->data,
4098 XSTRING (b->filename)->size);
4099 }
4100 write (listdesc, "\n", 1);
4101 write (listdesc, XSTRING (b->auto_save_file_name)->data,
4102 XSTRING (b->auto_save_file_name)->size);
4103 write (listdesc, "\n", 1);
4104 }
4105
4106 if (!NILP (current_only)
4107 && b != current_buffer)
4108 continue;
4109
4110 /* Don't auto-save indirect buffers.
4111 The base buffer takes care of it. */
4112 if (b->base_buffer)
4113 continue;
4114
4115 /* Check for auto save enabled
4116 and file changed since last auto save
4117 and file changed since last real save. */
4118 if (STRINGP (b->auto_save_file_name)
4119 && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)
4120 && b->auto_save_modified < BUF_MODIFF (b)
4121 /* -1 means we've turned off autosaving for a while--see below. */
4122 && XINT (b->save_length) >= 0
4123 && (do_handled_files
4124 || NILP (Ffind_file_name_handler (b->auto_save_file_name,
4125 Qwrite_region))))
4126 {
4127 EMACS_TIME before_time, after_time;
4128
4129 EMACS_GET_TIME (before_time);
4130
4131 /* If we had a failure, don't try again for 20 minutes. */
4132 if (b->auto_save_failure_time >= 0
4133 && EMACS_SECS (before_time) - b->auto_save_failure_time < 1200)
4134 continue;
4135
4136 if ((XFASTINT (b->save_length) * 10
4137 > (BUF_Z (b) - BUF_BEG (b)) * 13)
4138 /* A short file is likely to change a large fraction;
4139 spare the user annoying messages. */
4140 && XFASTINT (b->save_length) > 5000
4141 /* These messages are frequent and annoying for `*mail*'. */
4142 && !EQ (b->filename, Qnil)
4143 && NILP (no_message))
4144 {
4145 /* It has shrunk too much; turn off auto-saving here. */
4146 message ("Buffer %s has shrunk a lot; auto save turned off there",
4147 XSTRING (b->name)->data);
4148 /* Turn off auto-saving until there's a real save,
4149 and prevent any more warnings. */
4150 XSETINT (b->save_length, -1);
4151 Fsleep_for (make_number (1), Qnil);
4152 continue;
4153 }
4154 set_buffer_internal (b);
4155 if (!auto_saved && NILP (no_message))
4156 message1 ("Auto-saving...");
4157 internal_condition_case (auto_save_1, Qt, auto_save_error);
4158 auto_saved++;
4159 b->auto_save_modified = BUF_MODIFF (b);
4160 XSETFASTINT (current_buffer->save_length, Z - BEG);
4161 set_buffer_internal (old);
4162
4163 EMACS_GET_TIME (after_time);
4164
4165 /* If auto-save took more than 60 seconds,
4166 assume it was an NFS failure that got a timeout. */
4167 if (EMACS_SECS (after_time) - EMACS_SECS (before_time) > 60)
4168 b->auto_save_failure_time = EMACS_SECS (after_time);
4169 }
4170 }
4171
4172 /* Prevent another auto save till enough input events come in. */
4173 record_auto_save ();
4174
4175 if (auto_saved && NILP (no_message))
4176 {
4177 if (omessage)
4178 {
4179 sit_for (1, 0, 0, 0);
4180 message2 (omessage, omessage_length);
4181 }
4182 else
4183 message1 ("Auto-saving...done");
4184 }
4185
4186 Vquit_flag = oquit;
4187
4188 unbind_to (count, Qnil);
4189 return Qnil;
4190}
4191
4192DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
4193 Sset_buffer_auto_saved, 0, 0, 0,
4194 "Mark current buffer as auto-saved with its current text.\n\
4195No auto-save file will be written until the buffer changes again.")
4196 ()
4197{
4198 current_buffer->auto_save_modified = MODIFF;
4199 XSETFASTINT (current_buffer->save_length, Z - BEG);
4200 current_buffer->auto_save_failure_time = -1;
4201 return Qnil;
4202}
4203
4204DEFUN ("clear-buffer-auto-save-failure", Fclear_buffer_auto_save_failure,
4205 Sclear_buffer_auto_save_failure, 0, 0, 0,
4206 "Clear any record of a recent auto-save failure in the current buffer.")
4207 ()
4208{
4209 current_buffer->auto_save_failure_time = -1;
4210 return Qnil;
4211}
4212
4213DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
4214 0, 0, 0,
4215 "Return t if buffer has been auto-saved since last read in or saved.")
4216 ()
4217{
4218 return (SAVE_MODIFF < current_buffer->auto_save_modified) ? Qt : Qnil;
4219}
4220\f
4221/* Reading and completing file names */
4222extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
4223
4224/* In the string VAL, change each $ to $$ and return the result. */
4225
4226static Lisp_Object
4227double_dollars (val)
4228 Lisp_Object val;
4229{
4230 register unsigned char *old, *new;
4231 register int n;
4232 int osize, count;
4233
4234 osize = XSTRING (val)->size;
4235 /* Quote "$" as "$$" to get it past substitute-in-file-name */
4236 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
4237 if (*old++ == '$') count++;
4238 if (count > 0)
4239 {
4240 old = XSTRING (val)->data;
4241 val = Fmake_string (make_number (osize + count), make_number (0));
4242 new = XSTRING (val)->data;
4243 for (n = osize; n > 0; n--)
4244 if (*old != '$')
4245 *new++ = *old++;
4246 else
4247 {
4248 *new++ = '$';
4249 *new++ = '$';
4250 old++;
4251 }
4252 }
4253 return val;
4254}
4255
4256DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
4257 3, 3, 0,
4258 "Internal subroutine for read-file-name. Do not call this.")
4259 (string, dir, action)
4260 Lisp_Object string, dir, action;
4261 /* action is nil for complete, t for return list of completions,
4262 lambda for verify final value */
4263{
4264 Lisp_Object name, specdir, realdir, val, orig_string;
4265 int changed;
4266 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
4267
4268 realdir = dir;
4269 name = string;
4270 orig_string = Qnil;
4271 specdir = Qnil;
4272 changed = 0;
4273 /* No need to protect ACTION--we only compare it with t and nil. */
4274 GCPRO5 (string, realdir, name, specdir, orig_string);
4275
4276 if (XSTRING (string)->size == 0)
4277 {
4278 if (EQ (action, Qlambda))
4279 {
4280 UNGCPRO;
4281 return Qnil;
4282 }
4283 }
4284 else
4285 {
4286 orig_string = string;
4287 string = Fsubstitute_in_file_name (string);
4288 changed = NILP (Fstring_equal (string, orig_string));
4289 name = Ffile_name_nondirectory (string);
4290 val = Ffile_name_directory (string);
4291 if (! NILP (val))
4292 realdir = Fexpand_file_name (val, realdir);
4293 }
4294
4295 if (NILP (action))
4296 {
4297 specdir = Ffile_name_directory (string);
4298 val = Ffile_name_completion (name, realdir);
4299 UNGCPRO;
4300 if (!STRINGP (val))
4301 {
4302 if (changed)
4303 return double_dollars (string);
4304 return val;
4305 }
4306
4307 if (!NILP (specdir))
4308 val = concat2 (specdir, val);
4309#ifndef VMS
4310 return double_dollars (val);
4311#else /* not VMS */
4312 return val;
4313#endif /* not VMS */
4314 }
4315 UNGCPRO;
4316
4317 if (EQ (action, Qt))
4318 return Ffile_name_all_completions (name, realdir);
4319 /* Only other case actually used is ACTION = lambda */
4320#ifdef VMS
4321 /* Supposedly this helps commands such as `cd' that read directory names,
4322 but can someone explain how it helps them? -- RMS */
4323 if (XSTRING (name)->size == 0)
4324 return Qt;
4325#endif /* VMS */
4326 return Ffile_exists_p (string);
4327}
4328
4329DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
4330 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
4331Value is not expanded---you must call `expand-file-name' yourself.\n\
4332Default name to DEFAULT-FILENAME if user enters a null string.\n\
4333 (If DEFAULT-FILENAME is omitted, the visited file name is used,\n\
4334 except that if INITIAL is specified, that combined with DIR is used.)\n\
4335Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
4336 Non-nil and non-t means also require confirmation after completion.\n\
4337Fifth arg INITIAL specifies text to start with.\n\
4338DIR defaults to current buffer's directory default.")
4339 (prompt, dir, default_filename, mustmatch, initial)
4340 Lisp_Object prompt, dir, default_filename, mustmatch, initial;
4341{
4342 Lisp_Object val, insdef, insdef1, tem;
4343 struct gcpro gcpro1, gcpro2;
4344 register char *homedir;
4345 int count;
4346
4347 if (NILP (dir))
4348 dir = current_buffer->directory;
4349 if (NILP (default_filename))
4350 {
4351 if (! NILP (initial))
4352 default_filename = Fexpand_file_name (initial, dir);
4353 else
4354 default_filename = current_buffer->filename;
4355 }
4356
4357 /* If dir starts with user's homedir, change that to ~. */
4358 homedir = (char *) egetenv ("HOME");
4359#ifdef DOS_NT
4360 homedir = strcpy (alloca (strlen (homedir) + 1), homedir);
4361 CORRECT_DIR_SEPS (homedir);
4362#endif
4363 if (homedir != 0
4364 && STRINGP (dir)
4365 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
4366 && IS_DIRECTORY_SEP (XSTRING (dir)->data[strlen (homedir)]))
4367 {
4368 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
4369 XSTRING (dir)->size - strlen (homedir) + 1);
4370 XSTRING (dir)->data[0] = '~';
4371 }
4372
4373 if (insert_default_directory)
4374 {
4375 insdef = dir;
4376 if (!NILP (initial))
4377 {
4378 Lisp_Object args[2], pos;
4379
4380 args[0] = insdef;
4381 args[1] = initial;
4382 insdef = Fconcat (2, args);
4383 pos = make_number (XSTRING (double_dollars (dir))->size);
4384 insdef1 = Fcons (double_dollars (insdef), pos);
4385 }
4386 else
4387 insdef1 = double_dollars (insdef);
4388 }
4389 else if (!NILP (initial))
4390 {
4391 insdef = initial;
4392 insdef1 = Fcons (double_dollars (insdef), 0);
4393 }
4394 else
4395 insdef = Qnil, insdef1 = Qnil;
4396
4397#ifdef VMS
4398 count = specpdl_ptr - specpdl;
4399 specbind (intern ("completion-ignore-case"), Qt);
4400#endif
4401
4402 GCPRO2 (insdef, default_filename);
4403 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4404 dir, mustmatch, insdef1,
4405 Qfile_name_history);
4406
4407#ifdef VMS
4408 unbind_to (count, Qnil);
4409#endif
4410
4411 UNGCPRO;
4412 if (NILP (val))
4413 error ("No file name specified");
4414 tem = Fstring_equal (val, insdef);
4415 if (!NILP (tem) && !NILP (default_filename))
4416 return default_filename;
4417 if (XSTRING (val)->size == 0 && NILP (insdef))
4418 {
4419 if (!NILP (default_filename))
4420 return default_filename;
4421 else
4422 error ("No default file name");
4423 }
4424 return Fsubstitute_in_file_name (val);
4425}
4426
4427#if 0 /* Old version */
4428DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
4429 /* Don't confuse make-docfile by having two doc strings for this function.
4430 make-docfile does not pay attention to #if, for good reason! */
4431 0)
4432 (prompt, dir, defalt, mustmatch, initial)
4433 Lisp_Object prompt, dir, defalt, mustmatch, initial;
4434{
4435 Lisp_Object val, insdef, tem;
4436 struct gcpro gcpro1, gcpro2;
4437 register char *homedir;
4438 int count;
4439
4440 if (NILP (dir))
4441 dir = current_buffer->directory;
4442 if (NILP (defalt))
4443 defalt = current_buffer->filename;
4444
4445 /* If dir starts with user's homedir, change that to ~. */
4446 homedir = (char *) egetenv ("HOME");
4447 if (homedir != 0
4448 && STRINGP (dir)
4449 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
4450 && XSTRING (dir)->data[strlen (homedir)] == '/')
4451 {
4452 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
4453 XSTRING (dir)->size - strlen (homedir) + 1);
4454 XSTRING (dir)->data[0] = '~';
4455 }
4456
4457 if (!NILP (initial))
4458 insdef = initial;
4459 else if (insert_default_directory)
4460 insdef = dir;
4461 else
4462 insdef = build_string ("");
4463
4464#ifdef VMS
4465 count = specpdl_ptr - specpdl;
4466 specbind (intern ("completion-ignore-case"), Qt);
4467#endif
4468
4469 GCPRO2 (insdef, defalt);
4470 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4471 dir, mustmatch,
4472 insert_default_directory ? insdef : Qnil,
4473 Qfile_name_history);
4474
4475#ifdef VMS
4476 unbind_to (count, Qnil);
4477#endif
4478
4479 UNGCPRO;
4480 if (NILP (val))
4481 error ("No file name specified");
4482 tem = Fstring_equal (val, insdef);
4483 if (!NILP (tem) && !NILP (defalt))
4484 return defalt;
4485 return Fsubstitute_in_file_name (val);
4486}
4487#endif /* Old version */
4488\f
4489syms_of_fileio ()
4490{
4491 Qexpand_file_name = intern ("expand-file-name");
4492 Qsubstitute_in_file_name = intern ("substitute-in-file-name");
4493 Qdirectory_file_name = intern ("directory-file-name");
4494 Qfile_name_directory = intern ("file-name-directory");
4495 Qfile_name_nondirectory = intern ("file-name-nondirectory");
4496 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
4497 Qfile_name_as_directory = intern ("file-name-as-directory");
4498 Qcopy_file = intern ("copy-file");
4499 Qmake_directory_internal = intern ("make-directory-internal");
4500 Qdelete_directory = intern ("delete-directory");
4501 Qdelete_file = intern ("delete-file");
4502 Qrename_file = intern ("rename-file");
4503 Qadd_name_to_file = intern ("add-name-to-file");
4504 Qmake_symbolic_link = intern ("make-symbolic-link");
4505 Qfile_exists_p = intern ("file-exists-p");
4506 Qfile_executable_p = intern ("file-executable-p");
4507 Qfile_readable_p = intern ("file-readable-p");
4508 Qfile_symlink_p = intern ("file-symlink-p");
4509 Qfile_writable_p = intern ("file-writable-p");
4510 Qfile_directory_p = intern ("file-directory-p");
4511 Qfile_regular_p = intern ("file-regular-p");
4512 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
4513 Qfile_modes = intern ("file-modes");
4514 Qset_file_modes = intern ("set-file-modes");
4515 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
4516 Qinsert_file_contents = intern ("insert-file-contents");
4517 Qwrite_region = intern ("write-region");
4518 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
4519 Qset_visited_file_modtime = intern ("set-visited-file-modtime");
4520
4521 staticpro (&Qexpand_file_name);
4522 staticpro (&Qsubstitute_in_file_name);
4523 staticpro (&Qdirectory_file_name);
4524 staticpro (&Qfile_name_directory);
4525 staticpro (&Qfile_name_nondirectory);
4526 staticpro (&Qunhandled_file_name_directory);
4527 staticpro (&Qfile_name_as_directory);
4528 staticpro (&Qcopy_file);
4529 staticpro (&Qmake_directory_internal);
4530 staticpro (&Qdelete_directory);
4531 staticpro (&Qdelete_file);
4532 staticpro (&Qrename_file);
4533 staticpro (&Qadd_name_to_file);
4534 staticpro (&Qmake_symbolic_link);
4535 staticpro (&Qfile_exists_p);
4536 staticpro (&Qfile_executable_p);
4537 staticpro (&Qfile_readable_p);
4538 staticpro (&Qfile_symlink_p);
4539 staticpro (&Qfile_writable_p);
4540 staticpro (&Qfile_directory_p);
4541 staticpro (&Qfile_regular_p);
4542 staticpro (&Qfile_accessible_directory_p);
4543 staticpro (&Qfile_modes);
4544 staticpro (&Qset_file_modes);
4545 staticpro (&Qfile_newer_than_file_p);
4546 staticpro (&Qinsert_file_contents);
4547 staticpro (&Qwrite_region);
4548 staticpro (&Qverify_visited_file_modtime);
4549
4550 Qfile_name_history = intern ("file-name-history");
4551 Fset (Qfile_name_history, Qnil);
4552 staticpro (&Qfile_name_history);
4553
4554 Qfile_error = intern ("file-error");
4555 staticpro (&Qfile_error);
4556 Qfile_already_exists = intern ("file-already-exists");
4557 staticpro (&Qfile_already_exists);
4558
4559#ifdef DOS_NT
4560 Qfind_buffer_file_type = intern ("find-buffer-file-type");
4561 staticpro (&Qfind_buffer_file_type);
4562#endif /* DOS_NT */
4563
4564 DEFVAR_LISP ("auto-save-file-format", &Vauto_save_file_format,
4565 "*Format in which to write auto-save files.\n\
4566Should be a list of symbols naming formats that are defined in `format-alist'.\n\
4567If it is t, which is the default, auto-save files are written in the\n\
4568same format as a regular save would use.");
4569 Vauto_save_file_format = Qt;
4570
4571 Qformat_decode = intern ("format-decode");
4572 staticpro (&Qformat_decode);
4573 Qformat_annotate_function = intern ("format-annotate-function");
4574 staticpro (&Qformat_annotate_function);
4575
4576 Qcar_less_than_car = intern ("car-less-than-car");
4577 staticpro (&Qcar_less_than_car);
4578
4579 Fput (Qfile_error, Qerror_conditions,
4580 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
4581 Fput (Qfile_error, Qerror_message,
4582 build_string ("File error"));
4583
4584 Fput (Qfile_already_exists, Qerror_conditions,
4585 Fcons (Qfile_already_exists,
4586 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
4587 Fput (Qfile_already_exists, Qerror_message,
4588 build_string ("File already exists"));
4589
4590 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
4591 "*Non-nil means when reading a filename start with default dir in minibuffer.");
4592 insert_default_directory = 1;
4593
4594 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
4595 "*Non-nil means write new files with record format `stmlf'.\n\
4596nil means use format `var'. This variable is meaningful only on VMS.");
4597 vms_stmlf_recfm = 0;
4598
4599 DEFVAR_LISP ("directory-sep-char", &Vdirectory_sep_char,
4600 "Directory separator character for built-in functions that return file names.\n\
4601The value should be either ?/ or ?\\ (any other value is treated as ?\\).\n\
4602This variable affects the built-in functions only on Windows,\n\
4603on other platforms, it is initialized so that Lisp code can find out\n\
4604what the normal separator is.");
4605 Vdirectory_sep_char = '/';
4606
4607 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
4608 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
4609If a file name matches REGEXP, then all I/O on that file is done by calling\n\
4610HANDLER.\n\
4611\n\
4612The first argument given to HANDLER is the name of the I/O primitive\n\
4613to be handled; the remaining arguments are the arguments that were\n\
4614passed to that primitive. For example, if you do\n\
4615 (file-exists-p FILENAME)\n\
4616and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
4617 (funcall HANDLER 'file-exists-p FILENAME)\n\
4618The function `find-file-name-handler' checks this list for a handler\n\
4619for its argument.");
4620 Vfile_name_handler_alist = Qnil;
4621
4622 DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
4623 "A list of functions to be called at the end of `insert-file-contents'.\n\
4624Each is passed one argument, the number of bytes inserted. It should return\n\
4625the new byte count, and leave point the same. If `insert-file-contents' is\n\
4626intercepted by a handler from `file-name-handler-alist', that handler is\n\
4627responsible for calling the after-insert-file-functions if appropriate.");
4628 Vafter_insert_file_functions = Qnil;
4629
4630 DEFVAR_LISP ("write-region-annotate-functions", &Vwrite_region_annotate_functions,
4631 "A list of functions to be called at the start of `write-region'.\n\
4632Each is passed two arguments, START and END as for `write-region'.\n\
4633These are usually two numbers but not always; see the documentation\n\
4634for `write-region'. The function should return a list of pairs\n\
4635of the form (POSITION . STRING), consisting of strings to be effectively\n\
4636inserted at the specified positions of the file being written (1 means to\n\
4637insert before the first byte written). The POSITIONs must be sorted into\n\
4638increasing order. If there are several functions in the list, the several\n\
4639lists are merged destructively.");
4640 Vwrite_region_annotate_functions = Qnil;
4641
4642 DEFVAR_LISP ("write-region-annotations-so-far",
4643 &Vwrite_region_annotations_so_far,
4644 "When an annotation function is called, this holds the previous annotations.\n\
4645These are the annotations made by other annotation functions\n\
4646that were already called. See also `write-region-annotate-functions'.");
4647 Vwrite_region_annotations_so_far = Qnil;
4648
4649 DEFVAR_LISP ("inhibit-file-name-handlers", &Vinhibit_file_name_handlers,
4650 "A list of file name handlers that temporarily should not be used.\n\
4651This applies only to the operation `inhibit-file-name-operation'.");
4652 Vinhibit_file_name_handlers = Qnil;
4653
4654 DEFVAR_LISP ("inhibit-file-name-operation", &Vinhibit_file_name_operation,
4655 "The operation for which `inhibit-file-name-handlers' is applicable.");
4656 Vinhibit_file_name_operation = Qnil;
4657
4658 DEFVAR_LISP ("auto-save-list-file-name", &Vauto_save_list_file_name,
4659 "File name in which we write a list of all auto save file names.\n\
4660This variable is initialized automatically from `auto-save-list-file-prefix'\n\
4661shortly after Emacs reads your `.emacs' file, if you have not yet given it\n\
4662a non-nil value.");
4663 Vauto_save_list_file_name = Qnil;
4664
4665 defsubr (&Sfind_file_name_handler);
4666 defsubr (&Sfile_name_directory);
4667 defsubr (&Sfile_name_nondirectory);
4668 defsubr (&Sunhandled_file_name_directory);
4669 defsubr (&Sfile_name_as_directory);
4670 defsubr (&Sdirectory_file_name);
4671 defsubr (&Smake_temp_name);
4672 defsubr (&Sexpand_file_name);
4673 defsubr (&Ssubstitute_in_file_name);
4674 defsubr (&Scopy_file);
4675 defsubr (&Smake_directory_internal);
4676 defsubr (&Sdelete_directory);
4677 defsubr (&Sdelete_file);
4678 defsubr (&Srename_file);
4679 defsubr (&Sadd_name_to_file);
4680#ifdef S_IFLNK
4681 defsubr (&Smake_symbolic_link);
4682#endif /* S_IFLNK */
4683#ifdef VMS
4684 defsubr (&Sdefine_logical_name);
4685#endif /* VMS */
4686#ifdef HPUX_NET
4687 defsubr (&Ssysnetunam);
4688#endif /* HPUX_NET */
4689 defsubr (&Sfile_name_absolute_p);
4690 defsubr (&Sfile_exists_p);
4691 defsubr (&Sfile_executable_p);
4692 defsubr (&Sfile_readable_p);
4693 defsubr (&Sfile_writable_p);
4694 defsubr (&Sfile_symlink_p);
4695 defsubr (&Sfile_directory_p);
4696 defsubr (&Sfile_accessible_directory_p);
4697 defsubr (&Sfile_regular_p);
4698 defsubr (&Sfile_modes);
4699 defsubr (&Sset_file_modes);
4700 defsubr (&Sset_default_file_modes);
4701 defsubr (&Sdefault_file_modes);
4702 defsubr (&Sfile_newer_than_file_p);
4703 defsubr (&Sinsert_file_contents);
4704 defsubr (&Swrite_region);
4705 defsubr (&Scar_less_than_car);
4706 defsubr (&Sverify_visited_file_modtime);
4707 defsubr (&Sclear_visited_file_modtime);
4708 defsubr (&Svisited_file_modtime);
4709 defsubr (&Sset_visited_file_modtime);
4710 defsubr (&Sdo_auto_save);
4711 defsubr (&Sset_buffer_auto_saved);
4712 defsubr (&Sclear_buffer_auto_save_failure);
4713 defsubr (&Srecent_auto_save_p);
4714
4715 defsubr (&Sread_file_name_internal);
4716 defsubr (&Sread_file_name);
4717
4718#ifdef unix
4719 defsubr (&Sunix_sync);
4720#endif
4721}