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