* fileio.c (HAVE_FSYNC): Define, if appropriate.
[bpt/emacs.git] / src / fileio.c
1 /* File IO for GNU Emacs.
2 Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include "config.h"
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #ifdef VMS
26 #include "vms-pwd.h"
27 #else
28 #include <pwd.h>
29 #endif
30
31 #include <ctype.h>
32
33 #ifdef VMS
34 #include "dir.h"
35 #include <perror.h>
36 #include <stddef.h>
37 #include <string.h>
38 #endif
39
40 #include <errno.h>
41
42 #ifndef vax11c
43 extern int errno;
44 extern char *sys_errlist[];
45 extern int sys_nerr;
46 #endif
47
48 #define err_str(a) ((a) < sys_nerr ? sys_errlist[a] : "unknown error")
49
50 #ifdef APOLLO
51 #include <sys/time.h>
52 #endif
53
54 #ifndef USG
55 #ifndef VMS
56 #ifndef BSD4_1
57 #define HAVE_FSYNC
58 #endif
59 #endif
60 #endif
61
62 #include "lisp.h"
63 #include "intervals.h"
64 #include "buffer.h"
65 #include "window.h"
66
67 #ifdef VMS
68 #include <file.h>
69 #include <rmsdef.h>
70 #include <fab.h>
71 #include <nam.h>
72 #endif
73
74 #include "systime.h"
75
76 #ifdef HPUX
77 #include <netio.h>
78 #ifndef HPUX8
79 #include <errnet.h>
80 #endif
81 #endif
82
83 #ifndef O_WRONLY
84 #define O_WRONLY 1
85 #endif
86
87 #define min(a, b) ((a) < (b) ? (a) : (b))
88 #define max(a, b) ((a) > (b) ? (a) : (b))
89
90 /* Nonzero during writing of auto-save files */
91 int auto_saving;
92
93 /* Set by auto_save_1 to mode of original file so Fwrite_region will create
94 a new file with the same mode as the original */
95 int auto_save_mode_bits;
96
97 /* Alist of elements (REGEXP . HANDLER) for file names
98 whose I/O is done with a special handler. */
99 Lisp_Object Vfile_name_handler_alist;
100
101 /* Nonzero means, when reading a filename in the minibuffer,
102 start out by inserting the default directory into the minibuffer. */
103 int insert_default_directory;
104
105 /* On VMS, nonzero means write new files with record format stmlf.
106 Zero means use var format. */
107 int vms_stmlf_recfm;
108
109 Lisp_Object Qfile_error, Qfile_already_exists;
110
111 Lisp_Object Qfile_name_history;
112
113 report_file_error (string, data)
114 char *string;
115 Lisp_Object data;
116 {
117 Lisp_Object errstring;
118
119 if (errno >= 0 && errno < sys_nerr)
120 errstring = build_string (sys_errlist[errno]);
121 else
122 errstring = build_string ("undocumented error code");
123
124 /* System error messages are capitalized. Downcase the initial
125 unless it is followed by a slash. */
126 if (XSTRING (errstring)->data[1] != '/')
127 XSTRING (errstring)->data[0] = DOWNCASE (XSTRING (errstring)->data[0]);
128
129 while (1)
130 Fsignal (Qfile_error,
131 Fcons (build_string (string), Fcons (errstring, data)));
132 }
133
134 close_file_unwind (fd)
135 Lisp_Object fd;
136 {
137 close (XFASTINT (fd));
138 }
139 \f
140 Lisp_Object Qexpand_file_name;
141 Lisp_Object Qdirectory_file_name;
142 Lisp_Object Qfile_name_directory;
143 Lisp_Object Qfile_name_nondirectory;
144 Lisp_Object Qunhandled_file_name_directory;
145 Lisp_Object Qfile_name_as_directory;
146 Lisp_Object Qcopy_file;
147 Lisp_Object Qmake_directory;
148 Lisp_Object Qdelete_directory;
149 Lisp_Object Qdelete_file;
150 Lisp_Object Qrename_file;
151 Lisp_Object Qadd_name_to_file;
152 Lisp_Object Qmake_symbolic_link;
153 Lisp_Object Qfile_exists_p;
154 Lisp_Object Qfile_executable_p;
155 Lisp_Object Qfile_readable_p;
156 Lisp_Object Qfile_symlink_p;
157 Lisp_Object Qfile_writable_p;
158 Lisp_Object Qfile_directory_p;
159 Lisp_Object Qfile_accessible_directory_p;
160 Lisp_Object Qfile_modes;
161 Lisp_Object Qset_file_modes;
162 Lisp_Object Qfile_newer_than_file_p;
163 Lisp_Object Qinsert_file_contents;
164 Lisp_Object Qwrite_region;
165 Lisp_Object Qverify_visited_file_modtime;
166
167 DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 1, 1, 0,
168 "Return FILENAME's handler function, if its syntax is handled specially.\n\
169 Otherwise, return nil.\n\
170 A file name is handled if one of the regular expressions in\n\
171 `file-name-handler-alist' matches it.")
172 (filename)
173 Lisp_Object filename;
174 {
175 /* This function must not munge the match data. */
176
177 Lisp_Object chain;
178 for (chain = Vfile_name_handler_alist; XTYPE (chain) == Lisp_Cons;
179 chain = XCONS (chain)->cdr)
180 {
181 Lisp_Object elt;
182 elt = XCONS (chain)->car;
183 if (XTYPE (elt) == Lisp_Cons)
184 {
185 Lisp_Object string;
186 string = XCONS (elt)->car;
187 if (XTYPE (string) == Lisp_String
188 && fast_string_match (string, filename) >= 0)
189 return XCONS (elt)->cdr;
190 }
191
192 QUIT;
193 }
194 return Qnil;
195 }
196 \f
197 DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory,
198 1, 1, 0,
199 "Return the directory component in file name NAME.\n\
200 Return nil if NAME does not include a directory.\n\
201 Otherwise return a directory spec.\n\
202 Given a Unix syntax file name, returns a string ending in slash;\n\
203 on VMS, perhaps instead a string ending in `:', `]' or `>'.")
204 (file)
205 Lisp_Object file;
206 {
207 register unsigned char *beg;
208 register unsigned char *p;
209 Lisp_Object handler;
210
211 CHECK_STRING (file, 0);
212
213 /* If the file name has special constructs in it,
214 call the corresponding file handler. */
215 handler = Ffind_file_name_handler (file);
216 if (!NILP (handler))
217 return call2 (handler, Qfile_name_directory, file);
218
219 beg = XSTRING (file)->data;
220 p = beg + XSTRING (file)->size;
221
222 while (p != beg && p[-1] != '/'
223 #ifdef VMS
224 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
225 #endif /* VMS */
226 ) p--;
227
228 if (p == beg)
229 return Qnil;
230 return make_string (beg, p - beg);
231 }
232
233 DEFUN ("file-name-nondirectory", Ffile_name_nondirectory, Sfile_name_nondirectory,
234 1, 1, 0,
235 "Return file name NAME sans its directory.\n\
236 For example, in a Unix-syntax file name,\n\
237 this is everything after the last slash,\n\
238 or the entire name if it contains no slash.")
239 (file)
240 Lisp_Object file;
241 {
242 register unsigned char *beg, *p, *end;
243 Lisp_Object handler;
244
245 CHECK_STRING (file, 0);
246
247 /* If the file name has special constructs in it,
248 call the corresponding file handler. */
249 handler = Ffind_file_name_handler (file);
250 if (!NILP (handler))
251 return call2 (handler, Qfile_name_nondirectory, file);
252
253 beg = XSTRING (file)->data;
254 end = p = beg + XSTRING (file)->size;
255
256 while (p != beg && p[-1] != '/'
257 #ifdef VMS
258 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
259 #endif /* VMS */
260 ) p--;
261
262 return make_string (p, end - p);
263 }
264
265 DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory, Sunhandled_file_name_directory, 1, 1, 0,
266 "Return a directly usable directory name somehow associated with FILENAME.\n\
267 A `directly usable' directory name is one that may be used without the\n\
268 intervention of any file handler.\n\
269 If FILENAME is a directly usable file itself, return\n\
270 (file-name-directory FILENAME).\n\
271 The `call-process' and `start-process' functions use this function to\n\
272 get a current directory to run processes in.")
273 (filename)
274 Lisp_Object filename;
275 {
276 Lisp_Object handler;
277
278 /* If the file name has special constructs in it,
279 call the corresponding file handler. */
280 handler = Ffind_file_name_handler (filename);
281 if (!NILP (handler))
282 return call2 (handler, Qunhandled_file_name_directory, filename);
283
284 return Ffile_name_directory (filename);
285 }
286
287 \f
288 char *
289 file_name_as_directory (out, in)
290 char *out, *in;
291 {
292 int size = strlen (in) - 1;
293
294 strcpy (out, in);
295
296 #ifdef VMS
297 /* Is it already a directory string? */
298 if (in[size] == ':' || in[size] == ']' || in[size] == '>')
299 return out;
300 /* Is it a VMS directory file name? If so, hack VMS syntax. */
301 else if (! index (in, '/')
302 && ((size > 3 && ! strcmp (&in[size - 3], ".DIR"))
303 || (size > 3 && ! strcmp (&in[size - 3], ".dir"))
304 || (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4)
305 || ! strncmp (&in[size - 5], ".dir", 4))
306 && (in[size - 1] == '.' || in[size - 1] == ';')
307 && in[size] == '1')))
308 {
309 register char *p, *dot;
310 char brack;
311
312 /* x.dir -> [.x]
313 dir:x.dir --> dir:[x]
314 dir:[x]y.dir --> dir:[x.y] */
315 p = in + size;
316 while (p != in && *p != ':' && *p != '>' && *p != ']') p--;
317 if (p != in)
318 {
319 strncpy (out, in, p - in);
320 out[p - in] = '\0';
321 if (*p == ':')
322 {
323 brack = ']';
324 strcat (out, ":[");
325 }
326 else
327 {
328 brack = *p;
329 strcat (out, ".");
330 }
331 p++;
332 }
333 else
334 {
335 brack = ']';
336 strcpy (out, "[.");
337 }
338 dot = index (p, '.');
339 if (dot)
340 {
341 /* blindly remove any extension */
342 size = strlen (out) + (dot - p);
343 strncat (out, p, dot - p);
344 }
345 else
346 {
347 strcat (out, p);
348 size = strlen (out);
349 }
350 out[size++] = brack;
351 out[size] = '\0';
352 }
353 #else /* not VMS */
354 /* For Unix syntax, Append a slash if necessary */
355 if (out[size] != '/')
356 strcat (out, "/");
357 #endif /* not VMS */
358 return out;
359 }
360
361 DEFUN ("file-name-as-directory", Ffile_name_as_directory,
362 Sfile_name_as_directory, 1, 1, 0,
363 "Return a string representing file FILENAME interpreted as a directory.\n\
364 This operation exists because a directory is also a file, but its name as\n\
365 a directory is different from its name as a file.\n\
366 The result can be used as the value of `default-directory'\n\
367 or passed as second argument to `expand-file-name'.\n\
368 For a Unix-syntax file name, just appends a slash.\n\
369 On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
370 (file)
371 Lisp_Object file;
372 {
373 char *buf;
374 Lisp_Object handler;
375
376 CHECK_STRING (file, 0);
377 if (NILP (file))
378 return Qnil;
379
380 /* If the file name has special constructs in it,
381 call the corresponding file handler. */
382 handler = Ffind_file_name_handler (file);
383 if (!NILP (handler))
384 return call2 (handler, Qfile_name_as_directory, file);
385
386 buf = (char *) alloca (XSTRING (file)->size + 10);
387 return build_string (file_name_as_directory (buf, XSTRING (file)->data));
388 }
389 \f
390 /*
391 * Convert from directory name to filename.
392 * On VMS:
393 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
394 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
395 * On UNIX, it's simple: just make sure there is a terminating /
396
397 * Value is nonzero if the string output is different from the input.
398 */
399
400 directory_file_name (src, dst)
401 char *src, *dst;
402 {
403 long slen;
404 #ifdef VMS
405 long rlen;
406 char * ptr, * rptr;
407 char bracket;
408 struct FAB fab = cc$rms_fab;
409 struct NAM nam = cc$rms_nam;
410 char esa[NAM$C_MAXRSS];
411 #endif /* VMS */
412
413 slen = strlen (src);
414 #ifdef VMS
415 if (! index (src, '/')
416 && (src[slen - 1] == ']'
417 || src[slen - 1] == ':'
418 || src[slen - 1] == '>'))
419 {
420 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
421 fab.fab$l_fna = src;
422 fab.fab$b_fns = slen;
423 fab.fab$l_nam = &nam;
424 fab.fab$l_fop = FAB$M_NAM;
425
426 nam.nam$l_esa = esa;
427 nam.nam$b_ess = sizeof esa;
428 nam.nam$b_nop |= NAM$M_SYNCHK;
429
430 /* We call SYS$PARSE to handle such things as [--] for us. */
431 if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
432 {
433 slen = nam.nam$b_esl;
434 if (esa[slen - 1] == ';' && esa[slen - 2] == '.')
435 slen -= 2;
436 esa[slen] = '\0';
437 src = esa;
438 }
439 if (src[slen - 1] != ']' && src[slen - 1] != '>')
440 {
441 /* what about when we have logical_name:???? */
442 if (src[slen - 1] == ':')
443 { /* Xlate logical name and see what we get */
444 ptr = strcpy (dst, src); /* upper case for getenv */
445 while (*ptr)
446 {
447 if ('a' <= *ptr && *ptr <= 'z')
448 *ptr -= 040;
449 ptr++;
450 }
451 dst[slen - 1] = 0; /* remove colon */
452 if (!(src = egetenv (dst)))
453 return 0;
454 /* should we jump to the beginning of this procedure?
455 Good points: allows us to use logical names that xlate
456 to Unix names,
457 Bad points: can be a problem if we just translated to a device
458 name...
459 For now, I'll punt and always expect VMS names, and hope for
460 the best! */
461 slen = strlen (src);
462 if (src[slen - 1] != ']' && src[slen - 1] != '>')
463 { /* no recursion here! */
464 strcpy (dst, src);
465 return 0;
466 }
467 }
468 else
469 { /* not a directory spec */
470 strcpy (dst, src);
471 return 0;
472 }
473 }
474 bracket = src[slen - 1];
475
476 /* If bracket is ']' or '>', bracket - 2 is the corresponding
477 opening bracket. */
478 ptr = index (src, bracket - 2);
479 if (ptr == 0)
480 { /* no opening bracket */
481 strcpy (dst, src);
482 return 0;
483 }
484 if (!(rptr = rindex (src, '.')))
485 rptr = ptr;
486 slen = rptr - src;
487 strncpy (dst, src, slen);
488 dst[slen] = '\0';
489 if (*rptr == '.')
490 {
491 dst[slen++] = bracket;
492 dst[slen] = '\0';
493 }
494 else
495 {
496 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
497 then translate the device and recurse. */
498 if (dst[slen - 1] == ':'
499 && dst[slen - 2] != ':' /* skip decnet nodes */
500 && strcmp(src + slen, "[000000]") == 0)
501 {
502 dst[slen - 1] = '\0';
503 if ((ptr = egetenv (dst))
504 && (rlen = strlen (ptr) - 1) > 0
505 && (ptr[rlen] == ']' || ptr[rlen] == '>')
506 && ptr[rlen - 1] == '.')
507 {
508 char * buf = (char *) alloca (strlen (ptr) + 1);
509 strcpy (buf, ptr);
510 buf[rlen - 1] = ']';
511 buf[rlen] = '\0';
512 return directory_file_name (buf, dst);
513 }
514 else
515 dst[slen - 1] = ':';
516 }
517 strcat (dst, "[000000]");
518 slen += 8;
519 }
520 rptr++;
521 rlen = strlen (rptr) - 1;
522 strncat (dst, rptr, rlen);
523 dst[slen + rlen] = '\0';
524 strcat (dst, ".DIR.1");
525 return 1;
526 }
527 #endif /* VMS */
528 /* Process as Unix format: just remove any final slash.
529 But leave "/" unchanged; do not change it to "". */
530 strcpy (dst, src);
531 if (slen > 1 && dst[slen - 1] == '/')
532 dst[slen - 1] = 0;
533 return 1;
534 }
535
536 DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name,
537 1, 1, 0,
538 "Returns the file name of the directory named DIR.\n\
539 This is the name of the file that holds the data for the directory DIR.\n\
540 This operation exists because a directory is also a file, but its name as\n\
541 a directory is different from its name as a file.\n\
542 In Unix-syntax, this function just removes the final slash.\n\
543 On VMS, given a VMS-syntax directory name such as \"[X.Y]\",\n\
544 it returns a file name such as \"[X]Y.DIR.1\".")
545 (directory)
546 Lisp_Object directory;
547 {
548 char *buf;
549 Lisp_Object handler;
550
551 CHECK_STRING (directory, 0);
552
553 if (NILP (directory))
554 return Qnil;
555
556 /* If the file name has special constructs in it,
557 call the corresponding file handler. */
558 handler = Ffind_file_name_handler (directory);
559 if (!NILP (handler))
560 return call2 (handler, Qdirectory_file_name, directory);
561
562 #ifdef VMS
563 /* 20 extra chars is insufficient for VMS, since we might perform a
564 logical name translation. an equivalence string can be up to 255
565 chars long, so grab that much extra space... - sss */
566 buf = (char *) alloca (XSTRING (directory)->size + 20 + 255);
567 #else
568 buf = (char *) alloca (XSTRING (directory)->size + 20);
569 #endif
570 directory_file_name (XSTRING (directory)->data, buf);
571 return build_string (buf);
572 }
573
574 DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0,
575 "Generate temporary file name (string) starting with PREFIX (a string).\n\
576 The Emacs process number forms part of the result,\n\
577 so there is no danger of generating a name being used by another process.")
578 (prefix)
579 Lisp_Object prefix;
580 {
581 Lisp_Object val;
582 val = concat2 (prefix, build_string ("XXXXXX"));
583 mktemp (XSTRING (val)->data);
584 return val;
585 }
586 \f
587 DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
588 "Convert FILENAME to absolute, and canonicalize it.\n\
589 Second arg DEFAULT is directory to start with if FILENAME is relative\n\
590 (does not start with slash); if DEFAULT is nil or missing,\n\
591 the current buffer's value of default-directory is used.\n\
592 Path components that are `.' are removed, and \n\
593 path components followed by `..' are removed, along with the `..' itself;\n\
594 note that these simplifications are done without checking the resulting\n\
595 paths in the file system.\n\
596 An initial `~/' expands to your home directory.\n\
597 An initial `~USER/' expands to USER's home directory.\n\
598 See also the function `substitute-in-file-name'.")
599 (name, defalt)
600 Lisp_Object name, defalt;
601 {
602 unsigned char *nm;
603
604 register unsigned char *newdir, *p, *o;
605 int tlen;
606 unsigned char *target;
607 struct passwd *pw;
608 #ifdef VMS
609 unsigned char * colon = 0;
610 unsigned char * close = 0;
611 unsigned char * slash = 0;
612 unsigned char * brack = 0;
613 int lbrack = 0, rbrack = 0;
614 int dots = 0;
615 #endif /* VMS */
616 Lisp_Object handler;
617
618 CHECK_STRING (name, 0);
619
620 /* If the file name has special constructs in it,
621 call the corresponding file handler. */
622 handler = Ffind_file_name_handler (name);
623 if (!NILP (handler))
624 return call3 (handler, Qexpand_file_name, name, defalt);
625
626 /* Make sure DEFALT is properly expanded.
627 It would be better to do this down below where we actually use
628 defalt. Unfortunately, calling Fexpand_file_name recursively
629 could invoke GC, and the strings might be relocated. This would
630 be annoying because we have pointers into strings lying around
631 that would need adjusting, and people would add new pointers to
632 the code and forget to adjust them, resulting in intermittent bugs.
633 Putting this call here avoids all that crud. */
634 if (! NILP (defalt))
635 {
636 struct gcpro gcpro1;
637
638 GCPRO1 (name);
639 defalt = Fexpand_file_name (defalt, Qnil);
640 UNGCPRO;
641 }
642
643 #ifdef VMS
644 /* Filenames on VMS are always upper case. */
645 name = Fupcase (name);
646 #endif
647
648 nm = XSTRING (name)->data;
649
650 /* If nm is absolute, flush ...// and detect /./ and /../.
651 If no /./ or /../ we can return right away. */
652 if (
653 nm[0] == '/'
654 #ifdef VMS
655 || index (nm, ':')
656 #endif /* VMS */
657 )
658 {
659 /* If it turns out that the filename we want to return is just a
660 suffix of FILENAME, we don't need to go through and edit
661 things; we just need to construct a new string using data
662 starting at the middle of FILENAME. If we set lose to a
663 non-zero value, that means we've discovered that we can't do
664 that cool trick. */
665 int lose = 0;
666
667 p = nm;
668 while (*p)
669 {
670 /* Since we know the path is absolute, we can assume that each
671 element starts with a "/". */
672
673 /* "//" anywhere isn't necessarily hairy; we just start afresh
674 with the second slash. */
675 if (p[0] == '/' && p[1] == '/'
676 #ifdef APOLLO
677 /* // at start of filename is meaningful on Apollo system */
678 && nm != p
679 #endif /* APOLLO */
680 )
681 nm = p + 1;
682
683 /* "~" is hairy as the start of any path element. */
684 if (p[0] == '/' && p[1] == '~')
685 nm = p + 1, lose = 1;
686
687 /* "." and ".." are hairy. */
688 if (p[0] == '/'
689 && p[1] == '.'
690 && (p[2] == '/'
691 || p[2] == 0
692 || (p[2] == '.' && (p[3] == '/'
693 || p[3] == 0))))
694 lose = 1;
695 #ifdef VMS
696 if (p[0] == '\\')
697 lose = 1;
698 if (p[0] == '/') {
699 /* if dev:[dir]/, move nm to / */
700 if (!slash && p > nm && (brack || colon)) {
701 nm = (brack ? brack + 1 : colon + 1);
702 lbrack = rbrack = 0;
703 brack = 0;
704 colon = 0;
705 }
706 slash = p;
707 }
708 if (p[0] == '-')
709 #ifndef VMS4_4
710 /* VMS pre V4.4,convert '-'s in filenames. */
711 if (lbrack == rbrack)
712 {
713 if (dots < 2) /* this is to allow negative version numbers */
714 p[0] = '_';
715 }
716 else
717 #endif /* VMS4_4 */
718 if (lbrack > rbrack &&
719 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
720 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
721 lose = 1;
722 #ifndef VMS4_4
723 else
724 p[0] = '_';
725 #endif /* VMS4_4 */
726 /* count open brackets, reset close bracket pointer */
727 if (p[0] == '[' || p[0] == '<')
728 lbrack++, brack = 0;
729 /* count close brackets, set close bracket pointer */
730 if (p[0] == ']' || p[0] == '>')
731 rbrack++, brack = p;
732 /* detect ][ or >< */
733 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
734 lose = 1;
735 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
736 nm = p + 1, lose = 1;
737 if (p[0] == ':' && (colon || slash))
738 /* if dev1:[dir]dev2:, move nm to dev2: */
739 if (brack)
740 {
741 nm = brack + 1;
742 brack = 0;
743 }
744 /* if /pathname/dev:, move nm to dev: */
745 else if (slash)
746 nm = slash + 1;
747 /* if node::dev:, move colon following dev */
748 else if (colon && colon[-1] == ':')
749 colon = p;
750 /* if dev1:dev2:, move nm to dev2: */
751 else if (colon && colon[-1] != ':')
752 {
753 nm = colon + 1;
754 colon = 0;
755 }
756 if (p[0] == ':' && !colon)
757 {
758 if (p[1] == ':')
759 p++;
760 colon = p;
761 }
762 if (lbrack == rbrack)
763 if (p[0] == ';')
764 dots = 2;
765 else if (p[0] == '.')
766 dots++;
767 #endif /* VMS */
768 p++;
769 }
770 if (!lose)
771 {
772 #ifdef VMS
773 if (index (nm, '/'))
774 return build_string (sys_translate_unix (nm));
775 #endif /* VMS */
776 if (nm == XSTRING (name)->data)
777 return name;
778 return build_string (nm);
779 }
780 }
781
782 /* Now determine directory to start with and put it in newdir */
783
784 newdir = 0;
785
786 if (nm[0] == '~') /* prefix ~ */
787 {
788 if (nm[1] == '/'
789 #ifdef VMS
790 || nm[1] == ':'
791 #endif /* VMS */
792 || nm[1] == 0) /* ~ by itself */
793 {
794 if (!(newdir = (unsigned char *) egetenv ("HOME")))
795 newdir = (unsigned char *) "";
796 nm++;
797 #ifdef VMS
798 nm++; /* Don't leave the slash in nm. */
799 #endif /* VMS */
800 }
801 else /* ~user/filename */
802 {
803 for (p = nm; *p && (*p != '/'
804 #ifdef VMS
805 && *p != ':'
806 #endif /* VMS */
807 ); p++);
808 o = (unsigned char *) alloca (p - nm + 1);
809 bcopy ((char *) nm, o, p - nm);
810 o [p - nm] = 0;
811
812 pw = (struct passwd *) getpwnam (o + 1);
813 if (pw)
814 {
815 newdir = (unsigned char *) pw -> pw_dir;
816 #ifdef VMS
817 nm = p + 1; /* skip the terminator */
818 #else
819 nm = p;
820 #endif /* VMS */
821 }
822
823 /* If we don't find a user of that name, leave the name
824 unchanged; don't move nm forward to p. */
825 }
826 }
827
828 if (nm[0] != '/'
829 #ifdef VMS
830 && !index (nm, ':')
831 #endif /* not VMS */
832 && !newdir)
833 {
834 if (NILP (defalt))
835 defalt = current_buffer->directory;
836 CHECK_STRING (defalt, 1);
837 newdir = XSTRING (defalt)->data;
838 }
839
840 if (newdir != 0)
841 {
842 /* Get rid of any slash at the end of newdir. */
843 int length = strlen (newdir);
844 if (newdir[length - 1] == '/')
845 {
846 unsigned char *temp = (unsigned char *) alloca (length);
847 bcopy (newdir, temp, length - 1);
848 temp[length - 1] = 0;
849 newdir = temp;
850 }
851 tlen = length + 1;
852 }
853 else
854 tlen = 0;
855
856 /* Now concatenate the directory and name to new space in the stack frame */
857 tlen += strlen (nm) + 1;
858 target = (unsigned char *) alloca (tlen);
859 *target = 0;
860
861 if (newdir)
862 {
863 #ifndef VMS
864 if (nm[0] == 0 || nm[0] == '/')
865 strcpy (target, newdir);
866 else
867 #endif
868 file_name_as_directory (target, newdir);
869 }
870
871 strcat (target, nm);
872 #ifdef VMS
873 if (index (target, '/'))
874 strcpy (target, sys_translate_unix (target));
875 #endif /* VMS */
876
877 /* Now canonicalize by removing /. and /foo/.. if they appear. */
878
879 p = target;
880 o = target;
881
882 while (*p)
883 {
884 #ifdef VMS
885 if (*p != ']' && *p != '>' && *p != '-')
886 {
887 if (*p == '\\')
888 p++;
889 *o++ = *p++;
890 }
891 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
892 /* brackets are offset from each other by 2 */
893 {
894 p += 2;
895 if (*p != '.' && *p != '-' && o[-1] != '.')
896 /* convert [foo][bar] to [bar] */
897 while (o[-1] != '[' && o[-1] != '<')
898 o--;
899 else if (*p == '-' && *o != '.')
900 *--p = '.';
901 }
902 else if (p[0] == '-' && o[-1] == '.' &&
903 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
904 /* flush .foo.- ; leave - if stopped by '[' or '<' */
905 {
906 do
907 o--;
908 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
909 if (p[1] == '.') /* foo.-.bar ==> bar*/
910 p += 2;
911 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
912 p++, o--;
913 /* else [foo.-] ==> [-] */
914 }
915 else
916 {
917 #ifndef VMS4_4
918 if (*p == '-' &&
919 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
920 p[1] != ']' && p[1] != '>' && p[1] != '.')
921 *p = '_';
922 #endif /* VMS4_4 */
923 *o++ = *p++;
924 }
925 #else /* not VMS */
926 if (*p != '/')
927 {
928 *o++ = *p++;
929 }
930 else if (!strncmp (p, "//", 2)
931 #ifdef APOLLO
932 /* // at start of filename is meaningful in Apollo system */
933 && o != target
934 #endif /* APOLLO */
935 )
936 {
937 o = target;
938 p++;
939 }
940 else if (p[0] == '/'
941 && p[1] == '.'
942 && (p[2] == '/'
943 || p[2] == 0))
944 {
945 /* If "/." is the entire filename, keep the "/". Otherwise,
946 just delete the whole "/.". */
947 if (o == target && p[2] == '\0')
948 *o++ = *p;
949 p += 2;
950 }
951 else if (!strncmp (p, "/..", 3)
952 /* `/../' is the "superroot" on certain file systems. */
953 && o != target
954 && (p[3] == '/' || p[3] == 0))
955 {
956 while (o != target && *--o != '/')
957 ;
958 #ifdef APOLLO
959 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
960 ++o;
961 else
962 #endif /* APOLLO */
963 if (o == target && *o == '/')
964 ++o;
965 p += 3;
966 }
967 else
968 {
969 *o++ = *p++;
970 }
971 #endif /* not VMS */
972 }
973
974 return make_string (target, o - target);
975 }
976 #if 0
977 /* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'.
978 DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
979 "Convert FILENAME to absolute, and canonicalize it.\n\
980 Second arg DEFAULT is directory to start with if FILENAME is relative\n\
981 (does not start with slash); if DEFAULT is nil or missing,\n\
982 the current buffer's value of default-directory is used.\n\
983 Filenames containing `.' or `..' as components are simplified;\n\
984 initial `~/' expands to your home directory.\n\
985 See also the function `substitute-in-file-name'.")
986 (name, defalt)
987 Lisp_Object name, defalt;
988 {
989 unsigned char *nm;
990
991 register unsigned char *newdir, *p, *o;
992 int tlen;
993 unsigned char *target;
994 struct passwd *pw;
995 int lose;
996 #ifdef VMS
997 unsigned char * colon = 0;
998 unsigned char * close = 0;
999 unsigned char * slash = 0;
1000 unsigned char * brack = 0;
1001 int lbrack = 0, rbrack = 0;
1002 int dots = 0;
1003 #endif /* VMS */
1004
1005 CHECK_STRING (name, 0);
1006
1007 #ifdef VMS
1008 /* Filenames on VMS are always upper case. */
1009 name = Fupcase (name);
1010 #endif
1011
1012 nm = XSTRING (name)->data;
1013
1014 /* If nm is absolute, flush ...// and detect /./ and /../.
1015 If no /./ or /../ we can return right away. */
1016 if (
1017 nm[0] == '/'
1018 #ifdef VMS
1019 || index (nm, ':')
1020 #endif /* VMS */
1021 )
1022 {
1023 p = nm;
1024 lose = 0;
1025 while (*p)
1026 {
1027 if (p[0] == '/' && p[1] == '/'
1028 #ifdef APOLLO
1029 /* // at start of filename is meaningful on Apollo system */
1030 && nm != p
1031 #endif /* APOLLO */
1032 )
1033 nm = p + 1;
1034 if (p[0] == '/' && p[1] == '~')
1035 nm = p + 1, lose = 1;
1036 if (p[0] == '/' && p[1] == '.'
1037 && (p[2] == '/' || p[2] == 0
1038 || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
1039 lose = 1;
1040 #ifdef VMS
1041 if (p[0] == '\\')
1042 lose = 1;
1043 if (p[0] == '/') {
1044 /* if dev:[dir]/, move nm to / */
1045 if (!slash && p > nm && (brack || colon)) {
1046 nm = (brack ? brack + 1 : colon + 1);
1047 lbrack = rbrack = 0;
1048 brack = 0;
1049 colon = 0;
1050 }
1051 slash = p;
1052 }
1053 if (p[0] == '-')
1054 #ifndef VMS4_4
1055 /* VMS pre V4.4,convert '-'s in filenames. */
1056 if (lbrack == rbrack)
1057 {
1058 if (dots < 2) /* this is to allow negative version numbers */
1059 p[0] = '_';
1060 }
1061 else
1062 #endif /* VMS4_4 */
1063 if (lbrack > rbrack &&
1064 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
1065 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
1066 lose = 1;
1067 #ifndef VMS4_4
1068 else
1069 p[0] = '_';
1070 #endif /* VMS4_4 */
1071 /* count open brackets, reset close bracket pointer */
1072 if (p[0] == '[' || p[0] == '<')
1073 lbrack++, brack = 0;
1074 /* count close brackets, set close bracket pointer */
1075 if (p[0] == ']' || p[0] == '>')
1076 rbrack++, brack = p;
1077 /* detect ][ or >< */
1078 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
1079 lose = 1;
1080 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
1081 nm = p + 1, lose = 1;
1082 if (p[0] == ':' && (colon || slash))
1083 /* if dev1:[dir]dev2:, move nm to dev2: */
1084 if (brack)
1085 {
1086 nm = brack + 1;
1087 brack = 0;
1088 }
1089 /* if /pathname/dev:, move nm to dev: */
1090 else if (slash)
1091 nm = slash + 1;
1092 /* if node::dev:, move colon following dev */
1093 else if (colon && colon[-1] == ':')
1094 colon = p;
1095 /* if dev1:dev2:, move nm to dev2: */
1096 else if (colon && colon[-1] != ':')
1097 {
1098 nm = colon + 1;
1099 colon = 0;
1100 }
1101 if (p[0] == ':' && !colon)
1102 {
1103 if (p[1] == ':')
1104 p++;
1105 colon = p;
1106 }
1107 if (lbrack == rbrack)
1108 if (p[0] == ';')
1109 dots = 2;
1110 else if (p[0] == '.')
1111 dots++;
1112 #endif /* VMS */
1113 p++;
1114 }
1115 if (!lose)
1116 {
1117 #ifdef VMS
1118 if (index (nm, '/'))
1119 return build_string (sys_translate_unix (nm));
1120 #endif /* VMS */
1121 if (nm == XSTRING (name)->data)
1122 return name;
1123 return build_string (nm);
1124 }
1125 }
1126
1127 /* Now determine directory to start with and put it in NEWDIR */
1128
1129 newdir = 0;
1130
1131 if (nm[0] == '~') /* prefix ~ */
1132 if (nm[1] == '/'
1133 #ifdef VMS
1134 || nm[1] == ':'
1135 #endif /* VMS */
1136 || nm[1] == 0)/* ~/filename */
1137 {
1138 if (!(newdir = (unsigned char *) egetenv ("HOME")))
1139 newdir = (unsigned char *) "";
1140 nm++;
1141 #ifdef VMS
1142 nm++; /* Don't leave the slash in nm. */
1143 #endif /* VMS */
1144 }
1145 else /* ~user/filename */
1146 {
1147 /* Get past ~ to user */
1148 unsigned char *user = nm + 1;
1149 /* Find end of name. */
1150 unsigned char *ptr = (unsigned char *) index (user, '/');
1151 int len = ptr ? ptr - user : strlen (user);
1152 #ifdef VMS
1153 unsigned char *ptr1 = index (user, ':');
1154 if (ptr1 != 0 && ptr1 - user < len)
1155 len = ptr1 - user;
1156 #endif /* VMS */
1157 /* Copy the user name into temp storage. */
1158 o = (unsigned char *) alloca (len + 1);
1159 bcopy ((char *) user, o, len);
1160 o[len] = 0;
1161
1162 /* Look up the user name. */
1163 pw = (struct passwd *) getpwnam (o + 1);
1164 if (!pw)
1165 error ("\"%s\" isn't a registered user", o + 1);
1166
1167 newdir = (unsigned char *) pw->pw_dir;
1168
1169 /* Discard the user name from NM. */
1170 nm += len;
1171 }
1172
1173 if (nm[0] != '/'
1174 #ifdef VMS
1175 && !index (nm, ':')
1176 #endif /* not VMS */
1177 && !newdir)
1178 {
1179 if (NILP (defalt))
1180 defalt = current_buffer->directory;
1181 CHECK_STRING (defalt, 1);
1182 newdir = XSTRING (defalt)->data;
1183 }
1184
1185 /* Now concatenate the directory and name to new space in the stack frame */
1186
1187 tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1;
1188 target = (unsigned char *) alloca (tlen);
1189 *target = 0;
1190
1191 if (newdir)
1192 {
1193 #ifndef VMS
1194 if (nm[0] == 0 || nm[0] == '/')
1195 strcpy (target, newdir);
1196 else
1197 #endif
1198 file_name_as_directory (target, newdir);
1199 }
1200
1201 strcat (target, nm);
1202 #ifdef VMS
1203 if (index (target, '/'))
1204 strcpy (target, sys_translate_unix (target));
1205 #endif /* VMS */
1206
1207 /* Now canonicalize by removing /. and /foo/.. if they appear */
1208
1209 p = target;
1210 o = target;
1211
1212 while (*p)
1213 {
1214 #ifdef VMS
1215 if (*p != ']' && *p != '>' && *p != '-')
1216 {
1217 if (*p == '\\')
1218 p++;
1219 *o++ = *p++;
1220 }
1221 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
1222 /* brackets are offset from each other by 2 */
1223 {
1224 p += 2;
1225 if (*p != '.' && *p != '-' && o[-1] != '.')
1226 /* convert [foo][bar] to [bar] */
1227 while (o[-1] != '[' && o[-1] != '<')
1228 o--;
1229 else if (*p == '-' && *o != '.')
1230 *--p = '.';
1231 }
1232 else if (p[0] == '-' && o[-1] == '.' &&
1233 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1234 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1235 {
1236 do
1237 o--;
1238 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1239 if (p[1] == '.') /* foo.-.bar ==> bar*/
1240 p += 2;
1241 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1242 p++, o--;
1243 /* else [foo.-] ==> [-] */
1244 }
1245 else
1246 {
1247 #ifndef VMS4_4
1248 if (*p == '-' &&
1249 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
1250 p[1] != ']' && p[1] != '>' && p[1] != '.')
1251 *p = '_';
1252 #endif /* VMS4_4 */
1253 *o++ = *p++;
1254 }
1255 #else /* not VMS */
1256 if (*p != '/')
1257 {
1258 *o++ = *p++;
1259 }
1260 else if (!strncmp (p, "//", 2)
1261 #ifdef APOLLO
1262 /* // at start of filename is meaningful in Apollo system */
1263 && o != target
1264 #endif /* APOLLO */
1265 )
1266 {
1267 o = target;
1268 p++;
1269 }
1270 else if (p[0] == '/' && p[1] == '.' &&
1271 (p[2] == '/' || p[2] == 0))
1272 p += 2;
1273 else if (!strncmp (p, "/..", 3)
1274 /* `/../' is the "superroot" on certain file systems. */
1275 && o != target
1276 && (p[3] == '/' || p[3] == 0))
1277 {
1278 while (o != target && *--o != '/')
1279 ;
1280 #ifdef APOLLO
1281 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
1282 ++o;
1283 else
1284 #endif /* APOLLO */
1285 if (o == target && *o == '/')
1286 ++o;
1287 p += 3;
1288 }
1289 else
1290 {
1291 *o++ = *p++;
1292 }
1293 #endif /* not VMS */
1294 }
1295
1296 return make_string (target, o - target);
1297 }
1298 #endif
1299 \f
1300 DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name,
1301 Ssubstitute_in_file_name, 1, 1, 0,
1302 "Substitute environment variables referred to in FILENAME.\n\
1303 `$FOO' where FOO is an environment variable name means to substitute\n\
1304 the value of that variable. The variable name should be terminated\n\
1305 with a character not a letter, digit or underscore; otherwise, enclose\n\
1306 the entire variable name in braces.\n\
1307 If `/~' appears, all of FILENAME through that `/' is discarded.\n\n\
1308 On VMS, `$' substitution is not done; this function does little and only\n\
1309 duplicates what `expand-file-name' does.")
1310 (string)
1311 Lisp_Object string;
1312 {
1313 unsigned char *nm;
1314
1315 register unsigned char *s, *p, *o, *x, *endp;
1316 unsigned char *target;
1317 int total = 0;
1318 int substituted = 0;
1319 unsigned char *xnm;
1320
1321 CHECK_STRING (string, 0);
1322
1323 nm = XSTRING (string)->data;
1324 endp = nm + XSTRING (string)->size;
1325
1326 /* If /~ or // appears, discard everything through first slash. */
1327
1328 for (p = nm; p != endp; p++)
1329 {
1330 if ((p[0] == '~' ||
1331 #ifdef APOLLO
1332 /* // at start of file name is meaningful in Apollo system */
1333 (p[0] == '/' && p - 1 != nm)
1334 #else /* not APOLLO */
1335 p[0] == '/'
1336 #endif /* not APOLLO */
1337 )
1338 && p != nm &&
1339 #ifdef VMS
1340 (p[-1] == ':' || p[-1] == ']' || p[-1] == '>' ||
1341 #endif /* VMS */
1342 p[-1] == '/')
1343 #ifdef VMS
1344 )
1345 #endif /* VMS */
1346 {
1347 nm = p;
1348 substituted = 1;
1349 }
1350 }
1351
1352 #ifdef VMS
1353 return build_string (nm);
1354 #else
1355
1356 /* See if any variables are substituted into the string
1357 and find the total length of their values in `total' */
1358
1359 for (p = nm; p != endp;)
1360 if (*p != '$')
1361 p++;
1362 else
1363 {
1364 p++;
1365 if (p == endp)
1366 goto badsubst;
1367 else if (*p == '$')
1368 {
1369 /* "$$" means a single "$" */
1370 p++;
1371 total -= 1;
1372 substituted = 1;
1373 continue;
1374 }
1375 else if (*p == '{')
1376 {
1377 o = ++p;
1378 while (p != endp && *p != '}') p++;
1379 if (*p != '}') goto missingclose;
1380 s = p;
1381 }
1382 else
1383 {
1384 o = p;
1385 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1386 s = p;
1387 }
1388
1389 /* Copy out the variable name */
1390 target = (unsigned char *) alloca (s - o + 1);
1391 strncpy (target, o, s - o);
1392 target[s - o] = 0;
1393
1394 /* Get variable value */
1395 o = (unsigned char *) egetenv (target);
1396 /* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
1397 #if 0
1398 #ifdef USG
1399 if (!o && !strcmp (target, "USER"))
1400 o = egetenv ("LOGNAME");
1401 #endif /* USG */
1402 #endif /* 0 */
1403 if (!o) goto badvar;
1404 total += strlen (o);
1405 substituted = 1;
1406 }
1407
1408 if (!substituted)
1409 return string;
1410
1411 /* If substitution required, recopy the string and do it */
1412 /* Make space in stack frame for the new copy */
1413 xnm = (unsigned char *) alloca (XSTRING (string)->size + total + 1);
1414 x = xnm;
1415
1416 /* Copy the rest of the name through, replacing $ constructs with values */
1417 for (p = nm; *p;)
1418 if (*p != '$')
1419 *x++ = *p++;
1420 else
1421 {
1422 p++;
1423 if (p == endp)
1424 goto badsubst;
1425 else if (*p == '$')
1426 {
1427 *x++ = *p++;
1428 continue;
1429 }
1430 else if (*p == '{')
1431 {
1432 o = ++p;
1433 while (p != endp && *p != '}') p++;
1434 if (*p != '}') goto missingclose;
1435 s = p++;
1436 }
1437 else
1438 {
1439 o = p;
1440 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1441 s = p;
1442 }
1443
1444 /* Copy out the variable name */
1445 target = (unsigned char *) alloca (s - o + 1);
1446 strncpy (target, o, s - o);
1447 target[s - o] = 0;
1448
1449 /* Get variable value */
1450 o = (unsigned char *) egetenv (target);
1451 /* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
1452 #if 0
1453 #ifdef USG
1454 if (!o && !strcmp (target, "USER"))
1455 o = egetenv ("LOGNAME");
1456 #endif /* USG */
1457 #endif /* 0 */
1458 if (!o)
1459 goto badvar;
1460
1461 strcpy (x, o);
1462 x += strlen (o);
1463 }
1464
1465 *x = 0;
1466
1467 /* If /~ or // appears, discard everything through first slash. */
1468
1469 for (p = xnm; p != x; p++)
1470 if ((p[0] == '~' ||
1471 #ifdef APOLLO
1472 /* // at start of file name is meaningful in Apollo system */
1473 (p[0] == '/' && p - 1 != xnm)
1474 #else /* not APOLLO */
1475 p[0] == '/'
1476 #endif /* not APOLLO */
1477 )
1478 && p != nm && p[-1] == '/')
1479 xnm = p;
1480
1481 return make_string (xnm, x - xnm);
1482
1483 badsubst:
1484 error ("Bad format environment-variable substitution");
1485 missingclose:
1486 error ("Missing \"}\" in environment-variable substitution");
1487 badvar:
1488 error ("Substituting nonexistent environment variable \"%s\"", target);
1489
1490 /* NOTREACHED */
1491 #endif /* not VMS */
1492 }
1493 \f
1494 /* A slightly faster and more convenient way to get
1495 (directory-file-name (expand-file-name FOO)). The return value may
1496 have had its last character zapped with a '\0' character, meaning
1497 that it is acceptable to system calls, but not to other lisp
1498 functions. Callers should make sure that the return value doesn't
1499 escape. */
1500
1501 Lisp_Object
1502 expand_and_dir_to_file (filename, defdir)
1503 Lisp_Object filename, defdir;
1504 {
1505 register Lisp_Object abspath;
1506
1507 abspath = Fexpand_file_name (filename, defdir);
1508 #ifdef VMS
1509 {
1510 register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1];
1511 if (c == ':' || c == ']' || c == '>')
1512 abspath = Fdirectory_file_name (abspath);
1513 }
1514 #else
1515 /* Remove final slash, if any (unless path is root).
1516 stat behaves differently depending! */
1517 if (XSTRING (abspath)->size > 1
1518 && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/')
1519 {
1520 if (EQ (abspath, filename))
1521 abspath = Fcopy_sequence (abspath);
1522 XSTRING (abspath)->data[XSTRING (abspath)->size - 1] = 0;
1523 }
1524 #endif
1525 return abspath;
1526 }
1527 \f
1528 barf_or_query_if_file_exists (absname, querystring, interactive)
1529 Lisp_Object absname;
1530 unsigned char *querystring;
1531 int interactive;
1532 {
1533 register Lisp_Object tem;
1534 struct gcpro gcpro1;
1535
1536 if (access (XSTRING (absname)->data, 4) >= 0)
1537 {
1538 if (! interactive)
1539 Fsignal (Qfile_already_exists,
1540 Fcons (build_string ("File already exists"),
1541 Fcons (absname, Qnil)));
1542 GCPRO1 (absname);
1543 tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
1544 XSTRING (absname)->data, querystring));
1545 UNGCPRO;
1546 if (NILP (tem))
1547 Fsignal (Qfile_already_exists,
1548 Fcons (build_string ("File already exists"),
1549 Fcons (absname, Qnil)));
1550 }
1551 return;
1552 }
1553
1554 DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4,
1555 "fCopy file: \nFCopy %s to file: \np\nP",
1556 "Copy FILE to NEWNAME. Both args must be strings.\n\
1557 Signals a `file-already-exists' error if file NEWNAME already exists,\n\
1558 unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\
1559 A number as third arg means request confirmation if NEWNAME already exists.\n\
1560 This is what happens in interactive use with M-x.\n\
1561 Fourth arg KEEP-TIME non-nil means give the new file the same\n\
1562 last-modified time as the old one. (This works on only some systems.)\n\
1563 A prefix arg makes KEEP-TIME non-nil.")
1564 (filename, newname, ok_if_already_exists, keep_date)
1565 Lisp_Object filename, newname, ok_if_already_exists, keep_date;
1566 {
1567 int ifd, ofd, n;
1568 char buf[16 * 1024];
1569 struct stat st;
1570 Lisp_Object handler;
1571 struct gcpro gcpro1, gcpro2;
1572 int count = specpdl_ptr - specpdl;
1573
1574 GCPRO2 (filename, newname);
1575 CHECK_STRING (filename, 0);
1576 CHECK_STRING (newname, 1);
1577 filename = Fexpand_file_name (filename, Qnil);
1578 newname = Fexpand_file_name (newname, Qnil);
1579
1580 /* If the input file name has special constructs in it,
1581 call the corresponding file handler. */
1582 handler = Ffind_file_name_handler (filename);
1583 if (!NILP (handler))
1584 return call3 (handler, Qcopy_file, filename, newname);
1585 /* Likewise for output file name. */
1586 handler = Ffind_file_name_handler (newname);
1587 if (!NILP (handler))
1588 return call3 (handler, Qcopy_file, filename, newname);
1589
1590 if (NILP (ok_if_already_exists)
1591 || XTYPE (ok_if_already_exists) == Lisp_Int)
1592 barf_or_query_if_file_exists (newname, "copy to it",
1593 XTYPE (ok_if_already_exists) == Lisp_Int);
1594
1595 ifd = open (XSTRING (filename)->data, 0);
1596 if (ifd < 0)
1597 report_file_error ("Opening input file", Fcons (filename, Qnil));
1598
1599 record_unwind_protect (close_file_unwind, make_number (ifd));
1600
1601 #ifdef VMS
1602 /* Create the copy file with the same record format as the input file */
1603 ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
1604 #else
1605 ofd = creat (XSTRING (newname)->data, 0666);
1606 #endif /* VMS */
1607 if (ofd < 0)
1608 report_file_error ("Opening output file", Fcons (newname, Qnil));
1609
1610 record_unwind_protect (close_file_unwind, make_number (ofd));
1611
1612 immediate_quit = 1;
1613 QUIT;
1614 while ((n = read (ifd, buf, sizeof buf)) > 0)
1615 if (write (ofd, buf, n) != n)
1616 report_file_error ("I/O error", Fcons (newname, Qnil));
1617 immediate_quit = 0;
1618
1619 if (fstat (ifd, &st) >= 0)
1620 {
1621 if (!NILP (keep_date))
1622 {
1623 EMACS_TIME atime, mtime;
1624 EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
1625 EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
1626 EMACS_SET_UTIMES (XSTRING (newname)->data, atime, mtime);
1627 }
1628 #ifdef APOLLO
1629 if (!egetenv ("USE_DOMAIN_ACLS"))
1630 #endif
1631 chmod (XSTRING (newname)->data, st.st_mode & 07777);
1632 }
1633
1634 /* Discard the unwind protects. */
1635 specpdl_ptr = specpdl + count;
1636
1637 close (ifd);
1638 if (close (ofd) < 0)
1639 report_file_error ("I/O error", Fcons (newname, Qnil));
1640
1641 UNGCPRO;
1642 return Qnil;
1643 }
1644
1645 DEFUN ("make-directory-internal", Fmake_directory_internal,
1646 Smake_directory_internal, 1, 1, 0,
1647 "Create a directory. One argument, a file name string.")
1648 (dirname)
1649 Lisp_Object dirname;
1650 {
1651 unsigned char *dir;
1652 Lisp_Object handler;
1653
1654 CHECK_STRING (dirname, 0);
1655 dirname = Fexpand_file_name (dirname, Qnil);
1656
1657 handler = Ffind_file_name_handler (dirname);
1658 if (!NILP (handler))
1659 return call3 (handler, Qmake_directory, dirname, Qnil);
1660
1661 dir = XSTRING (dirname)->data;
1662
1663 if (mkdir (dir, 0777) != 0)
1664 report_file_error ("Creating directory", Flist (1, &dirname));
1665
1666 return Qnil;
1667 }
1668
1669 DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
1670 "Delete a directory. One argument, a file name string.")
1671 (dirname)
1672 Lisp_Object dirname;
1673 {
1674 unsigned char *dir;
1675 Lisp_Object handler;
1676
1677 CHECK_STRING (dirname, 0);
1678 dirname = Fexpand_file_name (dirname, Qnil);
1679 dir = XSTRING (dirname)->data;
1680
1681 handler = Ffind_file_name_handler (dirname);
1682 if (!NILP (handler))
1683 return call2 (handler, Qdelete_directory, dirname);
1684
1685 if (rmdir (dir) != 0)
1686 report_file_error ("Removing directory", Flist (1, &dirname));
1687
1688 return Qnil;
1689 }
1690
1691 DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
1692 "Delete specified file. One argument, a file name string.\n\
1693 If file has multiple names, it continues to exist with the other names.")
1694 (filename)
1695 Lisp_Object filename;
1696 {
1697 Lisp_Object handler;
1698 CHECK_STRING (filename, 0);
1699 filename = Fexpand_file_name (filename, Qnil);
1700
1701 handler = Ffind_file_name_handler (filename);
1702 if (!NILP (handler))
1703 return call2 (handler, Qdelete_file, filename);
1704
1705 if (0 > unlink (XSTRING (filename)->data))
1706 report_file_error ("Removing old name", Flist (1, &filename));
1707 return Qnil;
1708 }
1709
1710 DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
1711 "fRename file: \nFRename %s to file: \np",
1712 "Rename FILE as NEWNAME. Both args strings.\n\
1713 If file has names other than FILE, it continues to have those names.\n\
1714 Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1715 unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1716 A number as third arg means request confirmation if NEWNAME already exists.\n\
1717 This is what happens in interactive use with M-x.")
1718 (filename, newname, ok_if_already_exists)
1719 Lisp_Object filename, newname, ok_if_already_exists;
1720 {
1721 #ifdef NO_ARG_ARRAY
1722 Lisp_Object args[2];
1723 #endif
1724 Lisp_Object handler;
1725 struct gcpro gcpro1, gcpro2;
1726
1727 GCPRO2 (filename, newname);
1728 CHECK_STRING (filename, 0);
1729 CHECK_STRING (newname, 1);
1730 filename = Fexpand_file_name (filename, Qnil);
1731 newname = Fexpand_file_name (newname, Qnil);
1732
1733 /* If the file name has special constructs in it,
1734 call the corresponding file handler. */
1735 handler = Ffind_file_name_handler (filename);
1736 if (!NILP (handler))
1737 return call3 (handler, Qrename_file, filename, newname);
1738
1739 if (NILP (ok_if_already_exists)
1740 || XTYPE (ok_if_already_exists) == Lisp_Int)
1741 barf_or_query_if_file_exists (newname, "rename to it",
1742 XTYPE (ok_if_already_exists) == Lisp_Int);
1743 #ifndef BSD4_1
1744 if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
1745 #else
1746 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data)
1747 || 0 > unlink (XSTRING (filename)->data))
1748 #endif
1749 {
1750 if (errno == EXDEV)
1751 {
1752 Fcopy_file (filename, newname, ok_if_already_exists, Qt);
1753 Fdelete_file (filename);
1754 }
1755 else
1756 #ifdef NO_ARG_ARRAY
1757 {
1758 args[0] = filename;
1759 args[1] = newname;
1760 report_file_error ("Renaming", Flist (2, args));
1761 }
1762 #else
1763 report_file_error ("Renaming", Flist (2, &filename));
1764 #endif
1765 }
1766 UNGCPRO;
1767 return Qnil;
1768 }
1769
1770 DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3,
1771 "fAdd name to file: \nFName to add to %s: \np",
1772 "Give FILE additional name NEWNAME. Both args strings.\n\
1773 Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1774 unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1775 A number as third arg means request confirmation if NEWNAME already exists.\n\
1776 This is what happens in interactive use with M-x.")
1777 (filename, newname, ok_if_already_exists)
1778 Lisp_Object filename, newname, ok_if_already_exists;
1779 {
1780 #ifdef NO_ARG_ARRAY
1781 Lisp_Object args[2];
1782 #endif
1783 Lisp_Object handler;
1784 struct gcpro gcpro1, gcpro2;
1785
1786 GCPRO2 (filename, newname);
1787 CHECK_STRING (filename, 0);
1788 CHECK_STRING (newname, 1);
1789 filename = Fexpand_file_name (filename, Qnil);
1790 newname = Fexpand_file_name (newname, Qnil);
1791
1792 /* If the file name has special constructs in it,
1793 call the corresponding file handler. */
1794 handler = Ffind_file_name_handler (filename);
1795 if (!NILP (handler))
1796 return call3 (handler, Qadd_name_to_file, filename, newname);
1797
1798 if (NILP (ok_if_already_exists)
1799 || XTYPE (ok_if_already_exists) == Lisp_Int)
1800 barf_or_query_if_file_exists (newname, "make it a new name",
1801 XTYPE (ok_if_already_exists) == Lisp_Int);
1802 unlink (XSTRING (newname)->data);
1803 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data))
1804 {
1805 #ifdef NO_ARG_ARRAY
1806 args[0] = filename;
1807 args[1] = newname;
1808 report_file_error ("Adding new name", Flist (2, args));
1809 #else
1810 report_file_error ("Adding new name", Flist (2, &filename));
1811 #endif
1812 }
1813
1814 UNGCPRO;
1815 return Qnil;
1816 }
1817
1818 #ifdef S_IFLNK
1819 DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
1820 "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",
1821 "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\
1822 Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1823 unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1824 A number as third arg means request confirmation if NEWNAME already exists.\n\
1825 This happens for interactive use with M-x.")
1826 (filename, linkname, ok_if_already_exists)
1827 Lisp_Object filename, linkname, ok_if_already_exists;
1828 {
1829 #ifdef NO_ARG_ARRAY
1830 Lisp_Object args[2];
1831 #endif
1832 Lisp_Object handler;
1833 struct gcpro gcpro1, gcpro2;
1834
1835 GCPRO2 (filename, linkname);
1836 CHECK_STRING (filename, 0);
1837 CHECK_STRING (linkname, 1);
1838 #if 0 /* This made it impossible to make a link to a relative name. */
1839 filename = Fexpand_file_name (filename, Qnil);
1840 #endif
1841 linkname = Fexpand_file_name (linkname, Qnil);
1842
1843 /* If the file name has special constructs in it,
1844 call the corresponding file handler. */
1845 handler = Ffind_file_name_handler (filename);
1846 if (!NILP (handler))
1847 return call3 (handler, Qmake_symbolic_link, filename, linkname);
1848
1849 if (NILP (ok_if_already_exists)
1850 || XTYPE (ok_if_already_exists) == Lisp_Int)
1851 barf_or_query_if_file_exists (linkname, "make it a link",
1852 XTYPE (ok_if_already_exists) == Lisp_Int);
1853 if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
1854 {
1855 /* If we didn't complain already, silently delete existing file. */
1856 if (errno == EEXIST)
1857 {
1858 unlink (XSTRING (filename)->data);
1859 if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
1860 return Qnil;
1861 }
1862
1863 #ifdef NO_ARG_ARRAY
1864 args[0] = filename;
1865 args[1] = linkname;
1866 report_file_error ("Making symbolic link", Flist (2, args));
1867 #else
1868 report_file_error ("Making symbolic link", Flist (2, &filename));
1869 #endif
1870 }
1871 UNGCPRO;
1872 return Qnil;
1873 }
1874 #endif /* S_IFLNK */
1875
1876 #ifdef VMS
1877
1878 DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
1879 2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
1880 "Define the job-wide logical name NAME to have the value STRING.\n\
1881 If STRING is nil or a null string, the logical name NAME is deleted.")
1882 (varname, string)
1883 Lisp_Object varname;
1884 Lisp_Object string;
1885 {
1886 CHECK_STRING (varname, 0);
1887 if (NILP (string))
1888 delete_logical_name (XSTRING (varname)->data);
1889 else
1890 {
1891 CHECK_STRING (string, 1);
1892
1893 if (XSTRING (string)->size == 0)
1894 delete_logical_name (XSTRING (varname)->data);
1895 else
1896 define_logical_name (XSTRING (varname)->data, XSTRING (string)->data);
1897 }
1898
1899 return string;
1900 }
1901 #endif /* VMS */
1902
1903 #ifdef HPUX_NET
1904
1905 DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
1906 "Open a network connection to PATH using LOGIN as the login string.")
1907 (path, login)
1908 Lisp_Object path, login;
1909 {
1910 int netresult;
1911
1912 CHECK_STRING (path, 0);
1913 CHECK_STRING (login, 0);
1914
1915 netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
1916
1917 if (netresult == -1)
1918 return Qnil;
1919 else
1920 return Qt;
1921 }
1922 #endif /* HPUX_NET */
1923 \f
1924 DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
1925 1, 1, 0,
1926 "Return t if file FILENAME specifies an absolute path name.\n\
1927 On Unix, this is a name starting with a `/' or a `~'.")
1928 (filename)
1929 Lisp_Object filename;
1930 {
1931 unsigned char *ptr;
1932
1933 CHECK_STRING (filename, 0);
1934 ptr = XSTRING (filename)->data;
1935 if (*ptr == '/' || *ptr == '~'
1936 #ifdef VMS
1937 /* ??? This criterion is probably wrong for '<'. */
1938 || index (ptr, ':') || index (ptr, '<')
1939 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
1940 && ptr[1] != '.')
1941 #endif /* VMS */
1942 )
1943 return Qt;
1944 else
1945 return Qnil;
1946 }
1947
1948 DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
1949 "Return t if file FILENAME exists. (This does not mean you can read it.)\n\
1950 See also `file-readable-p' and `file-attributes'.")
1951 (filename)
1952 Lisp_Object filename;
1953 {
1954 Lisp_Object abspath;
1955 Lisp_Object handler;
1956
1957 CHECK_STRING (filename, 0);
1958 abspath = Fexpand_file_name (filename, Qnil);
1959
1960 /* If the file name has special constructs in it,
1961 call the corresponding file handler. */
1962 handler = Ffind_file_name_handler (abspath);
1963 if (!NILP (handler))
1964 return call2 (handler, Qfile_exists_p, abspath);
1965
1966 return (access (XSTRING (abspath)->data, 0) >= 0) ? Qt : Qnil;
1967 }
1968
1969 DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
1970 "Return t if FILENAME can be executed by you.\n\
1971 For a directory, this means you can access files in that directory.")
1972 (filename)
1973 Lisp_Object filename;
1974
1975 {
1976 Lisp_Object abspath;
1977 Lisp_Object handler;
1978
1979 CHECK_STRING (filename, 0);
1980 abspath = Fexpand_file_name (filename, Qnil);
1981
1982 /* If the file name has special constructs in it,
1983 call the corresponding file handler. */
1984 handler = Ffind_file_name_handler (abspath);
1985 if (!NILP (handler))
1986 return call2 (handler, Qfile_executable_p, abspath);
1987
1988 return (access (XSTRING (abspath)->data, 1) >= 0) ? Qt : Qnil;
1989 }
1990
1991 DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
1992 "Return t if file FILENAME exists and you can read it.\n\
1993 See also `file-exists-p' and `file-attributes'.")
1994 (filename)
1995 Lisp_Object filename;
1996 {
1997 Lisp_Object abspath;
1998 Lisp_Object handler;
1999
2000 CHECK_STRING (filename, 0);
2001 abspath = Fexpand_file_name (filename, Qnil);
2002
2003 /* If the file name has special constructs in it,
2004 call the corresponding file handler. */
2005 handler = Ffind_file_name_handler (abspath);
2006 if (!NILP (handler))
2007 return call2 (handler, Qfile_readable_p, abspath);
2008
2009 return (access (XSTRING (abspath)->data, 4) >= 0) ? Qt : Qnil;
2010 }
2011
2012 DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
2013 "If file FILENAME is the name of a symbolic link\n\
2014 returns the name of the file to which it is linked.\n\
2015 Otherwise returns NIL.")
2016 (filename)
2017 Lisp_Object filename;
2018 {
2019 #ifdef S_IFLNK
2020 char *buf;
2021 int bufsize;
2022 int valsize;
2023 Lisp_Object val;
2024 Lisp_Object handler;
2025
2026 CHECK_STRING (filename, 0);
2027 filename = Fexpand_file_name (filename, Qnil);
2028
2029 /* If the file name has special constructs in it,
2030 call the corresponding file handler. */
2031 handler = Ffind_file_name_handler (filename);
2032 if (!NILP (handler))
2033 return call2 (handler, Qfile_symlink_p, filename);
2034
2035 bufsize = 100;
2036 while (1)
2037 {
2038 buf = (char *) xmalloc (bufsize);
2039 bzero (buf, bufsize);
2040 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
2041 if (valsize < bufsize) break;
2042 /* Buffer was not long enough */
2043 free (buf);
2044 bufsize *= 2;
2045 }
2046 if (valsize == -1)
2047 {
2048 free (buf);
2049 return Qnil;
2050 }
2051 val = make_string (buf, valsize);
2052 free (buf);
2053 return val;
2054 #else /* not S_IFLNK */
2055 return Qnil;
2056 #endif /* not S_IFLNK */
2057 }
2058
2059 /* Having this before file-symlink-p mysteriously caused it to be forgotten
2060 on the RT/PC. */
2061 DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
2062 "Return t if file FILENAME can be written or created by you.")
2063 (filename)
2064 Lisp_Object filename;
2065 {
2066 Lisp_Object abspath, dir;
2067 Lisp_Object handler;
2068
2069 CHECK_STRING (filename, 0);
2070 abspath = Fexpand_file_name (filename, Qnil);
2071
2072 /* If the file name has special constructs in it,
2073 call the corresponding file handler. */
2074 handler = Ffind_file_name_handler (abspath);
2075 if (!NILP (handler))
2076 return call2 (handler, Qfile_writable_p, abspath);
2077
2078 if (access (XSTRING (abspath)->data, 0) >= 0)
2079 return (access (XSTRING (abspath)->data, 2) >= 0) ? Qt : Qnil;
2080 dir = Ffile_name_directory (abspath);
2081 #ifdef VMS
2082 if (!NILP (dir))
2083 dir = Fdirectory_file_name (dir);
2084 #endif /* VMS */
2085 return (access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
2086 ? Qt : Qnil);
2087 }
2088
2089 DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
2090 "Return t if file FILENAME is the name of a directory as a file.\n\
2091 A directory name spec may be given instead; then the value is t\n\
2092 if the directory so specified exists and really is a directory.")
2093 (filename)
2094 Lisp_Object filename;
2095 {
2096 register Lisp_Object abspath;
2097 struct stat st;
2098 Lisp_Object handler;
2099
2100 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2101
2102 /* If the file name has special constructs in it,
2103 call the corresponding file handler. */
2104 handler = Ffind_file_name_handler (abspath);
2105 if (!NILP (handler))
2106 return call2 (handler, Qfile_directory_p, abspath);
2107
2108 if (stat (XSTRING (abspath)->data, &st) < 0)
2109 return Qnil;
2110 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2111 }
2112
2113 DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
2114 "Return t if file FILENAME is the name of a directory as a file,\n\
2115 and files in that directory can be opened by you. In order to use a\n\
2116 directory as a buffer's current directory, this predicate must return true.\n\
2117 A directory name spec may be given instead; then the value is t\n\
2118 if the directory so specified exists and really is a readable and\n\
2119 searchable directory.")
2120 (filename)
2121 Lisp_Object filename;
2122 {
2123 Lisp_Object handler;
2124
2125 /* If the file name has special constructs in it,
2126 call the corresponding file handler. */
2127 handler = Ffind_file_name_handler (filename);
2128 if (!NILP (handler))
2129 return call2 (handler, Qfile_accessible_directory_p, filename);
2130
2131 if (NILP (Ffile_directory_p (filename))
2132 || NILP (Ffile_executable_p (filename)))
2133 return Qnil;
2134 else
2135 return Qt;
2136 }
2137
2138 DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2139 "Return mode bits of FILE, as an integer.")
2140 (filename)
2141 Lisp_Object filename;
2142 {
2143 Lisp_Object abspath;
2144 struct stat st;
2145 Lisp_Object handler;
2146
2147 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2148
2149 /* If the file name has special constructs in it,
2150 call the corresponding file handler. */
2151 handler = Ffind_file_name_handler (abspath);
2152 if (!NILP (handler))
2153 return call2 (handler, Qfile_modes, abspath);
2154
2155 if (stat (XSTRING (abspath)->data, &st) < 0)
2156 return Qnil;
2157 return make_number (st.st_mode & 07777);
2158 }
2159
2160 DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2161 "Set mode bits of FILE to MODE (an integer).\n\
2162 Only the 12 low bits of MODE are used.")
2163 (filename, mode)
2164 Lisp_Object filename, mode;
2165 {
2166 Lisp_Object abspath;
2167 Lisp_Object handler;
2168
2169 abspath = Fexpand_file_name (filename, current_buffer->directory);
2170 CHECK_NUMBER (mode, 1);
2171
2172 /* If the file name has special constructs in it,
2173 call the corresponding file handler. */
2174 handler = Ffind_file_name_handler (abspath);
2175 if (!NILP (handler))
2176 return call3 (handler, Qset_file_modes, abspath, mode);
2177
2178 #ifndef APOLLO
2179 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2180 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2181 #else /* APOLLO */
2182 if (!egetenv ("USE_DOMAIN_ACLS"))
2183 {
2184 struct stat st;
2185 struct timeval tvp[2];
2186
2187 /* chmod on apollo also change the file's modtime; need to save the
2188 modtime and then restore it. */
2189 if (stat (XSTRING (abspath)->data, &st) < 0)
2190 {
2191 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2192 return (Qnil);
2193 }
2194
2195 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2196 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2197
2198 /* reset the old accessed and modified times. */
2199 tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
2200 tvp[0].tv_usec = 0;
2201 tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
2202 tvp[1].tv_usec = 0;
2203
2204 if (utimes (XSTRING (abspath)->data, tvp) < 0)
2205 report_file_error ("Doing utimes", Fcons (abspath, Qnil));
2206 }
2207 #endif /* APOLLO */
2208
2209 return Qnil;
2210 }
2211
2212 DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
2213 "Set the file permission bits for newly created files.\n\
2214 The argument MODE should be an integer; only the low 9 bits are used.\n\
2215 This setting is inherited by subprocesses.")
2216 (mode)
2217 Lisp_Object mode;
2218 {
2219 CHECK_NUMBER (mode, 0);
2220
2221 umask ((~ XINT (mode)) & 0777);
2222
2223 return Qnil;
2224 }
2225
2226 DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
2227 "Return the default file protection for created files.\n\
2228 The value is an integer.")
2229 ()
2230 {
2231 int realmask;
2232 Lisp_Object value;
2233
2234 realmask = umask (0);
2235 umask (realmask);
2236
2237 XSET (value, Lisp_Int, (~ realmask) & 0777);
2238 return value;
2239 }
2240
2241 #ifdef unix
2242
2243 DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2244 "Tell Unix to finish all pending disk updates.")
2245 ()
2246 {
2247 sync ();
2248 return Qnil;
2249 }
2250
2251 #endif /* unix */
2252
2253 DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2254 "Return t if file FILE1 is newer than file FILE2.\n\
2255 If FILE1 does not exist, the answer is nil;\n\
2256 otherwise, if FILE2 does not exist, the answer is t.")
2257 (file1, file2)
2258 Lisp_Object file1, file2;
2259 {
2260 Lisp_Object abspath1, abspath2;
2261 struct stat st;
2262 int mtime1;
2263 Lisp_Object handler;
2264 struct gcpro gcpro1, gcpro2;
2265
2266 CHECK_STRING (file1, 0);
2267 CHECK_STRING (file2, 0);
2268
2269 abspath1 = Qnil;
2270 GCPRO2 (abspath1, file2);
2271 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2272 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
2273 UNGCPRO;
2274
2275 /* If the file name has special constructs in it,
2276 call the corresponding file handler. */
2277 handler = Ffind_file_name_handler (abspath1);
2278 if (!NILP (handler))
2279 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2280
2281 if (stat (XSTRING (abspath1)->data, &st) < 0)
2282 return Qnil;
2283
2284 mtime1 = st.st_mtime;
2285
2286 if (stat (XSTRING (abspath2)->data, &st) < 0)
2287 return Qt;
2288
2289 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2290 }
2291 \f
2292 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
2293 1, 2, 0,
2294 "Insert contents of file FILENAME after point.\n\
2295 Returns list of absolute pathname and length of data inserted.\n\
2296 If second argument VISIT is non-nil, the buffer's visited filename\n\
2297 and last save file modtime are set, and it is marked unmodified.\n\
2298 If visiting and the file does not exist, visiting is completed\n\
2299 before the error is signaled.")
2300 (filename, visit)
2301 Lisp_Object filename, visit;
2302 {
2303 struct stat st;
2304 register int fd;
2305 register int inserted = 0;
2306 register int how_much;
2307 int count = specpdl_ptr - specpdl;
2308 struct gcpro gcpro1;
2309 Lisp_Object handler, val;
2310
2311 val = Qnil;
2312
2313 GCPRO1 (filename);
2314 if (!NILP (current_buffer->read_only))
2315 Fbarf_if_buffer_read_only();
2316
2317 CHECK_STRING (filename, 0);
2318 filename = Fexpand_file_name (filename, Qnil);
2319
2320 /* If the file name has special constructs in it,
2321 call the corresponding file handler. */
2322 handler = Ffind_file_name_handler (filename);
2323 if (!NILP (handler))
2324 {
2325 val = call3 (handler, Qinsert_file_contents, filename, visit);
2326 st.st_mtime = 0;
2327 goto handled;
2328 }
2329
2330 fd = -1;
2331
2332 #ifndef APOLLO
2333 if (stat (XSTRING (filename)->data, &st) < 0
2334 || (fd = open (XSTRING (filename)->data, 0)) < 0)
2335 #else
2336 if ((fd = open (XSTRING (filename)->data, 0)) < 0
2337 || fstat (fd, &st) < 0)
2338 #endif /* not APOLLO */
2339 {
2340 if (fd >= 0) close (fd);
2341 if (NILP (visit))
2342 report_file_error ("Opening input file", Fcons (filename, Qnil));
2343 st.st_mtime = -1;
2344 how_much = 0;
2345 goto notfound;
2346 }
2347
2348 record_unwind_protect (close_file_unwind, make_number (fd));
2349
2350 #ifdef S_IFSOCK
2351 /* This code will need to be changed in order to work on named
2352 pipes, and it's probably just not worth it. So we should at
2353 least signal an error. */
2354 if ((st.st_mode & S_IFMT) == S_IFSOCK)
2355 Fsignal (Qfile_error,
2356 Fcons (build_string ("reading from named pipe"),
2357 Fcons (filename, Qnil)));
2358 #endif
2359
2360 /* Supposedly happens on VMS. */
2361 if (st.st_size < 0)
2362 error ("File size is negative");
2363
2364 {
2365 register Lisp_Object temp;
2366
2367 /* Make sure point-max won't overflow after this insertion. */
2368 XSET (temp, Lisp_Int, st.st_size + Z);
2369 if (st.st_size + Z != XINT (temp))
2370 error ("maximum buffer size exceeded");
2371 }
2372
2373 if (NILP (visit))
2374 prepare_to_modify_buffer (point, point);
2375
2376 move_gap (point);
2377 if (GAP_SIZE < st.st_size)
2378 make_gap (st.st_size - GAP_SIZE);
2379
2380 while (1)
2381 {
2382 int try = min (st.st_size - inserted, 64 << 10);
2383 int this;
2384
2385 /* Allow quitting out of the actual I/O. */
2386 immediate_quit = 1;
2387 QUIT;
2388 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2389 immediate_quit = 0;
2390
2391 if (this <= 0)
2392 {
2393 how_much = this;
2394 break;
2395 }
2396
2397 GPT += this;
2398 GAP_SIZE -= this;
2399 ZV += this;
2400 Z += this;
2401 inserted += this;
2402 }
2403
2404 if (inserted > 0)
2405 {
2406 record_insert (point, inserted);
2407
2408 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2409 offset_intervals (current_buffer, point, inserted);
2410 MODIFF++;
2411 }
2412
2413 close (fd);
2414
2415 /* Discard the unwind protect */
2416 specpdl_ptr = specpdl + count;
2417
2418 if (how_much < 0)
2419 error ("IO error reading %s: %s",
2420 XSTRING (filename)->data, err_str (errno));
2421
2422 notfound:
2423 handled:
2424
2425 if (!NILP (visit))
2426 {
2427 current_buffer->undo_list = Qnil;
2428 #ifdef APOLLO
2429 stat (XSTRING (filename)->data, &st);
2430 #endif
2431 current_buffer->modtime = st.st_mtime;
2432 current_buffer->save_modified = MODIFF;
2433 current_buffer->auto_save_modified = MODIFF;
2434 XFASTINT (current_buffer->save_length) = Z - BEG;
2435 #ifdef CLASH_DETECTION
2436 if (NILP (handler))
2437 {
2438 if (!NILP (current_buffer->filename))
2439 unlock_file (current_buffer->filename);
2440 unlock_file (filename);
2441 }
2442 #endif /* CLASH_DETECTION */
2443 current_buffer->filename = filename;
2444 /* If visiting nonexistent file, return nil. */
2445 if (current_buffer->modtime == -1)
2446 report_file_error ("Opening input file", Fcons (filename, Qnil));
2447 }
2448
2449 signal_after_change (point, 0, inserted);
2450
2451 if (!NILP (val))
2452 RETURN_UNGCPRO (val);
2453 RETURN_UNGCPRO (Fcons (filename,
2454 Fcons (make_number (inserted),
2455 Qnil)));
2456 }
2457
2458 DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2459 "r\nFWrite region to file: ",
2460 "Write current region into specified file.\n\
2461 When called from a program, takes three arguments:\n\
2462 START, END and FILENAME. START and END are buffer positions.\n\
2463 Optional fourth argument APPEND if non-nil means\n\
2464 append to existing file contents (if any).\n\
2465 Optional fifth argument VISIT if t means\n\
2466 set the last-save-file-modtime of buffer to this file's modtime\n\
2467 and mark buffer not modified.\n\
2468 If VISIT is a string, it is a second file name;\n\
2469 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
2470 VISIT is also the file name to lock and unlock for clash detection.\n\
2471 If VISIT is neither t nor nil nor a string,\n\
2472 that means do not print the \"Wrote file\" message.\n\
2473 Kludgy feature: if START is a string, then that string is written\n\
2474 to the file, instead of any buffer contents, and END is ignored.")
2475 (start, end, filename, append, visit)
2476 Lisp_Object start, end, filename, append, visit;
2477 {
2478 register int desc;
2479 int failure;
2480 int save_errno;
2481 unsigned char *fn;
2482 struct stat st;
2483 int tem;
2484 int count = specpdl_ptr - specpdl;
2485 #ifdef VMS
2486 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
2487 #endif /* VMS */
2488 Lisp_Object handler;
2489 Lisp_Object visit_file = XTYPE (visit) == Lisp_String ? visit : filename;
2490 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2491
2492 /* Special kludge to simplify auto-saving */
2493 if (NILP (start))
2494 {
2495 XFASTINT (start) = BEG;
2496 XFASTINT (end) = Z;
2497 }
2498 else if (XTYPE (start) != Lisp_String)
2499 validate_region (&start, &end);
2500
2501 GCPRO4 (start, filename, visit, visit_file);
2502 filename = Fexpand_file_name (filename, Qnil);
2503
2504 /* If the file name has special constructs in it,
2505 call the corresponding file handler. */
2506 handler = Ffind_file_name_handler (filename);
2507
2508 if (!NILP (handler))
2509 {
2510 Lisp_Object args[7];
2511 Lisp_Object val;
2512 args[0] = handler;
2513 args[1] = Qwrite_region;
2514 args[2] = start;
2515 args[3] = end;
2516 args[4] = filename;
2517 args[5] = append;
2518 args[6] = visit;
2519 val = Ffuncall (7, args);
2520
2521 /* Do this before reporting IO error
2522 to avoid a "file has changed on disk" warning on
2523 next attempt to save. */
2524 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
2525 {
2526 current_buffer->modtime = 0;
2527 current_buffer->save_modified = MODIFF;
2528 XFASTINT (current_buffer->save_length) = Z - BEG;
2529 current_buffer->filename = visit_file;
2530 }
2531 UNGCPRO;
2532 return val;
2533 }
2534
2535 #ifdef CLASH_DETECTION
2536 if (!auto_saving)
2537 lock_file (visit_file);
2538 #endif /* CLASH_DETECTION */
2539
2540 fn = XSTRING (filename)->data;
2541 desc = -1;
2542 if (!NILP (append))
2543 desc = open (fn, O_WRONLY);
2544
2545 if (desc < 0)
2546 #ifdef VMS
2547 if (auto_saving) /* Overwrite any previous version of autosave file */
2548 {
2549 vms_truncate (fn); /* if fn exists, truncate to zero length */
2550 desc = open (fn, O_RDWR);
2551 if (desc < 0)
2552 desc = creat_copy_attrs (XTYPE (current_buffer->filename) == Lisp_String
2553 ? XSTRING (current_buffer->filename)->data : 0,
2554 fn);
2555 }
2556 else /* Write to temporary name and rename if no errors */
2557 {
2558 Lisp_Object temp_name;
2559 temp_name = Ffile_name_directory (filename);
2560
2561 if (!NILP (temp_name))
2562 {
2563 temp_name = Fmake_temp_name (concat2 (temp_name,
2564 build_string ("$$SAVE$$")));
2565 fname = XSTRING (filename)->data;
2566 fn = XSTRING (temp_name)->data;
2567 desc = creat_copy_attrs (fname, fn);
2568 if (desc < 0)
2569 {
2570 /* If we can't open the temporary file, try creating a new
2571 version of the original file. VMS "creat" creates a
2572 new version rather than truncating an existing file. */
2573 fn = fname;
2574 fname = 0;
2575 desc = creat (fn, 0666);
2576 #if 0 /* This can clobber an existing file and fail to replace it,
2577 if the user runs out of space. */
2578 if (desc < 0)
2579 {
2580 /* We can't make a new version;
2581 try to truncate and rewrite existing version if any. */
2582 vms_truncate (fn);
2583 desc = open (fn, O_RDWR);
2584 }
2585 #endif
2586 }
2587 }
2588 else
2589 desc = creat (fn, 0666);
2590 }
2591 #else /* not VMS */
2592 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
2593 #endif /* not VMS */
2594
2595 UNGCPRO;
2596
2597 if (desc < 0)
2598 {
2599 #ifdef CLASH_DETECTION
2600 save_errno = errno;
2601 if (!auto_saving) unlock_file (visit_file);
2602 errno = save_errno;
2603 #endif /* CLASH_DETECTION */
2604 report_file_error ("Opening output file", Fcons (filename, Qnil));
2605 }
2606
2607 record_unwind_protect (close_file_unwind, make_number (desc));
2608
2609 if (!NILP (append))
2610 if (lseek (desc, 0, 2) < 0)
2611 {
2612 #ifdef CLASH_DETECTION
2613 if (!auto_saving) unlock_file (visit_file);
2614 #endif /* CLASH_DETECTION */
2615 report_file_error ("Lseek error", Fcons (filename, Qnil));
2616 }
2617
2618 #ifdef VMS
2619 /*
2620 * Kludge Warning: The VMS C RTL likes to insert carriage returns
2621 * if we do writes that don't end with a carriage return. Furthermore
2622 * it cannot handle writes of more then 16K. The modified
2623 * version of "sys_write" in SYSDEP.C (see comment there) copes with
2624 * this EXCEPT for the last record (iff it doesn't end with a carriage
2625 * return). This implies that if your buffer doesn't end with a carriage
2626 * return, you get one free... tough. However it also means that if
2627 * we make two calls to sys_write (a la the following code) you can
2628 * get one at the gap as well. The easiest way to fix this (honest)
2629 * is to move the gap to the next newline (or the end of the buffer).
2630 * Thus this change.
2631 *
2632 * Yech!
2633 */
2634 if (GPT > BEG && GPT_ADDR[-1] != '\n')
2635 move_gap (find_next_newline (GPT, 1));
2636 #endif
2637
2638 failure = 0;
2639 immediate_quit = 1;
2640
2641 if (XTYPE (start) == Lisp_String)
2642 {
2643 failure = 0 > e_write (desc, XSTRING (start)->data,
2644 XSTRING (start)->size);
2645 save_errno = errno;
2646 }
2647 else if (XINT (start) != XINT (end))
2648 {
2649 if (XINT (start) < GPT)
2650 {
2651 register int end1 = XINT (end);
2652 tem = XINT (start);
2653 failure = 0 > e_write (desc, &FETCH_CHAR (tem),
2654 min (GPT, end1) - tem);
2655 save_errno = errno;
2656 }
2657
2658 if (XINT (end) > GPT && !failure)
2659 {
2660 tem = XINT (start);
2661 tem = max (tem, GPT);
2662 failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem);
2663 save_errno = errno;
2664 }
2665 }
2666
2667 immediate_quit = 0;
2668
2669 #ifdef HAVE_FSYNC
2670 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
2671 Disk full in NFS may be reported here. */
2672 if (fsync (desc) < 0)
2673 failure = 1, save_errno = errno;
2674 #endif
2675
2676 /* Spurious "file has changed on disk" warnings have been
2677 observed on Suns as well.
2678 It seems that `close' can change the modtime, under nfs.
2679
2680 (This has supposedly been fixed in Sunos 4,
2681 but who knows about all the other machines with NFS?) */
2682 #if 0
2683
2684 /* On VMS and APOLLO, must do the stat after the close
2685 since closing changes the modtime. */
2686 #ifndef VMS
2687 #ifndef APOLLO
2688 /* Recall that #if defined does not work on VMS. */
2689 #define FOO
2690 fstat (desc, &st);
2691 #endif
2692 #endif
2693 #endif
2694
2695 /* NFS can report a write failure now. */
2696 if (close (desc) < 0)
2697 failure = 1, save_errno = errno;
2698
2699 #ifdef VMS
2700 /* If we wrote to a temporary name and had no errors, rename to real name. */
2701 if (fname)
2702 {
2703 if (!failure)
2704 failure = (rename (fn, fname) != 0), save_errno = errno;
2705 fn = fname;
2706 }
2707 #endif /* VMS */
2708
2709 #ifndef FOO
2710 stat (fn, &st);
2711 #endif
2712 /* Discard the unwind protect */
2713 specpdl_ptr = specpdl + count;
2714
2715 #ifdef CLASH_DETECTION
2716 if (!auto_saving)
2717 unlock_file (visit_file);
2718 #endif /* CLASH_DETECTION */
2719
2720 /* Do this before reporting IO error
2721 to avoid a "file has changed on disk" warning on
2722 next attempt to save. */
2723 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
2724 current_buffer->modtime = st.st_mtime;
2725
2726 if (failure)
2727 error ("IO error writing %s: %s", fn, err_str (save_errno));
2728
2729 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
2730 {
2731 current_buffer->save_modified = MODIFF;
2732 XFASTINT (current_buffer->save_length) = Z - BEG;
2733 current_buffer->filename = visit_file;
2734 }
2735 else if (!NILP (visit))
2736 return Qnil;
2737
2738 if (!auto_saving)
2739 message ("Wrote %s", XSTRING (visit_file)->data);
2740
2741 return Qnil;
2742 }
2743
2744 int
2745 e_write (desc, addr, len)
2746 int desc;
2747 register char *addr;
2748 register int len;
2749 {
2750 char buf[16 * 1024];
2751 register char *p, *end;
2752
2753 if (!EQ (current_buffer->selective_display, Qt))
2754 return write (desc, addr, len) - len;
2755 else
2756 {
2757 p = buf;
2758 end = p + sizeof buf;
2759 while (len--)
2760 {
2761 if (p == end)
2762 {
2763 if (write (desc, buf, sizeof buf) != sizeof buf)
2764 return -1;
2765 p = buf;
2766 }
2767 *p = *addr++;
2768 if (*p++ == '\015')
2769 p[-1] = '\n';
2770 }
2771 if (p != buf)
2772 if (write (desc, buf, p - buf) != p - buf)
2773 return -1;
2774 }
2775 return 0;
2776 }
2777
2778 DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
2779 Sverify_visited_file_modtime, 1, 1, 0,
2780 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
2781 This means that the file has not been changed since it was visited or saved.")
2782 (buf)
2783 Lisp_Object buf;
2784 {
2785 struct buffer *b;
2786 struct stat st;
2787 Lisp_Object handler;
2788
2789 CHECK_BUFFER (buf, 0);
2790 b = XBUFFER (buf);
2791
2792 if (XTYPE (b->filename) != Lisp_String) return Qt;
2793 if (b->modtime == 0) return Qt;
2794
2795 /* If the file name has special constructs in it,
2796 call the corresponding file handler. */
2797 handler = Ffind_file_name_handler (b->filename);
2798 if (!NILP (handler))
2799 return call2 (handler, Qverify_visited_file_modtime, buf);
2800
2801 if (stat (XSTRING (b->filename)->data, &st) < 0)
2802 {
2803 /* If the file doesn't exist now and didn't exist before,
2804 we say that it isn't modified, provided the error is a tame one. */
2805 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
2806 st.st_mtime = -1;
2807 else
2808 st.st_mtime = 0;
2809 }
2810 if (st.st_mtime == b->modtime
2811 /* If both are positive, accept them if they are off by one second. */
2812 || (st.st_mtime > 0 && b->modtime > 0
2813 && (st.st_mtime == b->modtime + 1
2814 || st.st_mtime == b->modtime - 1)))
2815 return Qt;
2816 return Qnil;
2817 }
2818
2819 DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
2820 Sclear_visited_file_modtime, 0, 0, 0,
2821 "Clear out records of last mod time of visited file.\n\
2822 Next attempt to save will certainly not complain of a discrepancy.")
2823 ()
2824 {
2825 current_buffer->modtime = 0;
2826 return Qnil;
2827 }
2828
2829 DEFUN ("visited-file-modtime", Fvisited_file_modtime,
2830 Svisited_file_modtime, 0, 0, 0,
2831 "Return the current buffer's recorded visited file modification time.\n\
2832 The value is a list of the form (HIGH . LOW), like the time values\n\
2833 that `file-attributes' returns.")
2834 ()
2835 {
2836 return long_to_cons (current_buffer->modtime);
2837 }
2838
2839 DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
2840 Sset_visited_file_modtime, 0, 1, 0,
2841 "Update buffer's recorded modification time from the visited file's time.\n\
2842 Useful if the buffer was not read from the file normally\n\
2843 or if the file itself has been changed for some known benign reason.\n\
2844 An argument specifies the modification time value to use\n\
2845 \(instead of that of the visited file), in the form of a list\n\
2846 \(HIGH . LOW) or (HIGH LOW).")
2847 (time_list)
2848 Lisp_Object time_list;
2849 {
2850 if (!NILP (time_list))
2851 current_buffer->modtime = cons_to_long (time_list);
2852 else
2853 {
2854 register Lisp_Object filename;
2855 struct stat st;
2856 Lisp_Object handler;
2857
2858 filename = Fexpand_file_name (current_buffer->filename, Qnil);
2859
2860 /* If the file name has special constructs in it,
2861 call the corresponding file handler. */
2862 handler = Ffind_file_name_handler (filename);
2863 if (!NILP (handler))
2864 return call3 (handler, Qfile_name_directory, filename, Qnil);
2865 else if (stat (XSTRING (filename)->data, &st) >= 0)
2866 current_buffer->modtime = st.st_mtime;
2867 }
2868
2869 return Qnil;
2870 }
2871 \f
2872 Lisp_Object
2873 auto_save_error ()
2874 {
2875 unsigned char *name = XSTRING (current_buffer->name)->data;
2876
2877 ring_bell ();
2878 message ("Autosaving...error for %s", name);
2879 Fsleep_for (make_number (1), Qnil);
2880 message ("Autosaving...error!for %s", name);
2881 Fsleep_for (make_number (1), Qnil);
2882 message ("Autosaving...error for %s", name);
2883 Fsleep_for (make_number (1), Qnil);
2884 return Qnil;
2885 }
2886
2887 Lisp_Object
2888 auto_save_1 ()
2889 {
2890 unsigned char *fn;
2891 struct stat st;
2892
2893 /* Get visited file's mode to become the auto save file's mode. */
2894 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
2895 /* But make sure we can overwrite it later! */
2896 auto_save_mode_bits = st.st_mode | 0600;
2897 else
2898 auto_save_mode_bits = 0666;
2899
2900 return
2901 Fwrite_region (Qnil, Qnil,
2902 current_buffer->auto_save_file_name,
2903 Qnil, Qlambda);
2904 }
2905
2906 DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
2907 "Auto-save all buffers that need it.\n\
2908 This is all buffers that have auto-saving enabled\n\
2909 and are changed since last auto-saved.\n\
2910 Auto-saving writes the buffer into a file\n\
2911 so that your editing is not lost if the system crashes.\n\
2912 This file is not the file you visited; that changes only when you save.\n\n\
2913 Non-nil first argument means do not print any message if successful.\n\
2914 Non-nil second argument means save only current buffer.")
2915 (no_message, current_only)
2916 Lisp_Object no_message, current_only;
2917 {
2918 struct buffer *old = current_buffer, *b;
2919 Lisp_Object tail, buf;
2920 int auto_saved = 0;
2921 char *omessage = echo_area_glyphs;
2922 extern int minibuf_level;
2923 int do_handled_files;
2924
2925 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
2926 point to non-strings reached from Vbuffer_alist. */
2927
2928 auto_saving = 1;
2929 if (minibuf_level)
2930 no_message = Qt;
2931
2932 /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
2933 eventually call do-auto-save, so don't err here in that case. */
2934 if (!NILP (Vrun_hooks))
2935 call1 (Vrun_hooks, intern ("auto-save-hook"));
2936
2937 /* First, save all files which don't have handlers. If Emacs is
2938 crashing, the handlers may tweak what is causing Emacs to crash
2939 in the first place, and it would be a shame if Emacs failed to
2940 autosave perfectly ordinary files because it couldn't handle some
2941 ange-ftp'd file. */
2942 for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
2943 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
2944 tail = XCONS (tail)->cdr)
2945 {
2946 buf = XCONS (XCONS (tail)->car)->cdr;
2947 b = XBUFFER (buf);
2948
2949 if (!NILP (current_only)
2950 && b != current_buffer)
2951 continue;
2952
2953 /* Check for auto save enabled
2954 and file changed since last auto save
2955 and file changed since last real save. */
2956 if (XTYPE (b->auto_save_file_name) == Lisp_String
2957 && b->save_modified < BUF_MODIFF (b)
2958 && b->auto_save_modified < BUF_MODIFF (b)
2959 && (do_handled_files
2960 || NILP (Ffind_file_name_handler (b->auto_save_file_name))))
2961 {
2962 if ((XFASTINT (b->save_length) * 10
2963 > (BUF_Z (b) - BUF_BEG (b)) * 13)
2964 /* A short file is likely to change a large fraction;
2965 spare the user annoying messages. */
2966 && XFASTINT (b->save_length) > 5000
2967 /* These messages are frequent and annoying for `*mail*'. */
2968 && !EQ (b->filename, Qnil)
2969 && NILP (no_message))
2970 {
2971 /* It has shrunk too much; turn off auto-saving here. */
2972 message ("Buffer %s has shrunk a lot; auto save turned off there",
2973 XSTRING (b->name)->data);
2974 /* User can reenable saving with M-x auto-save. */
2975 b->auto_save_file_name = Qnil;
2976 /* Prevent warning from repeating if user does so. */
2977 XFASTINT (b->save_length) = 0;
2978 Fsleep_for (make_number (1), Qnil);
2979 continue;
2980 }
2981 set_buffer_internal (b);
2982 if (!auto_saved && NILP (no_message))
2983 message1 ("Auto-saving...");
2984 internal_condition_case (auto_save_1, Qt, auto_save_error);
2985 auto_saved++;
2986 b->auto_save_modified = BUF_MODIFF (b);
2987 XFASTINT (current_buffer->save_length) = Z - BEG;
2988 set_buffer_internal (old);
2989 }
2990 }
2991
2992 /* Prevent another auto save till enough input events come in. */
2993 record_auto_save ();
2994
2995 if (auto_saved && NILP (no_message))
2996 message1 (omessage ? omessage : "Auto-saving...done");
2997
2998 auto_saving = 0;
2999 return Qnil;
3000 }
3001
3002 DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
3003 Sset_buffer_auto_saved, 0, 0, 0,
3004 "Mark current buffer as auto-saved with its current text.\n\
3005 No auto-save file will be written until the buffer changes again.")
3006 ()
3007 {
3008 current_buffer->auto_save_modified = MODIFF;
3009 XFASTINT (current_buffer->save_length) = Z - BEG;
3010 return Qnil;
3011 }
3012
3013 DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
3014 0, 0, 0,
3015 "Return t if buffer has been auto-saved since last read in or saved.")
3016 ()
3017 {
3018 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
3019 }
3020 \f
3021 /* Reading and completing file names */
3022 extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
3023
3024 DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
3025 3, 3, 0,
3026 "Internal subroutine for read-file-name. Do not call this.")
3027 (string, dir, action)
3028 Lisp_Object string, dir, action;
3029 /* action is nil for complete, t for return list of completions,
3030 lambda for verify final value */
3031 {
3032 Lisp_Object name, specdir, realdir, val, orig_string;
3033 int changed;
3034 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3035
3036 realdir = dir;
3037 name = string;
3038 orig_string = Qnil;
3039 specdir = Qnil;
3040 changed = 0;
3041 /* No need to protect ACTION--we only compare it with t and nil. */
3042 GCPRO4 (string, realdir, name, specdir);
3043
3044 if (XSTRING (string)->size == 0)
3045 {
3046 if (EQ (action, Qlambda))
3047 {
3048 UNGCPRO;
3049 return Qnil;
3050 }
3051 }
3052 else
3053 {
3054 orig_string = string;
3055 string = Fsubstitute_in_file_name (string);
3056 changed = NILP (Fstring_equal (string, orig_string));
3057 name = Ffile_name_nondirectory (string);
3058 val = Ffile_name_directory (string);
3059 if (! NILP (val))
3060 realdir = Fexpand_file_name (val, realdir);
3061 }
3062
3063 if (NILP (action))
3064 {
3065 specdir = Ffile_name_directory (string);
3066 val = Ffile_name_completion (name, realdir);
3067 UNGCPRO;
3068 if (XTYPE (val) != Lisp_String)
3069 {
3070 if (changed)
3071 return string;
3072 return val;
3073 }
3074
3075 if (!NILP (specdir))
3076 val = concat2 (specdir, val);
3077 #ifndef VMS
3078 {
3079 register unsigned char *old, *new;
3080 register int n;
3081 int osize, count;
3082
3083 osize = XSTRING (val)->size;
3084 /* Quote "$" as "$$" to get it past substitute-in-file-name */
3085 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
3086 if (*old++ == '$') count++;
3087 if (count > 0)
3088 {
3089 old = XSTRING (val)->data;
3090 val = Fmake_string (make_number (osize + count), make_number (0));
3091 new = XSTRING (val)->data;
3092 for (n = osize; n > 0; n--)
3093 if (*old != '$')
3094 *new++ = *old++;
3095 else
3096 {
3097 *new++ = '$';
3098 *new++ = '$';
3099 old++;
3100 }
3101 }
3102 }
3103 #endif /* Not VMS */
3104 return val;
3105 }
3106 UNGCPRO;
3107
3108 if (EQ (action, Qt))
3109 return Ffile_name_all_completions (name, realdir);
3110 /* Only other case actually used is ACTION = lambda */
3111 #ifdef VMS
3112 /* Supposedly this helps commands such as `cd' that read directory names,
3113 but can someone explain how it helps them? -- RMS */
3114 if (XSTRING (name)->size == 0)
3115 return Qt;
3116 #endif /* VMS */
3117 return Ffile_exists_p (string);
3118 }
3119
3120 DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3121 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3122 Value is not expanded---you must call `expand-file-name' yourself.\n\
3123 Default name to DEFAULT if user enters a null string.\n\
3124 (If DEFAULT is omitted, the visited file name is used.)\n\
3125 Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3126 Non-nil and non-t means also require confirmation after completion.\n\
3127 Fifth arg INITIAL specifies text to start with.\n\
3128 DIR defaults to current buffer's directory default.")
3129 (prompt, dir, defalt, mustmatch, initial)
3130 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3131 {
3132 Lisp_Object val, insdef, insdef1, tem;
3133 struct gcpro gcpro1, gcpro2;
3134 register char *homedir;
3135 int count;
3136
3137 if (NILP (dir))
3138 dir = current_buffer->directory;
3139 if (NILP (defalt))
3140 defalt = current_buffer->filename;
3141
3142 /* If dir starts with user's homedir, change that to ~. */
3143 homedir = (char *) egetenv ("HOME");
3144 if (homedir != 0
3145 && XTYPE (dir) == Lisp_String
3146 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3147 && XSTRING (dir)->data[strlen (homedir)] == '/')
3148 {
3149 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3150 XSTRING (dir)->size - strlen (homedir) + 1);
3151 XSTRING (dir)->data[0] = '~';
3152 }
3153
3154 if (insert_default_directory)
3155 {
3156 insdef = dir;
3157 insdef1 = dir;
3158 if (!NILP (initial))
3159 {
3160 Lisp_Object args[2], pos;
3161
3162 args[0] = insdef;
3163 args[1] = initial;
3164 insdef = Fconcat (2, args);
3165 pos = make_number (XSTRING (dir)->size);
3166 insdef1 = Fcons (insdef, pos);
3167 }
3168 }
3169 else
3170 insdef = Qnil, insdef1 = Qnil;
3171
3172 #ifdef VMS
3173 count = specpdl_ptr - specpdl;
3174 specbind (intern ("completion-ignore-case"), Qt);
3175 #endif
3176
3177 GCPRO2 (insdef, defalt);
3178 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3179 dir, mustmatch, insdef1,
3180 Qfile_name_history);
3181
3182 #ifdef VMS
3183 unbind_to (count, Qnil);
3184 #endif
3185
3186 UNGCPRO;
3187 if (NILP (val))
3188 error ("No file name specified");
3189 tem = Fstring_equal (val, insdef);
3190 if (!NILP (tem) && !NILP (defalt))
3191 return defalt;
3192 return Fsubstitute_in_file_name (val);
3193 }
3194
3195 #if 0 /* Old version */
3196 DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3197 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3198 Value is not expanded---you must call `expand-file-name' yourself.\n\
3199 Default name to DEFAULT if user enters a null string.\n\
3200 (If DEFAULT is omitted, the visited file name is used.)\n\
3201 Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3202 Non-nil and non-t means also require confirmation after completion.\n\
3203 Fifth arg INITIAL specifies text to start with.\n\
3204 DIR defaults to current buffer's directory default.")
3205 (prompt, dir, defalt, mustmatch, initial)
3206 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3207 {
3208 Lisp_Object val, insdef, tem;
3209 struct gcpro gcpro1, gcpro2;
3210 register char *homedir;
3211 int count;
3212
3213 if (NILP (dir))
3214 dir = current_buffer->directory;
3215 if (NILP (defalt))
3216 defalt = current_buffer->filename;
3217
3218 /* If dir starts with user's homedir, change that to ~. */
3219 homedir = (char *) egetenv ("HOME");
3220 if (homedir != 0
3221 && XTYPE (dir) == Lisp_String
3222 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3223 && XSTRING (dir)->data[strlen (homedir)] == '/')
3224 {
3225 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3226 XSTRING (dir)->size - strlen (homedir) + 1);
3227 XSTRING (dir)->data[0] = '~';
3228 }
3229
3230 if (!NILP (initial))
3231 insdef = initial;
3232 else if (insert_default_directory)
3233 insdef = dir;
3234 else
3235 insdef = build_string ("");
3236
3237 #ifdef VMS
3238 count = specpdl_ptr - specpdl;
3239 specbind (intern ("completion-ignore-case"), Qt);
3240 #endif
3241
3242 GCPRO2 (insdef, defalt);
3243 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3244 dir, mustmatch,
3245 insert_default_directory ? insdef : Qnil,
3246 Qfile_name_history);
3247
3248 #ifdef VMS
3249 unbind_to (count, Qnil);
3250 #endif
3251
3252 UNGCPRO;
3253 if (NILP (val))
3254 error ("No file name specified");
3255 tem = Fstring_equal (val, insdef);
3256 if (!NILP (tem) && !NILP (defalt))
3257 return defalt;
3258 return Fsubstitute_in_file_name (val);
3259 }
3260 #endif /* Old version */
3261 \f
3262 syms_of_fileio ()
3263 {
3264 Qexpand_file_name = intern ("expand-file-name");
3265 Qdirectory_file_name = intern ("directory-file-name");
3266 Qfile_name_directory = intern ("file-name-directory");
3267 Qfile_name_nondirectory = intern ("file-name-nondirectory");
3268 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
3269 Qfile_name_as_directory = intern ("file-name-as-directory");
3270 Qcopy_file = intern ("copy-file");
3271 Qmake_directory = intern ("make-directory");
3272 Qdelete_directory = intern ("delete-directory");
3273 Qdelete_file = intern ("delete-file");
3274 Qrename_file = intern ("rename-file");
3275 Qadd_name_to_file = intern ("add-name-to-file");
3276 Qmake_symbolic_link = intern ("make-symbolic-link");
3277 Qfile_exists_p = intern ("file-exists-p");
3278 Qfile_executable_p = intern ("file-executable-p");
3279 Qfile_readable_p = intern ("file-readable-p");
3280 Qfile_symlink_p = intern ("file-symlink-p");
3281 Qfile_writable_p = intern ("file-writable-p");
3282 Qfile_directory_p = intern ("file-directory-p");
3283 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
3284 Qfile_modes = intern ("file-modes");
3285 Qset_file_modes = intern ("set-file-modes");
3286 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
3287 Qinsert_file_contents = intern ("insert-file-contents");
3288 Qwrite_region = intern ("write-region");
3289 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3290
3291 staticpro (&Qexpand_file_name);
3292 staticpro (&Qdirectory_file_name);
3293 staticpro (&Qfile_name_directory);
3294 staticpro (&Qfile_name_nondirectory);
3295 staticpro (&Qunhandled_file_name_directory);
3296 staticpro (&Qfile_name_as_directory);
3297 staticpro (&Qcopy_file);
3298 staticpro (&Qmake_directory);
3299 staticpro (&Qdelete_directory);
3300 staticpro (&Qdelete_file);
3301 staticpro (&Qrename_file);
3302 staticpro (&Qadd_name_to_file);
3303 staticpro (&Qmake_symbolic_link);
3304 staticpro (&Qfile_exists_p);
3305 staticpro (&Qfile_executable_p);
3306 staticpro (&Qfile_readable_p);
3307 staticpro (&Qfile_symlink_p);
3308 staticpro (&Qfile_writable_p);
3309 staticpro (&Qfile_directory_p);
3310 staticpro (&Qfile_accessible_directory_p);
3311 staticpro (&Qfile_modes);
3312 staticpro (&Qset_file_modes);
3313 staticpro (&Qfile_newer_than_file_p);
3314 staticpro (&Qinsert_file_contents);
3315 staticpro (&Qwrite_region);
3316 staticpro (&Qverify_visited_file_modtime);
3317
3318 Qfile_name_history = intern ("file-name-history");
3319 Fset (Qfile_name_history, Qnil);
3320 staticpro (&Qfile_name_history);
3321
3322 Qfile_error = intern ("file-error");
3323 staticpro (&Qfile_error);
3324 Qfile_already_exists = intern("file-already-exists");
3325 staticpro (&Qfile_already_exists);
3326
3327 Fput (Qfile_error, Qerror_conditions,
3328 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
3329 Fput (Qfile_error, Qerror_message,
3330 build_string ("File error"));
3331
3332 Fput (Qfile_already_exists, Qerror_conditions,
3333 Fcons (Qfile_already_exists,
3334 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
3335 Fput (Qfile_already_exists, Qerror_message,
3336 build_string ("File already exists"));
3337
3338 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
3339 "*Non-nil means when reading a filename start with default dir in minibuffer.");
3340 insert_default_directory = 1;
3341
3342 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
3343 "*Non-nil means write new files with record format `stmlf'.\n\
3344 nil means use format `var'. This variable is meaningful only on VMS.");
3345 vms_stmlf_recfm = 0;
3346
3347 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
3348 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
3349 If a file name matches REGEXP, then all I/O on that file is done by calling\n\
3350 HANDLER.\n\
3351 \n\
3352 The first argument given to HANDLER is the name of the I/O primitive\n\
3353 to be handled; the remaining arguments are the arguments that were\n\
3354 passed to that primitive. For example, if you do\n\
3355 (file-exists-p FILENAME)\n\
3356 and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
3357 (funcall HANDLER 'file-exists-p FILENAME)\n\
3358 The function `find-file-name-handler' checks this list for a handler\n\
3359 for its argument.");
3360 Vfile_name_handler_alist = Qnil;
3361
3362 defsubr (&Sfind_file_name_handler);
3363 defsubr (&Sfile_name_directory);
3364 defsubr (&Sfile_name_nondirectory);
3365 defsubr (&Sunhandled_file_name_directory);
3366 defsubr (&Sfile_name_as_directory);
3367 defsubr (&Sdirectory_file_name);
3368 defsubr (&Smake_temp_name);
3369 defsubr (&Sexpand_file_name);
3370 defsubr (&Ssubstitute_in_file_name);
3371 defsubr (&Scopy_file);
3372 defsubr (&Smake_directory_internal);
3373 defsubr (&Sdelete_directory);
3374 defsubr (&Sdelete_file);
3375 defsubr (&Srename_file);
3376 defsubr (&Sadd_name_to_file);
3377 #ifdef S_IFLNK
3378 defsubr (&Smake_symbolic_link);
3379 #endif /* S_IFLNK */
3380 #ifdef VMS
3381 defsubr (&Sdefine_logical_name);
3382 #endif /* VMS */
3383 #ifdef HPUX_NET
3384 defsubr (&Ssysnetunam);
3385 #endif /* HPUX_NET */
3386 defsubr (&Sfile_name_absolute_p);
3387 defsubr (&Sfile_exists_p);
3388 defsubr (&Sfile_executable_p);
3389 defsubr (&Sfile_readable_p);
3390 defsubr (&Sfile_writable_p);
3391 defsubr (&Sfile_symlink_p);
3392 defsubr (&Sfile_directory_p);
3393 defsubr (&Sfile_accessible_directory_p);
3394 defsubr (&Sfile_modes);
3395 defsubr (&Sset_file_modes);
3396 defsubr (&Sset_default_file_modes);
3397 defsubr (&Sdefault_file_modes);
3398 defsubr (&Sfile_newer_than_file_p);
3399 defsubr (&Sinsert_file_contents);
3400 defsubr (&Swrite_region);
3401 defsubr (&Sverify_visited_file_modtime);
3402 defsubr (&Sclear_visited_file_modtime);
3403 defsubr (&Svisited_file_modtime);
3404 defsubr (&Sset_visited_file_modtime);
3405 defsubr (&Sdo_auto_save);
3406 defsubr (&Sset_buffer_auto_saved);
3407 defsubr (&Srecent_auto_save_p);
3408
3409 defsubr (&Sread_file_name_internal);
3410 defsubr (&Sread_file_name);
3411
3412 #ifdef unix
3413 defsubr (&Sunix_sync);
3414 #endif
3415 }