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