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