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