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