(revert-buffer): Use new insert-file-contents replace arg.
[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
3d9f5ce2 47#include "vmsdir.h"
bfb61299
JB
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);
570d7624
JB
1530 if (!o) goto badvar;
1531 total += strlen (o);
1532 substituted = 1;
1533 }
1534
1535 if (!substituted)
1536 return string;
1537
1538 /* If substitution required, recopy the string and do it */
1539 /* Make space in stack frame for the new copy */
1540 xnm = (unsigned char *) alloca (XSTRING (string)->size + total + 1);
1541 x = xnm;
1542
1543 /* Copy the rest of the name through, replacing $ constructs with values */
1544 for (p = nm; *p;)
1545 if (*p != '$')
1546 *x++ = *p++;
1547 else
1548 {
1549 p++;
1550 if (p == endp)
1551 goto badsubst;
1552 else if (*p == '$')
1553 {
1554 *x++ = *p++;
1555 continue;
1556 }
1557 else if (*p == '{')
1558 {
1559 o = ++p;
1560 while (p != endp && *p != '}') p++;
1561 if (*p != '}') goto missingclose;
1562 s = p++;
1563 }
1564 else
1565 {
1566 o = p;
1567 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1568 s = p;
1569 }
1570
1571 /* Copy out the variable name */
1572 target = (unsigned char *) alloca (s - o + 1);
1573 strncpy (target, o, s - o);
1574 target[s - o] = 0;
4c3c22f3
RS
1575#ifdef MSDOS
1576 strupr (target); /* $home == $HOME etc. */
1577#endif
570d7624
JB
1578
1579 /* Get variable value */
1580 o = (unsigned char *) egetenv (target);
570d7624
JB
1581 if (!o)
1582 goto badvar;
1583
1584 strcpy (x, o);
1585 x += strlen (o);
1586 }
1587
1588 *x = 0;
1589
1590 /* If /~ or // appears, discard everything through first slash. */
1591
1592 for (p = xnm; p != x; p++)
1593 if ((p[0] == '~' ||
1594#ifdef APOLLO
1595 /* // at start of file name is meaningful in Apollo system */
1596 (p[0] == '/' && p - 1 != xnm)
1597#else /* not APOLLO */
1598 p[0] == '/'
1599#endif /* not APOLLO */
1600 )
1601 && p != nm && p[-1] == '/')
1602 xnm = p;
4c3c22f3
RS
1603#ifdef MSDOS
1604 else if (p[0] && p[1] == ':')
1605 xnm = p;
1606#endif
570d7624
JB
1607
1608 return make_string (xnm, x - xnm);
1609
1610 badsubst:
1611 error ("Bad format environment-variable substitution");
1612 missingclose:
1613 error ("Missing \"}\" in environment-variable substitution");
1614 badvar:
1615 error ("Substituting nonexistent environment variable \"%s\"", target);
1616
1617 /* NOTREACHED */
1618#endif /* not VMS */
1619}
1620\f
067ffa38 1621/* A slightly faster and more convenient way to get
298b760e 1622 (directory-file-name (expand-file-name FOO)). */
067ffa38 1623
570d7624
JB
1624Lisp_Object
1625expand_and_dir_to_file (filename, defdir)
1626 Lisp_Object filename, defdir;
1627{
1628 register Lisp_Object abspath;
1629
1630 abspath = Fexpand_file_name (filename, defdir);
1631#ifdef VMS
1632 {
1633 register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1];
1634 if (c == ':' || c == ']' || c == '>')
1635 abspath = Fdirectory_file_name (abspath);
1636 }
1637#else
1638 /* Remove final slash, if any (unless path is root).
1639 stat behaves differently depending! */
1640 if (XSTRING (abspath)->size > 1
1641 && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/')
ddc61f46
RS
1642 /* We cannot take shortcuts; they might be wrong for magic file names. */
1643 abspath = Fdirectory_file_name (abspath);
570d7624
JB
1644#endif
1645 return abspath;
1646}
1647\f
1648barf_or_query_if_file_exists (absname, querystring, interactive)
1649 Lisp_Object absname;
1650 unsigned char *querystring;
1651 int interactive;
1652{
1653 register Lisp_Object tem;
1654 struct gcpro gcpro1;
1655
1656 if (access (XSTRING (absname)->data, 4) >= 0)
1657 {
1658 if (! interactive)
1659 Fsignal (Qfile_already_exists,
1660 Fcons (build_string ("File already exists"),
1661 Fcons (absname, Qnil)));
1662 GCPRO1 (absname);
1663 tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
1664 XSTRING (absname)->data, querystring));
1665 UNGCPRO;
265a9e55 1666 if (NILP (tem))
570d7624
JB
1667 Fsignal (Qfile_already_exists,
1668 Fcons (build_string ("File already exists"),
1669 Fcons (absname, Qnil)));
1670 }
1671 return;
1672}
1673
1674DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4,
349a7710 1675 "fCopy file: \nFCopy %s to file: \np\nP",
570d7624
JB
1676 "Copy FILE to NEWNAME. Both args must be strings.\n\
1677Signals a `file-already-exists' error if file NEWNAME already exists,\n\
1678unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\
1679A number as third arg means request confirmation if NEWNAME already exists.\n\
1680This is what happens in interactive use with M-x.\n\
349a7710
JB
1681Fourth arg KEEP-TIME non-nil means give the new file the same\n\
1682last-modified time as the old one. (This works on only some systems.)\n\
1683A prefix arg makes KEEP-TIME non-nil.")
570d7624
JB
1684 (filename, newname, ok_if_already_exists, keep_date)
1685 Lisp_Object filename, newname, ok_if_already_exists, keep_date;
1686{
1687 int ifd, ofd, n;
1688 char buf[16 * 1024];
1689 struct stat st;
32f4334d 1690 Lisp_Object handler;
570d7624 1691 struct gcpro gcpro1, gcpro2;
b5148e85 1692 int count = specpdl_ptr - specpdl;
51cf6d37 1693 Lisp_Object args[6];
f73b0ada 1694 int input_file_statable_p;
570d7624
JB
1695
1696 GCPRO2 (filename, newname);
1697 CHECK_STRING (filename, 0);
1698 CHECK_STRING (newname, 1);
1699 filename = Fexpand_file_name (filename, Qnil);
1700 newname = Fexpand_file_name (newname, Qnil);
32f4334d 1701
0bf2eed2 1702 /* If the input file name has special constructs in it,
32f4334d 1703 call the corresponding file handler. */
642ef245 1704 handler = Ffind_file_name_handler (filename);
0bf2eed2 1705 /* Likewise for output file name. */
51cf6d37
RS
1706 if (NILP (handler))
1707 handler = Ffind_file_name_handler (newname);
32f4334d 1708 if (!NILP (handler))
51cf6d37
RS
1709 return call5 (handler, Qcopy_file, filename, newname,
1710 ok_if_already_exists, keep_date);
32f4334d 1711
265a9e55 1712 if (NILP (ok_if_already_exists)
570d7624
JB
1713 || XTYPE (ok_if_already_exists) == Lisp_Int)
1714 barf_or_query_if_file_exists (newname, "copy to it",
1715 XTYPE (ok_if_already_exists) == Lisp_Int);
1716
1717 ifd = open (XSTRING (filename)->data, 0);
1718 if (ifd < 0)
1719 report_file_error ("Opening input file", Fcons (filename, Qnil));
1720
b5148e85
RS
1721 record_unwind_protect (close_file_unwind, make_number (ifd));
1722
f73b0ada
BF
1723 /* We can only copy regular files and symbolic links. Other files are not
1724 copyable by us. */
1725 input_file_statable_p = (fstat (ifd, &st) >= 0);
1726
1727#if defined (S_ISREG) && defined (S_ISLNK)
1728 if (input_file_statable_p)
1729 {
1730 if (!(S_ISREG (st.st_mode)) && !(S_ISLNK (st.st_mode)))
1731 {
1732#if defined (EISDIR)
1733 /* Get a better looking error message. */
1734 errno = EISDIR;
1735#endif /* EISDIR */
1736 report_file_error ("Non-regular file", Fcons (filename, Qnil));
1737 }
1738 }
1739#endif /* S_ISREG && S_ISLNK */
1740
570d7624
JB
1741#ifdef VMS
1742 /* Create the copy file with the same record format as the input file */
1743 ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
1744#else
4c3c22f3
RS
1745#ifdef MSDOS
1746 /* System's default file type was set to binary by _fmode in emacs.c. */
1747 ofd = creat (XSTRING (newname)->data, S_IREAD | S_IWRITE);
1748#else /* not MSDOS */
570d7624 1749 ofd = creat (XSTRING (newname)->data, 0666);
4c3c22f3 1750#endif /* not MSDOS */
570d7624
JB
1751#endif /* VMS */
1752 if (ofd < 0)
66331187 1753 report_file_error ("Opening output file", Fcons (newname, Qnil));
b5148e85
RS
1754
1755 record_unwind_protect (close_file_unwind, make_number (ofd));
570d7624 1756
b5148e85
RS
1757 immediate_quit = 1;
1758 QUIT;
570d7624
JB
1759 while ((n = read (ifd, buf, sizeof buf)) > 0)
1760 if (write (ofd, buf, n) != n)
66331187 1761 report_file_error ("I/O error", Fcons (newname, Qnil));
b5148e85 1762 immediate_quit = 0;
570d7624 1763
f73b0ada 1764 if (input_file_statable_p)
570d7624 1765 {
265a9e55 1766 if (!NILP (keep_date))
570d7624 1767 {
de5bf5d3
JB
1768 EMACS_TIME atime, mtime;
1769 EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
1770 EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
1771 EMACS_SET_UTIMES (XSTRING (newname)->data, atime, mtime);
570d7624 1772 }
570d7624
JB
1773#ifdef APOLLO
1774 if (!egetenv ("USE_DOMAIN_ACLS"))
1775#endif
de5bf5d3 1776 chmod (XSTRING (newname)->data, st.st_mode & 07777);
570d7624
JB
1777 }
1778
b5148e85
RS
1779 /* Discard the unwind protects. */
1780 specpdl_ptr = specpdl + count;
1781
570d7624
JB
1782 close (ifd);
1783 if (close (ofd) < 0)
1784 report_file_error ("I/O error", Fcons (newname, Qnil));
1785
1786 UNGCPRO;
1787 return Qnil;
1788}
1789
9bbe01fb 1790DEFUN ("make-directory-internal", Fmake_directory_internal,
353cfc19 1791 Smake_directory_internal, 1, 1, 0,
570d7624
JB
1792 "Create a directory. One argument, a file name string.")
1793 (dirname)
1794 Lisp_Object dirname;
1795{
1796 unsigned char *dir;
32f4334d 1797 Lisp_Object handler;
570d7624
JB
1798
1799 CHECK_STRING (dirname, 0);
1800 dirname = Fexpand_file_name (dirname, Qnil);
32f4334d 1801
642ef245 1802 handler = Ffind_file_name_handler (dirname);
32f4334d 1803 if (!NILP (handler))
9bbe01fb
RS
1804 return call3 (handler, Qmake_directory, dirname, Qnil);
1805
570d7624
JB
1806 dir = XSTRING (dirname)->data;
1807
1808 if (mkdir (dir, 0777) != 0)
1809 report_file_error ("Creating directory", Flist (1, &dirname));
1810
32f4334d 1811 return Qnil;
570d7624
JB
1812}
1813
aa734e17
RS
1814DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
1815 "Delete a directory. One argument, a file name string.")
570d7624
JB
1816 (dirname)
1817 Lisp_Object dirname;
1818{
1819 unsigned char *dir;
32f4334d 1820 Lisp_Object handler;
570d7624
JB
1821
1822 CHECK_STRING (dirname, 0);
1823 dirname = Fexpand_file_name (dirname, Qnil);
1824 dir = XSTRING (dirname)->data;
1825
642ef245 1826 handler = Ffind_file_name_handler (dirname);
32f4334d
RS
1827 if (!NILP (handler))
1828 return call2 (handler, Qdelete_directory, dirname);
1829
570d7624
JB
1830 if (rmdir (dir) != 0)
1831 report_file_error ("Removing directory", Flist (1, &dirname));
1832
1833 return Qnil;
1834}
1835
1836DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
1837 "Delete specified file. One argument, a file name string.\n\
1838If file has multiple names, it continues to exist with the other names.")
1839 (filename)
1840 Lisp_Object filename;
1841{
32f4334d 1842 Lisp_Object handler;
570d7624
JB
1843 CHECK_STRING (filename, 0);
1844 filename = Fexpand_file_name (filename, Qnil);
32f4334d 1845
642ef245 1846 handler = Ffind_file_name_handler (filename);
32f4334d
RS
1847 if (!NILP (handler))
1848 return call2 (handler, Qdelete_file, filename);
1849
570d7624
JB
1850 if (0 > unlink (XSTRING (filename)->data))
1851 report_file_error ("Removing old name", Flist (1, &filename));
1852 return Qnil;
1853}
1854
1855DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
1856 "fRename file: \nFRename %s to file: \np",
1857 "Rename FILE as NEWNAME. Both args strings.\n\
1858If file has names other than FILE, it continues to have those names.\n\
1859Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1860unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1861A number as third arg means request confirmation if NEWNAME already exists.\n\
1862This is what happens in interactive use with M-x.")
1863 (filename, newname, ok_if_already_exists)
1864 Lisp_Object filename, newname, ok_if_already_exists;
1865{
1866#ifdef NO_ARG_ARRAY
1867 Lisp_Object args[2];
1868#endif
32f4334d 1869 Lisp_Object handler;
570d7624
JB
1870 struct gcpro gcpro1, gcpro2;
1871
1872 GCPRO2 (filename, newname);
1873 CHECK_STRING (filename, 0);
1874 CHECK_STRING (newname, 1);
1875 filename = Fexpand_file_name (filename, Qnil);
1876 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1877
1878 /* If the file name has special constructs in it,
1879 call the corresponding file handler. */
642ef245 1880 handler = Ffind_file_name_handler (filename);
51cf6d37
RS
1881 if (NILP (handler))
1882 handler = Ffind_file_name_handler (newname);
32f4334d 1883 if (!NILP (handler))
a5a44b91
JB
1884 return call4 (handler, Qrename_file,
1885 filename, newname, ok_if_already_exists);
32f4334d 1886
265a9e55 1887 if (NILP (ok_if_already_exists)
570d7624
JB
1888 || XTYPE (ok_if_already_exists) == Lisp_Int)
1889 barf_or_query_if_file_exists (newname, "rename to it",
1890 XTYPE (ok_if_already_exists) == Lisp_Int);
1891#ifndef BSD4_1
1892 if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
1893#else
1894 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data)
1895 || 0 > unlink (XSTRING (filename)->data))
1896#endif
1897 {
1898 if (errno == EXDEV)
1899 {
d093c3ac
RM
1900 Fcopy_file (filename, newname,
1901 /* We have already prompted if it was an integer,
1902 so don't have copy-file prompt again. */
1903 NILP (ok_if_already_exists) ? Qnil : Qt, Qt);
570d7624
JB
1904 Fdelete_file (filename);
1905 }
1906 else
1907#ifdef NO_ARG_ARRAY
1908 {
1909 args[0] = filename;
1910 args[1] = newname;
1911 report_file_error ("Renaming", Flist (2, args));
1912 }
1913#else
1914 report_file_error ("Renaming", Flist (2, &filename));
1915#endif
1916 }
1917 UNGCPRO;
1918 return Qnil;
1919}
1920
1921DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3,
1922 "fAdd name to file: \nFName to add to %s: \np",
1923 "Give FILE additional name NEWNAME. Both args strings.\n\
1924Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1925unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1926A number as third arg means request confirmation if NEWNAME already exists.\n\
1927This is what happens in interactive use with M-x.")
1928 (filename, newname, ok_if_already_exists)
1929 Lisp_Object filename, newname, ok_if_already_exists;
1930{
1931#ifdef NO_ARG_ARRAY
1932 Lisp_Object args[2];
1933#endif
32f4334d 1934 Lisp_Object handler;
570d7624
JB
1935 struct gcpro gcpro1, gcpro2;
1936
1937 GCPRO2 (filename, newname);
1938 CHECK_STRING (filename, 0);
1939 CHECK_STRING (newname, 1);
1940 filename = Fexpand_file_name (filename, Qnil);
1941 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1942
1943 /* If the file name has special constructs in it,
1944 call the corresponding file handler. */
642ef245 1945 handler = Ffind_file_name_handler (filename);
32f4334d 1946 if (!NILP (handler))
51cf6d37
RS
1947 return call4 (handler, Qadd_name_to_file, filename, newname,
1948 ok_if_already_exists);
32f4334d 1949
265a9e55 1950 if (NILP (ok_if_already_exists)
570d7624
JB
1951 || XTYPE (ok_if_already_exists) == Lisp_Int)
1952 barf_or_query_if_file_exists (newname, "make it a new name",
1953 XTYPE (ok_if_already_exists) == Lisp_Int);
1954 unlink (XSTRING (newname)->data);
1955 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data))
1956 {
1957#ifdef NO_ARG_ARRAY
1958 args[0] = filename;
1959 args[1] = newname;
1960 report_file_error ("Adding new name", Flist (2, args));
1961#else
1962 report_file_error ("Adding new name", Flist (2, &filename));
1963#endif
1964 }
1965
1966 UNGCPRO;
1967 return Qnil;
1968}
1969
1970#ifdef S_IFLNK
1971DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
1972 "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",
1973 "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\
1974Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1975unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1976A number as third arg means request confirmation if NEWNAME already exists.\n\
1977This happens for interactive use with M-x.")
e5d77022
JB
1978 (filename, linkname, ok_if_already_exists)
1979 Lisp_Object filename, linkname, ok_if_already_exists;
570d7624
JB
1980{
1981#ifdef NO_ARG_ARRAY
1982 Lisp_Object args[2];
1983#endif
32f4334d 1984 Lisp_Object handler;
570d7624
JB
1985 struct gcpro gcpro1, gcpro2;
1986
e5d77022 1987 GCPRO2 (filename, linkname);
570d7624 1988 CHECK_STRING (filename, 0);
e5d77022 1989 CHECK_STRING (linkname, 1);
d9bc1c99
RS
1990 /* If the link target has a ~, we must expand it to get
1991 a truly valid file name. Otherwise, do not expand;
1992 we want to permit links to relative file names. */
1993 if (XSTRING (filename)->data[0] == '~')
1994 filename = Fexpand_file_name (filename, Qnil);
e5d77022 1995 linkname = Fexpand_file_name (linkname, Qnil);
32f4334d
RS
1996
1997 /* If the file name has special constructs in it,
1998 call the corresponding file handler. */
642ef245 1999 handler = Ffind_file_name_handler (filename);
32f4334d 2000 if (!NILP (handler))
51cf6d37
RS
2001 return call4 (handler, Qmake_symbolic_link, filename, linkname,
2002 ok_if_already_exists);
32f4334d 2003
265a9e55 2004 if (NILP (ok_if_already_exists)
570d7624 2005 || XTYPE (ok_if_already_exists) == Lisp_Int)
e5d77022 2006 barf_or_query_if_file_exists (linkname, "make it a link",
570d7624 2007 XTYPE (ok_if_already_exists) == Lisp_Int);
e5d77022 2008 if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
2009 {
2010 /* If we didn't complain already, silently delete existing file. */
2011 if (errno == EEXIST)
2012 {
9083124b 2013 unlink (XSTRING (linkname)->data);
e5d77022 2014 if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
2015 return Qnil;
2016 }
2017
2018#ifdef NO_ARG_ARRAY
2019 args[0] = filename;
e5d77022 2020 args[1] = linkname;
570d7624
JB
2021 report_file_error ("Making symbolic link", Flist (2, args));
2022#else
2023 report_file_error ("Making symbolic link", Flist (2, &filename));
2024#endif
2025 }
2026 UNGCPRO;
2027 return Qnil;
2028}
2029#endif /* S_IFLNK */
2030
2031#ifdef VMS
2032
2033DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
2034 2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
2035 "Define the job-wide logical name NAME to have the value STRING.\n\
2036If STRING is nil or a null string, the logical name NAME is deleted.")
2037 (varname, string)
2038 Lisp_Object varname;
2039 Lisp_Object string;
2040{
2041 CHECK_STRING (varname, 0);
265a9e55 2042 if (NILP (string))
570d7624
JB
2043 delete_logical_name (XSTRING (varname)->data);
2044 else
2045 {
2046 CHECK_STRING (string, 1);
2047
2048 if (XSTRING (string)->size == 0)
2049 delete_logical_name (XSTRING (varname)->data);
2050 else
2051 define_logical_name (XSTRING (varname)->data, XSTRING (string)->data);
2052 }
2053
2054 return string;
2055}
2056#endif /* VMS */
2057
2058#ifdef HPUX_NET
2059
2060DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
2061 "Open a network connection to PATH using LOGIN as the login string.")
2062 (path, login)
2063 Lisp_Object path, login;
2064{
2065 int netresult;
2066
2067 CHECK_STRING (path, 0);
2068 CHECK_STRING (login, 0);
2069
2070 netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
2071
2072 if (netresult == -1)
2073 return Qnil;
2074 else
2075 return Qt;
2076}
2077#endif /* HPUX_NET */
2078\f
2079DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
2080 1, 1, 0,
2081 "Return t if file FILENAME specifies an absolute path name.\n\
2082On Unix, this is a name starting with a `/' or a `~'.")
2083 (filename)
2084 Lisp_Object filename;
2085{
2086 unsigned char *ptr;
2087
2088 CHECK_STRING (filename, 0);
2089 ptr = XSTRING (filename)->data;
2090 if (*ptr == '/' || *ptr == '~'
2091#ifdef VMS
2092/* ??? This criterion is probably wrong for '<'. */
2093 || index (ptr, ':') || index (ptr, '<')
2094 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
2095 && ptr[1] != '.')
2096#endif /* VMS */
4c3c22f3
RS
2097#ifdef MSDOS
2098 || (*ptr != 0 && ptr[1] == ':' && ptr[2] == '/')
2099#endif
570d7624
JB
2100 )
2101 return Qt;
2102 else
2103 return Qnil;
2104}
2105
2106DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
2107 "Return t if file FILENAME exists. (This does not mean you can read it.)\n\
2108See also `file-readable-p' and `file-attributes'.")
2109 (filename)
2110 Lisp_Object filename;
2111{
2112 Lisp_Object abspath;
32f4334d 2113 Lisp_Object handler;
570d7624
JB
2114
2115 CHECK_STRING (filename, 0);
2116 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2117
2118 /* If the file name has special constructs in it,
2119 call the corresponding file handler. */
642ef245 2120 handler = Ffind_file_name_handler (abspath);
32f4334d 2121 if (!NILP (handler))
09121adc 2122 return call2 (handler, Qfile_exists_p, abspath);
32f4334d 2123
570d7624
JB
2124 return (access (XSTRING (abspath)->data, 0) >= 0) ? Qt : Qnil;
2125}
2126
2127DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
2128 "Return t if FILENAME can be executed by you.\n\
8b235fde 2129For a directory, this means you can access files in that directory.")
570d7624
JB
2130 (filename)
2131 Lisp_Object filename;
2132
2133{
2134 Lisp_Object abspath;
32f4334d 2135 Lisp_Object handler;
570d7624
JB
2136
2137 CHECK_STRING (filename, 0);
2138 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2139
2140 /* If the file name has special constructs in it,
2141 call the corresponding file handler. */
642ef245 2142 handler = Ffind_file_name_handler (abspath);
32f4334d 2143 if (!NILP (handler))
09121adc 2144 return call2 (handler, Qfile_executable_p, abspath);
32f4334d 2145
570d7624
JB
2146 return (access (XSTRING (abspath)->data, 1) >= 0) ? Qt : Qnil;
2147}
2148
2149DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
2150 "Return t if file FILENAME exists and you can read it.\n\
2151See also `file-exists-p' and `file-attributes'.")
2152 (filename)
2153 Lisp_Object filename;
2154{
2155 Lisp_Object abspath;
32f4334d 2156 Lisp_Object handler;
570d7624
JB
2157
2158 CHECK_STRING (filename, 0);
2159 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2160
2161 /* If the file name has special constructs in it,
2162 call the corresponding file handler. */
642ef245 2163 handler = Ffind_file_name_handler (abspath);
32f4334d 2164 if (!NILP (handler))
09121adc 2165 return call2 (handler, Qfile_readable_p, abspath);
32f4334d 2166
570d7624
JB
2167 return (access (XSTRING (abspath)->data, 4) >= 0) ? Qt : Qnil;
2168}
2169
2170DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
89de89c7
RS
2171 "Return non-nil if file FILENAME is the name of a symbolic link.\n\
2172The value is the name of the file to which it is linked.\n\
2173Otherwise returns nil.")
570d7624
JB
2174 (filename)
2175 Lisp_Object filename;
2176{
2177#ifdef S_IFLNK
2178 char *buf;
2179 int bufsize;
2180 int valsize;
2181 Lisp_Object val;
32f4334d 2182 Lisp_Object handler;
570d7624
JB
2183
2184 CHECK_STRING (filename, 0);
2185 filename = Fexpand_file_name (filename, Qnil);
2186
32f4334d
RS
2187 /* If the file name has special constructs in it,
2188 call the corresponding file handler. */
642ef245 2189 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2190 if (!NILP (handler))
2191 return call2 (handler, Qfile_symlink_p, filename);
2192
570d7624
JB
2193 bufsize = 100;
2194 while (1)
2195 {
2196 buf = (char *) xmalloc (bufsize);
2197 bzero (buf, bufsize);
2198 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
2199 if (valsize < bufsize) break;
2200 /* Buffer was not long enough */
9ac0d9e0 2201 xfree (buf);
570d7624
JB
2202 bufsize *= 2;
2203 }
2204 if (valsize == -1)
2205 {
9ac0d9e0 2206 xfree (buf);
570d7624
JB
2207 return Qnil;
2208 }
2209 val = make_string (buf, valsize);
9ac0d9e0 2210 xfree (buf);
570d7624
JB
2211 return val;
2212#else /* not S_IFLNK */
2213 return Qnil;
2214#endif /* not S_IFLNK */
2215}
2216
a253bab2
JB
2217#ifdef SOLARIS_BROKEN_ACCESS
2218/* In Solaris 2.1, the readonly-ness of the filesystem is not
2219 considered by the access system call. This is Sun's bug, but we
2220 still have to make Emacs work. */
2221
2222#include <sys/statvfs.h>
2223
2224static int
2225ro_fsys (path)
2226 char *path;
2227{
2228 struct statvfs statvfsb;
2229
2230 if (statvfs(path, &statvfsb))
2231 return 1; /* error from statvfs, be conservative and say not wrtable */
2232 else
2233 /* Otherwise, fsys is ro if bit is set. */
2234 return statvfsb.f_flag & ST_RDONLY;
2235}
2236#else
2237/* But on every other os, access has already done the right thing. */
2238#define ro_fsys(path) 0
2239#endif
2240
570d7624
JB
2241/* Having this before file-symlink-p mysteriously caused it to be forgotten
2242 on the RT/PC. */
2243DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
2244 "Return t if file FILENAME can be written or created by you.")
2245 (filename)
2246 Lisp_Object filename;
2247{
2248 Lisp_Object abspath, dir;
32f4334d 2249 Lisp_Object handler;
570d7624
JB
2250
2251 CHECK_STRING (filename, 0);
2252 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2253
2254 /* If the file name has special constructs in it,
2255 call the corresponding file handler. */
642ef245 2256 handler = Ffind_file_name_handler (abspath);
32f4334d 2257 if (!NILP (handler))
09121adc 2258 return call2 (handler, Qfile_writable_p, abspath);
32f4334d 2259
570d7624 2260 if (access (XSTRING (abspath)->data, 0) >= 0)
a253bab2 2261 return ((access (XSTRING (abspath)->data, 2) >= 0
e7c7295c 2262 && ! ro_fsys ((char *) XSTRING (abspath)->data))
a253bab2 2263 ? Qt : Qnil);
570d7624
JB
2264 dir = Ffile_name_directory (abspath);
2265#ifdef VMS
265a9e55 2266 if (!NILP (dir))
570d7624
JB
2267 dir = Fdirectory_file_name (dir);
2268#endif /* VMS */
4c3c22f3
RS
2269#ifdef MSDOS
2270 if (!NILP (dir))
2271 dir = Fdirectory_file_name (dir);
2272#endif /* MSDOS */
a253bab2 2273 return ((access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
e7c7295c 2274 && ! ro_fsys ((char *) XSTRING (dir)->data))
570d7624
JB
2275 ? Qt : Qnil);
2276}
2277
2278DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
2279 "Return t if file FILENAME is the name of a directory as a file.\n\
2280A directory name spec may be given instead; then the value is t\n\
2281if the directory so specified exists and really is a directory.")
2282 (filename)
2283 Lisp_Object filename;
2284{
2285 register Lisp_Object abspath;
2286 struct stat st;
32f4334d 2287 Lisp_Object handler;
570d7624
JB
2288
2289 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2290
32f4334d
RS
2291 /* If the file name has special constructs in it,
2292 call the corresponding file handler. */
642ef245 2293 handler = Ffind_file_name_handler (abspath);
32f4334d 2294 if (!NILP (handler))
09121adc 2295 return call2 (handler, Qfile_directory_p, abspath);
32f4334d 2296
570d7624
JB
2297 if (stat (XSTRING (abspath)->data, &st) < 0)
2298 return Qnil;
2299 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2300}
2301
b72dea2a
JB
2302DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
2303 "Return t if file FILENAME is the name of a directory as a file,\n\
2304and files in that directory can be opened by you. In order to use a\n\
2305directory as a buffer's current directory, this predicate must return true.\n\
2306A directory name spec may be given instead; then the value is t\n\
2307if the directory so specified exists and really is a readable and\n\
2308searchable directory.")
2309 (filename)
2310 Lisp_Object filename;
2311{
32f4334d
RS
2312 Lisp_Object handler;
2313
2314 /* If the file name has special constructs in it,
2315 call the corresponding file handler. */
642ef245 2316 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2317 if (!NILP (handler))
2318 return call2 (handler, Qfile_accessible_directory_p, filename);
2319
b72dea2a
JB
2320 if (NILP (Ffile_directory_p (filename))
2321 || NILP (Ffile_executable_p (filename)))
2322 return Qnil;
2323 else
2324 return Qt;
2325}
2326
570d7624
JB
2327DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2328 "Return mode bits of FILE, as an integer.")
2329 (filename)
2330 Lisp_Object filename;
2331{
2332 Lisp_Object abspath;
2333 struct stat st;
32f4334d 2334 Lisp_Object handler;
570d7624
JB
2335
2336 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2337
32f4334d
RS
2338 /* If the file name has special constructs in it,
2339 call the corresponding file handler. */
642ef245 2340 handler = Ffind_file_name_handler (abspath);
32f4334d 2341 if (!NILP (handler))
09121adc 2342 return call2 (handler, Qfile_modes, abspath);
32f4334d 2343
570d7624
JB
2344 if (stat (XSTRING (abspath)->data, &st) < 0)
2345 return Qnil;
2346 return make_number (st.st_mode & 07777);
2347}
2348
2349DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2350 "Set mode bits of FILE to MODE (an integer).\n\
2351Only the 12 low bits of MODE are used.")
2352 (filename, mode)
2353 Lisp_Object filename, mode;
2354{
2355 Lisp_Object abspath;
32f4334d 2356 Lisp_Object handler;
570d7624
JB
2357
2358 abspath = Fexpand_file_name (filename, current_buffer->directory);
2359 CHECK_NUMBER (mode, 1);
2360
32f4334d
RS
2361 /* If the file name has special constructs in it,
2362 call the corresponding file handler. */
642ef245 2363 handler = Ffind_file_name_handler (abspath);
32f4334d 2364 if (!NILP (handler))
09121adc 2365 return call3 (handler, Qset_file_modes, abspath, mode);
32f4334d 2366
570d7624
JB
2367#ifndef APOLLO
2368 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2369 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2370#else /* APOLLO */
2371 if (!egetenv ("USE_DOMAIN_ACLS"))
2372 {
2373 struct stat st;
2374 struct timeval tvp[2];
2375
2376 /* chmod on apollo also change the file's modtime; need to save the
2377 modtime and then restore it. */
2378 if (stat (XSTRING (abspath)->data, &st) < 0)
2379 {
2380 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2381 return (Qnil);
2382 }
2383
2384 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2385 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2386
2387 /* reset the old accessed and modified times. */
2388 tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
2389 tvp[0].tv_usec = 0;
2390 tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
2391 tvp[1].tv_usec = 0;
2392
2393 if (utimes (XSTRING (abspath)->data, tvp) < 0)
2394 report_file_error ("Doing utimes", Fcons (abspath, Qnil));
2395 }
2396#endif /* APOLLO */
2397
2398 return Qnil;
2399}
2400
c24e9a53 2401DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
5f85ea58
RS
2402 "Set the file permission bits for newly created files.\n\
2403The argument MODE should be an integer; only the low 9 bits are used.\n\
36a8c287 2404This setting is inherited by subprocesses.")
5f85ea58
RS
2405 (mode)
2406 Lisp_Object mode;
36a8c287 2407{
5f85ea58 2408 CHECK_NUMBER (mode, 0);
36a8c287 2409
5f85ea58 2410 umask ((~ XINT (mode)) & 0777);
36a8c287
JB
2411
2412 return Qnil;
2413}
2414
c24e9a53 2415DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
5f85ea58
RS
2416 "Return the default file protection for created files.\n\
2417The value is an integer.")
36a8c287
JB
2418 ()
2419{
5f85ea58
RS
2420 int realmask;
2421 Lisp_Object value;
36a8c287 2422
5f85ea58
RS
2423 realmask = umask (0);
2424 umask (realmask);
36a8c287 2425
5f85ea58
RS
2426 XSET (value, Lisp_Int, (~ realmask) & 0777);
2427 return value;
36a8c287
JB
2428}
2429
85ffea93
RS
2430#ifdef unix
2431
2432DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2433 "Tell Unix to finish all pending disk updates.")
2434 ()
2435{
2436 sync ();
2437 return Qnil;
2438}
2439
2440#endif /* unix */
2441
570d7624
JB
2442DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2443 "Return t if file FILE1 is newer than file FILE2.\n\
2444If FILE1 does not exist, the answer is nil;\n\
2445otherwise, if FILE2 does not exist, the answer is t.")
2446 (file1, file2)
2447 Lisp_Object file1, file2;
2448{
32f4334d 2449 Lisp_Object abspath1, abspath2;
570d7624
JB
2450 struct stat st;
2451 int mtime1;
32f4334d 2452 Lisp_Object handler;
09121adc 2453 struct gcpro gcpro1, gcpro2;
570d7624
JB
2454
2455 CHECK_STRING (file1, 0);
2456 CHECK_STRING (file2, 0);
2457
09121adc
RS
2458 abspath1 = Qnil;
2459 GCPRO2 (abspath1, file2);
32f4334d
RS
2460 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2461 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
09121adc 2462 UNGCPRO;
570d7624 2463
32f4334d
RS
2464 /* If the file name has special constructs in it,
2465 call the corresponding file handler. */
642ef245 2466 handler = Ffind_file_name_handler (abspath1);
51cf6d37
RS
2467 if (NILP (handler))
2468 handler = Ffind_file_name_handler (abspath2);
32f4334d
RS
2469 if (!NILP (handler))
2470 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2471
2472 if (stat (XSTRING (abspath1)->data, &st) < 0)
570d7624
JB
2473 return Qnil;
2474
2475 mtime1 = st.st_mtime;
2476
32f4334d 2477 if (stat (XSTRING (abspath2)->data, &st) < 0)
570d7624
JB
2478 return Qt;
2479
2480 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2481}
2482\f
4c3c22f3
RS
2483#ifdef MSDOS
2484Lisp_Object Qfind_buffer_file_type;
2485#endif
2486
570d7624 2487DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
7fded690 2488 1, 4, 0,
570d7624 2489 "Insert contents of file FILENAME after point.\n\
7fded690 2490Returns list of absolute file name and length of data inserted.\n\
570d7624
JB
2491If second argument VISIT is non-nil, the buffer's visited filename\n\
2492and last save file modtime are set, and it is marked unmodified.\n\
2493If visiting and the file does not exist, visiting is completed\n\
7fded690
JB
2494before the error is signaled.\n\n\
2495The optional third and fourth arguments BEG and END\n\
2496specify what portion of the file to insert.\n\
2497If VISIT is non-nil, BEG and END must be nil.")
2498 (filename, visit, beg, end)
2499 Lisp_Object filename, visit, beg, end;
570d7624
JB
2500{
2501 struct stat st;
2502 register int fd;
2503 register int inserted = 0;
2504 register int how_much;
2505 int count = specpdl_ptr - specpdl;
d6a3cc15
RS
2506 struct gcpro gcpro1, gcpro2;
2507 Lisp_Object handler, val, insval;
2508 Lisp_Object p;
7fded690 2509 int total;
32f4334d
RS
2510
2511 val = Qnil;
d6a3cc15 2512 p = Qnil;
32f4334d 2513
d6a3cc15 2514 GCPRO2 (filename, p);
265a9e55 2515 if (!NILP (current_buffer->read_only))
570d7624
JB
2516 Fbarf_if_buffer_read_only();
2517
2518 CHECK_STRING (filename, 0);
2519 filename = Fexpand_file_name (filename, Qnil);
2520
32f4334d
RS
2521 /* If the file name has special constructs in it,
2522 call the corresponding file handler. */
642ef245 2523 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2524 if (!NILP (handler))
2525 {
7fded690 2526 val = call5 (handler, Qinsert_file_contents, filename, visit, beg, end);
32f4334d
RS
2527 goto handled;
2528 }
2529
570d7624
JB
2530 fd = -1;
2531
2532#ifndef APOLLO
2533 if (stat (XSTRING (filename)->data, &st) < 0
349a7710 2534 || (fd = open (XSTRING (filename)->data, 0)) < 0)
570d7624
JB
2535#else
2536 if ((fd = open (XSTRING (filename)->data, 0)) < 0
2537 || fstat (fd, &st) < 0)
2538#endif /* not APOLLO */
2539 {
2540 if (fd >= 0) close (fd);
265a9e55 2541 if (NILP (visit))
570d7624
JB
2542 report_file_error ("Opening input file", Fcons (filename, Qnil));
2543 st.st_mtime = -1;
2544 how_much = 0;
2545 goto notfound;
2546 }
2547
2548 record_unwind_protect (close_file_unwind, make_number (fd));
2549
be53b411
JB
2550#ifdef S_IFSOCK
2551 /* This code will need to be changed in order to work on named
2552 pipes, and it's probably just not worth it. So we should at
2553 least signal an error. */
2554 if ((st.st_mode & S_IFMT) == S_IFSOCK)
2555 Fsignal (Qfile_error,
2556 Fcons (build_string ("reading from named pipe"),
2557 Fcons (filename, Qnil)));
2558#endif
2559
570d7624
JB
2560 /* Supposedly happens on VMS. */
2561 if (st.st_size < 0)
2562 error ("File size is negative");
be53b411 2563
7fded690
JB
2564 if (!NILP (beg) || !NILP (end))
2565 if (!NILP (visit))
2566 error ("Attempt to visit less than an entire file");
2567
2568 if (!NILP (beg))
2569 CHECK_NUMBER (beg, 0);
2570 else
2571 XFASTINT (beg) = 0;
2572
2573 if (!NILP (end))
2574 CHECK_NUMBER (end, 0);
2575 else
2576 {
2577 XSETINT (end, st.st_size);
2578 if (XINT (end) != st.st_size)
2579 error ("maximum buffer size exceeded");
2580 }
2581
2582 total = XINT (end) - XINT (beg);
2583
570d7624
JB
2584 {
2585 register Lisp_Object temp;
2586
2587 /* Make sure point-max won't overflow after this insertion. */
7fded690
JB
2588 XSET (temp, Lisp_Int, total);
2589 if (total != XINT (temp))
570d7624
JB
2590 error ("maximum buffer size exceeded");
2591 }
2592
57d8d468 2593 if (NILP (visit) && total > 0)
570d7624
JB
2594 prepare_to_modify_buffer (point, point);
2595
2596 move_gap (point);
7fded690
JB
2597 if (GAP_SIZE < total)
2598 make_gap (total - GAP_SIZE);
2599
2600 if (XINT (beg) != 0)
2601 {
2602 if (lseek (fd, XINT (beg), 0) < 0)
2603 report_file_error ("Setting file position", Fcons (filename, Qnil));
2604 }
2605
570d7624
JB
2606 while (1)
2607 {
7fded690 2608 int try = min (total - inserted, 64 << 10);
b5148e85
RS
2609 int this;
2610
2611 /* Allow quitting out of the actual I/O. */
2612 immediate_quit = 1;
2613 QUIT;
2614 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2615 immediate_quit = 0;
570d7624
JB
2616
2617 if (this <= 0)
2618 {
2619 how_much = this;
2620 break;
2621 }
2622
2623 GPT += this;
2624 GAP_SIZE -= this;
2625 ZV += this;
2626 Z += this;
2627 inserted += this;
2628 }
2629
4c3c22f3
RS
2630#ifdef MSDOS
2631 /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
2632 /* Determine file type from name and remove LFs from CR-LFs if the file
2633 is deemed to be a text file. */
2634 {
2635 struct gcpro gcpro1;
2636 Lisp_Object code = Qnil;
2637 GCPRO1 (filename);
2638 code = call1 (Qfind_buffer_file_type, filename);
2639 UNGCPRO;
2640 if (XTYPE (code) == Lisp_Int)
2641 XFASTINT (current_buffer->buffer_file_type) = XFASTINT (code);
2642 if (XFASTINT (current_buffer->buffer_file_type) == 0)
2643 {
2644 int reduced_size =
2645 inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
2646 ZV -= reduced_size;
2647 Z -= reduced_size;
2648 GPT -= reduced_size;
2649 GAP_SIZE += reduced_size;
2650 inserted -= reduced_size;
2651 }
2652 }
2653#endif
2654
570d7624 2655 if (inserted > 0)
7d8451f1
RS
2656 {
2657 record_insert (point, inserted);
8d4e077b
JA
2658
2659 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2660 offset_intervals (current_buffer, point, inserted);
7d8451f1
RS
2661 MODIFF++;
2662 }
570d7624
JB
2663
2664 close (fd);
2665
2666 /* Discard the unwind protect */
2667 specpdl_ptr = specpdl + count;
2668
2669 if (how_much < 0)
2670 error ("IO error reading %s: %s",
ce97267f 2671 XSTRING (filename)->data, strerror (errno));
570d7624
JB
2672
2673 notfound:
32f4334d 2674 handled:
570d7624 2675
265a9e55 2676 if (!NILP (visit))
570d7624
JB
2677 {
2678 current_buffer->undo_list = Qnil;
2679#ifdef APOLLO
2680 stat (XSTRING (filename)->data, &st);
2681#endif
62bcf009 2682
a7e82472
RS
2683 if (NILP (handler))
2684 {
2685 current_buffer->modtime = st.st_mtime;
2686 current_buffer->filename = filename;
2687 }
62bcf009 2688
570d7624
JB
2689 current_buffer->save_modified = MODIFF;
2690 current_buffer->auto_save_modified = MODIFF;
2691 XFASTINT (current_buffer->save_length) = Z - BEG;
2692#ifdef CLASH_DETECTION
32f4334d
RS
2693 if (NILP (handler))
2694 {
2695 if (!NILP (current_buffer->filename))
2696 unlock_file (current_buffer->filename);
2697 unlock_file (filename);
2698 }
570d7624 2699#endif /* CLASH_DETECTION */
570d7624 2700 /* If visiting nonexistent file, return nil. */
32f4334d 2701 if (current_buffer->modtime == -1)
570d7624
JB
2702 report_file_error ("Opening input file", Fcons (filename, Qnil));
2703 }
2704
62bcf009 2705 if (inserted > 0 && NILP (visit) && total > 0)
d2cad97d 2706 signal_after_change (point, 0, inserted);
570d7624 2707
d6a3cc15
RS
2708 if (inserted > 0)
2709 {
2710 p = Vafter_insert_file_functions;
2711 while (!NILP (p))
2712 {
2713 insval = call1 (Fcar (p), make_number (inserted));
2714 if (!NILP (insval))
2715 {
2716 CHECK_NUMBER (insval, 0);
2717 inserted = XFASTINT (insval);
2718 }
2719 QUIT;
2720 p = Fcdr (p);
2721 }
2722 }
2723
32f4334d
RS
2724 if (!NILP (val))
2725 RETURN_UNGCPRO (val);
9b7828a5
JB
2726 RETURN_UNGCPRO (Fcons (filename,
2727 Fcons (make_number (inserted),
2728 Qnil)));
570d7624 2729}
7fded690 2730\f
d6a3cc15
RS
2731static Lisp_Object build_annotations ();
2732
570d7624
JB
2733DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2734 "r\nFWrite region to file: ",
2735 "Write current region into specified file.\n\
2736When called from a program, takes three arguments:\n\
2737START, END and FILENAME. START and END are buffer positions.\n\
2738Optional fourth argument APPEND if non-nil means\n\
2739 append to existing file contents (if any).\n\
2740Optional fifth argument VISIT if t means\n\
2741 set the last-save-file-modtime of buffer to this file's modtime\n\
2742 and mark buffer not modified.\n\
3b7792ed
RS
2743If VISIT is a string, it is a second file name;\n\
2744 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
2745 VISIT is also the file name to lock and unlock for clash detection.\n\
1d386d28
RS
2746If VISIT is neither t nor nil nor a string,\n\
2747 that means do not print the \"Wrote file\" message.\n\
570d7624
JB
2748Kludgy feature: if START is a string, then that string is written\n\
2749to the file, instead of any buffer contents, and END is ignored.")
2750 (start, end, filename, append, visit)
2751 Lisp_Object start, end, filename, append, visit;
2752{
2753 register int desc;
2754 int failure;
2755 int save_errno;
2756 unsigned char *fn;
2757 struct stat st;
c975dd7a 2758 int tem;
570d7624
JB
2759 int count = specpdl_ptr - specpdl;
2760#ifdef VMS
2761 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
2762#endif /* VMS */
3eac9910 2763 Lisp_Object handler;
4ad827c5 2764 Lisp_Object visit_file;
d6a3cc15
RS
2765 Lisp_Object annotations;
2766 int visiting, quietly;
3b7792ed 2767 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
4c3c22f3
RS
2768#ifdef MSDOS
2769 int buffer_file_type
2770 = NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
2771#endif
570d7624 2772
561cb8e1 2773 if (!NILP (start) && !STRINGP (start))
570d7624
JB
2774 validate_region (&start, &end);
2775
2776 filename = Fexpand_file_name (filename, Qnil);
561cb8e1 2777 if (STRINGP (visit))
e5176bae 2778 visit_file = Fexpand_file_name (visit, Qnil);
4ad827c5
RS
2779 else
2780 visit_file = filename;
2781
561cb8e1 2782 visiting = (EQ (visit, Qt) || STRINGP (visit));
d6a3cc15
RS
2783 quietly = !NILP (visit);
2784
2785 annotations = Qnil;
2786
2787 GCPRO4 (start, filename, annotations, visit_file);
570d7624 2788
32f4334d
RS
2789 /* If the file name has special constructs in it,
2790 call the corresponding file handler. */
642ef245 2791 handler = Ffind_file_name_handler (filename);
b56ad927
RS
2792 /* If FILENAME has no handler, see if VISIT has one. */
2793 if (NILP (handler) && XTYPE (visit) == Lisp_String)
2794 handler = Ffind_file_name_handler (visit);
3eac9910 2795
32f4334d
RS
2796 if (!NILP (handler))
2797 {
32f4334d 2798 Lisp_Object val;
51cf6d37
RS
2799 val = call6 (handler, Qwrite_region, start, end,
2800 filename, append, visit);
32f4334d 2801
d6a3cc15 2802 if (visiting)
32f4334d 2803 {
32f4334d
RS
2804 current_buffer->save_modified = MODIFF;
2805 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 2806 current_buffer->filename = visit_file;
32f4334d 2807 }
09121adc 2808 UNGCPRO;
32f4334d
RS
2809 return val;
2810 }
2811
561cb8e1
RS
2812 /* Special kludge to simplify auto-saving. */
2813 if (NILP (start))
2814 {
2815 XFASTINT (start) = BEG;
2816 XFASTINT (end) = Z;
2817 }
2818
d6a3cc15
RS
2819 annotations = build_annotations (start, end);
2820
570d7624
JB
2821#ifdef CLASH_DETECTION
2822 if (!auto_saving)
3b7792ed 2823 lock_file (visit_file);
570d7624
JB
2824#endif /* CLASH_DETECTION */
2825
09121adc 2826 fn = XSTRING (filename)->data;
570d7624 2827 desc = -1;
265a9e55 2828 if (!NILP (append))
4c3c22f3
RS
2829#ifdef MSDOS
2830 desc = open (fn, O_WRONLY | buffer_file_type);
2831#else
570d7624 2832 desc = open (fn, O_WRONLY);
4c3c22f3 2833#endif
570d7624
JB
2834
2835 if (desc < 0)
2836#ifdef VMS
2837 if (auto_saving) /* Overwrite any previous version of autosave file */
2838 {
2839 vms_truncate (fn); /* if fn exists, truncate to zero length */
2840 desc = open (fn, O_RDWR);
2841 if (desc < 0)
561cb8e1 2842 desc = creat_copy_attrs (STRINGP (current_buffer->filename)
b72dea2a
JB
2843 ? XSTRING (current_buffer->filename)->data : 0,
2844 fn);
570d7624
JB
2845 }
2846 else /* Write to temporary name and rename if no errors */
2847 {
2848 Lisp_Object temp_name;
2849 temp_name = Ffile_name_directory (filename);
2850
265a9e55 2851 if (!NILP (temp_name))
570d7624
JB
2852 {
2853 temp_name = Fmake_temp_name (concat2 (temp_name,
2854 build_string ("$$SAVE$$")));
2855 fname = XSTRING (filename)->data;
2856 fn = XSTRING (temp_name)->data;
2857 desc = creat_copy_attrs (fname, fn);
2858 if (desc < 0)
2859 {
2860 /* If we can't open the temporary file, try creating a new
2861 version of the original file. VMS "creat" creates a
2862 new version rather than truncating an existing file. */
2863 fn = fname;
2864 fname = 0;
2865 desc = creat (fn, 0666);
2866#if 0 /* This can clobber an existing file and fail to replace it,
2867 if the user runs out of space. */
2868 if (desc < 0)
2869 {
2870 /* We can't make a new version;
2871 try to truncate and rewrite existing version if any. */
2872 vms_truncate (fn);
2873 desc = open (fn, O_RDWR);
2874 }
2875#endif
2876 }
2877 }
2878 else
2879 desc = creat (fn, 0666);
2880 }
2881#else /* not VMS */
4c3c22f3
RS
2882#ifdef MSDOS
2883 desc = open (fn,
2884 O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type,
2885 S_IREAD | S_IWRITE);
2886#else /* not MSDOS */
570d7624 2887 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
4c3c22f3 2888#endif /* not MSDOS */
570d7624
JB
2889#endif /* not VMS */
2890
09121adc
RS
2891 UNGCPRO;
2892
570d7624
JB
2893 if (desc < 0)
2894 {
2895#ifdef CLASH_DETECTION
2896 save_errno = errno;
3b7792ed 2897 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
2898 errno = save_errno;
2899#endif /* CLASH_DETECTION */
2900 report_file_error ("Opening output file", Fcons (filename, Qnil));
2901 }
2902
2903 record_unwind_protect (close_file_unwind, make_number (desc));
2904
265a9e55 2905 if (!NILP (append))
570d7624
JB
2906 if (lseek (desc, 0, 2) < 0)
2907 {
2908#ifdef CLASH_DETECTION
3b7792ed 2909 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
2910#endif /* CLASH_DETECTION */
2911 report_file_error ("Lseek error", Fcons (filename, Qnil));
2912 }
2913
2914#ifdef VMS
2915/*
2916 * Kludge Warning: The VMS C RTL likes to insert carriage returns
2917 * if we do writes that don't end with a carriage return. Furthermore
2918 * it cannot handle writes of more then 16K. The modified
2919 * version of "sys_write" in SYSDEP.C (see comment there) copes with
2920 * this EXCEPT for the last record (iff it doesn't end with a carriage
2921 * return). This implies that if your buffer doesn't end with a carriage
2922 * return, you get one free... tough. However it also means that if
2923 * we make two calls to sys_write (a la the following code) you can
2924 * get one at the gap as well. The easiest way to fix this (honest)
2925 * is to move the gap to the next newline (or the end of the buffer).
2926 * Thus this change.
2927 *
2928 * Yech!
2929 */
2930 if (GPT > BEG && GPT_ADDR[-1] != '\n')
2931 move_gap (find_next_newline (GPT, 1));
2932#endif
2933
2934 failure = 0;
2935 immediate_quit = 1;
2936
561cb8e1 2937 if (STRINGP (start))
570d7624 2938 {
d6a3cc15
RS
2939 failure = 0 > a_write (desc, XSTRING (start)->data,
2940 XSTRING (start)->size, 0, &annotations);
570d7624
JB
2941 save_errno = errno;
2942 }
2943 else if (XINT (start) != XINT (end))
2944 {
c975dd7a 2945 int nwritten = 0;
570d7624
JB
2946 if (XINT (start) < GPT)
2947 {
2948 register int end1 = XINT (end);
2949 tem = XINT (start);
d6a3cc15 2950 failure = 0 > a_write (desc, &FETCH_CHAR (tem),
c975dd7a
RS
2951 min (GPT, end1) - tem, tem, &annotations);
2952 nwritten += min (GPT, end1) - tem;
570d7624
JB
2953 save_errno = errno;
2954 }
2955
2956 if (XINT (end) > GPT && !failure)
2957 {
2958 tem = XINT (start);
2959 tem = max (tem, GPT);
d6a3cc15 2960 failure = 0 > a_write (desc, &FETCH_CHAR (tem), XINT (end) - tem,
c975dd7a
RS
2961 tem, &annotations);
2962 nwritten += XINT (end) - tem;
d6a3cc15
RS
2963 save_errno = errno;
2964 }
c975dd7a
RS
2965
2966 if (nwritten == 0)
d6a3cc15
RS
2967 {
2968 /* If file was empty, still need to write the annotations */
c975dd7a 2969 failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
570d7624
JB
2970 save_errno = errno;
2971 }
2972 }
2973
2974 immediate_quit = 0;
2975
6e23c83e 2976#ifdef HAVE_FSYNC
570d7624
JB
2977 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
2978 Disk full in NFS may be reported here. */
1daffa1c
RS
2979 /* mib says that closing the file will try to write as fast as NFS can do
2980 it, and that means the fsync here is not crucial for autosave files. */
2981 if (!auto_saving && fsync (desc) < 0)
570d7624 2982 failure = 1, save_errno = errno;
570d7624
JB
2983#endif
2984
2985 /* Spurious "file has changed on disk" warnings have been
2986 observed on Suns as well.
2987 It seems that `close' can change the modtime, under nfs.
2988
2989 (This has supposedly been fixed in Sunos 4,
2990 but who knows about all the other machines with NFS?) */
2991#if 0
2992
2993 /* On VMS and APOLLO, must do the stat after the close
2994 since closing changes the modtime. */
2995#ifndef VMS
2996#ifndef APOLLO
2997 /* Recall that #if defined does not work on VMS. */
2998#define FOO
2999 fstat (desc, &st);
3000#endif
3001#endif
3002#endif
3003
3004 /* NFS can report a write failure now. */
3005 if (close (desc) < 0)
3006 failure = 1, save_errno = errno;
3007
3008#ifdef VMS
3009 /* If we wrote to a temporary name and had no errors, rename to real name. */
3010 if (fname)
3011 {
3012 if (!failure)
3013 failure = (rename (fn, fname) != 0), save_errno = errno;
3014 fn = fname;
3015 }
3016#endif /* VMS */
3017
3018#ifndef FOO
3019 stat (fn, &st);
3020#endif
3021 /* Discard the unwind protect */
3022 specpdl_ptr = specpdl + count;
3023
3024#ifdef CLASH_DETECTION
3025 if (!auto_saving)
3b7792ed 3026 unlock_file (visit_file);
570d7624
JB
3027#endif /* CLASH_DETECTION */
3028
3029 /* Do this before reporting IO error
3030 to avoid a "file has changed on disk" warning on
3031 next attempt to save. */
d6a3cc15 3032 if (visiting)
570d7624
JB
3033 current_buffer->modtime = st.st_mtime;
3034
3035 if (failure)
ce97267f 3036 error ("IO error writing %s: %s", fn, strerror (save_errno));
570d7624 3037
d6a3cc15 3038 if (visiting)
570d7624
JB
3039 {
3040 current_buffer->save_modified = MODIFF;
3041 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 3042 current_buffer->filename = visit_file;
570d7624 3043 }
d6a3cc15 3044 else if (quietly)
570d7624
JB
3045 return Qnil;
3046
3047 if (!auto_saving)
3b7792ed 3048 message ("Wrote %s", XSTRING (visit_file)->data);
570d7624
JB
3049
3050 return Qnil;
3051}
3052
d6a3cc15
RS
3053Lisp_Object merge ();
3054
3055DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
2ba0ccff 3056 "Return t if (car A) is numerically less than (car B).")
d6a3cc15
RS
3057 (a, b)
3058 Lisp_Object a, b;
3059{
3060 return Flss (Fcar (a), Fcar (b));
3061}
3062
3063/* Build the complete list of annotations appropriate for writing out
3064 the text between START and END, by calling all the functions in
3065 write-region-annotate-functions and merging the lists they return. */
3066
3067static Lisp_Object
3068build_annotations (start, end)
3069 Lisp_Object start, end;
3070{
3071 Lisp_Object annotations;
3072 Lisp_Object p, res;
3073 struct gcpro gcpro1, gcpro2;
3074
3075 annotations = Qnil;
3076 p = Vwrite_region_annotate_functions;
3077 GCPRO2 (annotations, p);
3078 while (!NILP (p))
3079 {
3080 res = call2 (Fcar (p), start, end);
3081 Flength (res); /* Check basic validity of return value */
3082 annotations = merge (annotations, res, Qcar_less_than_car);
3083 p = Fcdr (p);
3084 }
3085 UNGCPRO;
3086 return annotations;
3087}
3088
3089/* Write to descriptor DESC the LEN characters starting at ADDR,
3090 assuming they start at position POS in the buffer.
3091 Intersperse with them the annotations from *ANNOT
3092 (those which fall within the range of positions POS to POS + LEN),
3093 each at its appropriate position.
3094
3095 Modify *ANNOT by discarding elements as we output them.
3096 The return value is negative in case of system call failure. */
3097
3098int
3099a_write (desc, addr, len, pos, annot)
3100 int desc;
3101 register char *addr;
3102 register int len;
3103 int pos;
3104 Lisp_Object *annot;
3105{
3106 Lisp_Object tem;
3107 int nextpos;
3108 int lastpos = pos + len;
3109
3110 while (1)
3111 {
3112 tem = Fcar_safe (Fcar (*annot));
3113 if (INTEGERP (tem) && XINT (tem) >= pos && XFASTINT (tem) <= lastpos)
3114 nextpos = XFASTINT (tem);
3115 else
3116 return e_write (desc, addr, lastpos - pos);
3117 if (nextpos > pos)
3118 {
3119 if (0 > e_write (desc, addr, nextpos - pos))
3120 return -1;
3121 addr += nextpos - pos;
3122 pos = nextpos;
3123 }
3124 tem = Fcdr (Fcar (*annot));
3125 if (STRINGP (tem))
3126 {
3127 if (0 > e_write (desc, XSTRING (tem)->data, XSTRING (tem)->size))
3128 return -1;
3129 }
3130 *annot = Fcdr (*annot);
3131 }
3132}
3133
570d7624
JB
3134int
3135e_write (desc, addr, len)
3136 int desc;
3137 register char *addr;
3138 register int len;
3139{
3140 char buf[16 * 1024];
3141 register char *p, *end;
3142
3143 if (!EQ (current_buffer->selective_display, Qt))
3144 return write (desc, addr, len) - len;
3145 else
3146 {
3147 p = buf;
3148 end = p + sizeof buf;
3149 while (len--)
3150 {
3151 if (p == end)
3152 {
3153 if (write (desc, buf, sizeof buf) != sizeof buf)
3154 return -1;
3155 p = buf;
3156 }
3157 *p = *addr++;
3158 if (*p++ == '\015')
3159 p[-1] = '\n';
3160 }
3161 if (p != buf)
3162 if (write (desc, buf, p - buf) != p - buf)
3163 return -1;
3164 }
3165 return 0;
3166}
3167
3168DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
3169 Sverify_visited_file_modtime, 1, 1, 0,
3170 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
3171This means that the file has not been changed since it was visited or saved.")
3172 (buf)
3173 Lisp_Object buf;
3174{
3175 struct buffer *b;
3176 struct stat st;
32f4334d 3177 Lisp_Object handler;
570d7624
JB
3178
3179 CHECK_BUFFER (buf, 0);
3180 b = XBUFFER (buf);
3181
3182 if (XTYPE (b->filename) != Lisp_String) return Qt;
3183 if (b->modtime == 0) return Qt;
3184
32f4334d
RS
3185 /* If the file name has special constructs in it,
3186 call the corresponding file handler. */
642ef245 3187 handler = Ffind_file_name_handler (b->filename);
32f4334d 3188 if (!NILP (handler))
09121adc 3189 return call2 (handler, Qverify_visited_file_modtime, buf);
32f4334d 3190
570d7624
JB
3191 if (stat (XSTRING (b->filename)->data, &st) < 0)
3192 {
3193 /* If the file doesn't exist now and didn't exist before,
3194 we say that it isn't modified, provided the error is a tame one. */
3195 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
3196 st.st_mtime = -1;
3197 else
3198 st.st_mtime = 0;
3199 }
3200 if (st.st_mtime == b->modtime
3201 /* If both are positive, accept them if they are off by one second. */
3202 || (st.st_mtime > 0 && b->modtime > 0
3203 && (st.st_mtime == b->modtime + 1
3204 || st.st_mtime == b->modtime - 1)))
3205 return Qt;
3206 return Qnil;
3207}
3208
3209DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
3210 Sclear_visited_file_modtime, 0, 0, 0,
3211 "Clear out records of last mod time of visited file.\n\
3212Next attempt to save will certainly not complain of a discrepancy.")
3213 ()
3214{
3215 current_buffer->modtime = 0;
3216 return Qnil;
3217}
3218
f5d5eccf
RS
3219DEFUN ("visited-file-modtime", Fvisited_file_modtime,
3220 Svisited_file_modtime, 0, 0, 0,
3221 "Return the current buffer's recorded visited file modification time.\n\
3222The value is a list of the form (HIGH . LOW), like the time values\n\
3223that `file-attributes' returns.")
3224 ()
3225{
3226 return long_to_cons (current_buffer->modtime);
3227}
3228
570d7624 3229DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
f5d5eccf 3230 Sset_visited_file_modtime, 0, 1, 0,
570d7624
JB
3231 "Update buffer's recorded modification time from the visited file's time.\n\
3232Useful if the buffer was not read from the file normally\n\
f5d5eccf
RS
3233or if the file itself has been changed for some known benign reason.\n\
3234An argument specifies the modification time value to use\n\
3235\(instead of that of the visited file), in the form of a list\n\
3236\(HIGH . LOW) or (HIGH LOW).")
3237 (time_list)
3238 Lisp_Object time_list;
570d7624 3239{
f5d5eccf
RS
3240 if (!NILP (time_list))
3241 current_buffer->modtime = cons_to_long (time_list);
3242 else
3243 {
3244 register Lisp_Object filename;
3245 struct stat st;
3246 Lisp_Object handler;
570d7624 3247
f5d5eccf 3248 filename = Fexpand_file_name (current_buffer->filename, Qnil);
32f4334d 3249
f5d5eccf
RS
3250 /* If the file name has special constructs in it,
3251 call the corresponding file handler. */
3252 handler = Ffind_file_name_handler (filename);
3253 if (!NILP (handler))
caf3c431 3254 /* The handler can find the file name the same way we did. */
76c881b0 3255 return call2 (handler, Qset_visited_file_modtime, Qnil);
f5d5eccf
RS
3256 else if (stat (XSTRING (filename)->data, &st) >= 0)
3257 current_buffer->modtime = st.st_mtime;
3258 }
570d7624
JB
3259
3260 return Qnil;
3261}
3262\f
3263Lisp_Object
3264auto_save_error ()
3265{
3266 unsigned char *name = XSTRING (current_buffer->name)->data;
3267
3268 ring_bell ();
3269 message ("Autosaving...error for %s", name);
de49a6d3 3270 Fsleep_for (make_number (1), Qnil);
570d7624 3271 message ("Autosaving...error!for %s", name);
de49a6d3 3272 Fsleep_for (make_number (1), Qnil);
570d7624 3273 message ("Autosaving...error for %s", name);
de49a6d3 3274 Fsleep_for (make_number (1), Qnil);
570d7624
JB
3275 return Qnil;
3276}
3277
3278Lisp_Object
3279auto_save_1 ()
3280{
3281 unsigned char *fn;
3282 struct stat st;
3283
3284 /* Get visited file's mode to become the auto save file's mode. */
3285 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
3286 /* But make sure we can overwrite it later! */
3287 auto_save_mode_bits = st.st_mode | 0600;
3288 else
3289 auto_save_mode_bits = 0666;
3290
3291 return
3292 Fwrite_region (Qnil, Qnil,
3293 current_buffer->auto_save_file_name,
3294 Qnil, Qlambda);
3295}
3296
3297DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
3298 "Auto-save all buffers that need it.\n\
3299This is all buffers that have auto-saving enabled\n\
3300and are changed since last auto-saved.\n\
3301Auto-saving writes the buffer into a file\n\
3302so that your editing is not lost if the system crashes.\n\
3303This file is not the file you visited; that changes only when you save.\n\n\
3304Non-nil first argument means do not print any message if successful.\n\
4746118a 3305Non-nil second argument means save only current buffer.")
17857782
JB
3306 (no_message, current_only)
3307 Lisp_Object no_message, current_only;
570d7624
JB
3308{
3309 struct buffer *old = current_buffer, *b;
3310 Lisp_Object tail, buf;
3311 int auto_saved = 0;
3312 char *omessage = echo_area_glyphs;
f05b275b 3313 int omessage_length = echo_area_glyphs_length;
f14b1c68
JB
3314 extern int minibuf_level;
3315 int do_handled_files;
ff4c9993
RS
3316 Lisp_Object oquit;
3317
3318 /* Ordinarily don't quit within this function,
3319 but don't make it impossible to quit (in case we get hung in I/O). */
3320 oquit = Vquit_flag;
3321 Vquit_flag = Qnil;
570d7624
JB
3322
3323 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
3324 point to non-strings reached from Vbuffer_alist. */
3325
3326 auto_saving = 1;
3327 if (minibuf_level)
17857782 3328 no_message = Qt;
570d7624
JB
3329
3330 /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
3331 eventually call do-auto-save, so don't err here in that case. */
265a9e55 3332 if (!NILP (Vrun_hooks))
570d7624
JB
3333 call1 (Vrun_hooks, intern ("auto-save-hook"));
3334
f14b1c68
JB
3335 /* First, save all files which don't have handlers. If Emacs is
3336 crashing, the handlers may tweak what is causing Emacs to crash
3337 in the first place, and it would be a shame if Emacs failed to
3338 autosave perfectly ordinary files because it couldn't handle some
3339 ange-ftp'd file. */
3340 for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
3341 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
3342 tail = XCONS (tail)->cdr)
3343 {
3344 buf = XCONS (XCONS (tail)->car)->cdr;
3345 b = XBUFFER (buf);
17857782 3346
f14b1c68
JB
3347 if (!NILP (current_only)
3348 && b != current_buffer)
3349 continue;
17857782 3350
f14b1c68
JB
3351 /* Check for auto save enabled
3352 and file changed since last auto save
3353 and file changed since last real save. */
3354 if (XTYPE (b->auto_save_file_name) == Lisp_String
3355 && b->save_modified < BUF_MODIFF (b)
3356 && b->auto_save_modified < BUF_MODIFF (b)
3357 && (do_handled_files
3358 || NILP (Ffind_file_name_handler (b->auto_save_file_name))))
3359 {
b60247d9
RS
3360 EMACS_TIME before_time, after_time;
3361
3362 EMACS_GET_TIME (before_time);
3363
3364 /* If we had a failure, don't try again for 20 minutes. */
3365 if (b->auto_save_failure_time >= 0
3366 && EMACS_SECS (before_time) - b->auto_save_failure_time < 1200)
3367 continue;
3368
f14b1c68
JB
3369 if ((XFASTINT (b->save_length) * 10
3370 > (BUF_Z (b) - BUF_BEG (b)) * 13)
3371 /* A short file is likely to change a large fraction;
3372 spare the user annoying messages. */
3373 && XFASTINT (b->save_length) > 5000
3374 /* These messages are frequent and annoying for `*mail*'. */
3375 && !EQ (b->filename, Qnil)
3376 && NILP (no_message))
3377 {
3378 /* It has shrunk too much; turn off auto-saving here. */
3379 message ("Buffer %s has shrunk a lot; auto save turned off there",
3380 XSTRING (b->name)->data);
3381 /* User can reenable saving with M-x auto-save. */
3382 b->auto_save_file_name = Qnil;
3383 /* Prevent warning from repeating if user does so. */
3384 XFASTINT (b->save_length) = 0;
3385 Fsleep_for (make_number (1), Qnil);
3386 continue;
3387 }
3388 set_buffer_internal (b);
3389 if (!auto_saved && NILP (no_message))
3390 message1 ("Auto-saving...");
3391 internal_condition_case (auto_save_1, Qt, auto_save_error);
3392 auto_saved++;
3393 b->auto_save_modified = BUF_MODIFF (b);
3394 XFASTINT (current_buffer->save_length) = Z - BEG;
3395 set_buffer_internal (old);
b60247d9
RS
3396
3397 EMACS_GET_TIME (after_time);
3398
3399 /* If auto-save took more than 60 seconds,
3400 assume it was an NFS failure that got a timeout. */
3401 if (EMACS_SECS (after_time) - EMACS_SECS (before_time) > 60)
3402 b->auto_save_failure_time = EMACS_SECS (after_time);
f14b1c68
JB
3403 }
3404 }
570d7624 3405
b67f2ca5
RS
3406 /* Prevent another auto save till enough input events come in. */
3407 record_auto_save ();
570d7624 3408
17857782 3409 if (auto_saved && NILP (no_message))
f05b275b
KH
3410 {
3411 if (omessage)
3412 message2 (omessage, omessage_length);
3413 else
3414 message1 ("Auto-saving...done");
3415 }
570d7624 3416
ff4c9993
RS
3417 Vquit_flag = oquit;
3418
570d7624
JB
3419 auto_saving = 0;
3420 return Qnil;
3421}
3422
3423DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
3424 Sset_buffer_auto_saved, 0, 0, 0,
3425 "Mark current buffer as auto-saved with its current text.\n\
3426No auto-save file will be written until the buffer changes again.")
3427 ()
3428{
3429 current_buffer->auto_save_modified = MODIFF;
3430 XFASTINT (current_buffer->save_length) = Z - BEG;
b60247d9
RS
3431 current_buffer->auto_save_failure_time = -1;
3432 return Qnil;
3433}
3434
3435DEFUN ("clear-buffer-auto-save-failure", Fclear_buffer_auto_save_failure,
3436 Sclear_buffer_auto_save_failure, 0, 0, 0,
3437 "Clear any record of a recent auto-save failure in the current buffer.")
3438 ()
3439{
3440 current_buffer->auto_save_failure_time = -1;
570d7624
JB
3441 return Qnil;
3442}
3443
3444DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
3445 0, 0, 0,
3446 "Return t if buffer has been auto-saved since last read in or saved.")
3447 ()
3448{
3449 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
3450}
3451\f
3452/* Reading and completing file names */
3453extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
3454
6e710ae5
RS
3455/* In the string VAL, change each $ to $$ and return the result. */
3456
3457static Lisp_Object
3458double_dollars (val)
3459 Lisp_Object val;
3460{
3461 register unsigned char *old, *new;
3462 register int n;
3463 int osize, count;
3464
3465 osize = XSTRING (val)->size;
3466 /* Quote "$" as "$$" to get it past substitute-in-file-name */
3467 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
3468 if (*old++ == '$') count++;
3469 if (count > 0)
3470 {
3471 old = XSTRING (val)->data;
3472 val = Fmake_string (make_number (osize + count), make_number (0));
3473 new = XSTRING (val)->data;
3474 for (n = osize; n > 0; n--)
3475 if (*old != '$')
3476 *new++ = *old++;
3477 else
3478 {
3479 *new++ = '$';
3480 *new++ = '$';
3481 old++;
3482 }
3483 }
3484 return val;
3485}
3486
570d7624
JB
3487DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
3488 3, 3, 0,
3489 "Internal subroutine for read-file-name. Do not call this.")
3490 (string, dir, action)
3491 Lisp_Object string, dir, action;
3492 /* action is nil for complete, t for return list of completions,
3493 lambda for verify final value */
3494{
3495 Lisp_Object name, specdir, realdir, val, orig_string;
09121adc
RS
3496 int changed;
3497 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3498
3499 realdir = dir;
3500 name = string;
3501 orig_string = Qnil;
3502 specdir = Qnil;
3503 changed = 0;
3504 /* No need to protect ACTION--we only compare it with t and nil. */
3505 GCPRO4 (string, realdir, name, specdir);
570d7624
JB
3506
3507 if (XSTRING (string)->size == 0)
3508 {
570d7624 3509 if (EQ (action, Qlambda))
09121adc
RS
3510 {
3511 UNGCPRO;
3512 return Qnil;
3513 }
570d7624
JB
3514 }
3515 else
3516 {
3517 orig_string = string;
3518 string = Fsubstitute_in_file_name (string);
09121adc 3519 changed = NILP (Fstring_equal (string, orig_string));
570d7624 3520 name = Ffile_name_nondirectory (string);
09121adc
RS
3521 val = Ffile_name_directory (string);
3522 if (! NILP (val))
3523 realdir = Fexpand_file_name (val, realdir);
570d7624
JB
3524 }
3525
265a9e55 3526 if (NILP (action))
570d7624
JB
3527 {
3528 specdir = Ffile_name_directory (string);
3529 val = Ffile_name_completion (name, realdir);
09121adc 3530 UNGCPRO;
570d7624
JB
3531 if (XTYPE (val) != Lisp_String)
3532 {
09121adc 3533 if (changed)
570d7624 3534 return string;
09121adc 3535 return val;
570d7624
JB
3536 }
3537
265a9e55 3538 if (!NILP (specdir))
570d7624
JB
3539 val = concat2 (specdir, val);
3540#ifndef VMS
6e710ae5
RS
3541 return double_dollars (val);
3542#else /* not VMS */
09121adc 3543 return val;
6e710ae5 3544#endif /* not VMS */
570d7624 3545 }
09121adc 3546 UNGCPRO;
570d7624
JB
3547
3548 if (EQ (action, Qt))
3549 return Ffile_name_all_completions (name, realdir);
3550 /* Only other case actually used is ACTION = lambda */
3551#ifdef VMS
3552 /* Supposedly this helps commands such as `cd' that read directory names,
3553 but can someone explain how it helps them? -- RMS */
3554 if (XSTRING (name)->size == 0)
3555 return Qt;
3556#endif /* VMS */
3557 return Ffile_exists_p (string);
3558}
3559
3560DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3561 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3562Value is not expanded---you must call `expand-file-name' yourself.\n\
3563Default name to DEFAULT if user enters a null string.\n\
3564 (If DEFAULT is omitted, the visited file name is used.)\n\
3565Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3566 Non-nil and non-t means also require confirmation after completion.\n\
3567Fifth arg INITIAL specifies text to start with.\n\
3568DIR defaults to current buffer's directory default.")
3569 (prompt, dir, defalt, mustmatch, initial)
3570 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3571{
85b5fe07 3572 Lisp_Object val, insdef, insdef1, tem;
570d7624
JB
3573 struct gcpro gcpro1, gcpro2;
3574 register char *homedir;
3575 int count;
3576
265a9e55 3577 if (NILP (dir))
570d7624 3578 dir = current_buffer->directory;
265a9e55 3579 if (NILP (defalt))
570d7624
JB
3580 defalt = current_buffer->filename;
3581
3582 /* If dir starts with user's homedir, change that to ~. */
3583 homedir = (char *) egetenv ("HOME");
3584 if (homedir != 0
3585 && XTYPE (dir) == Lisp_String
3586 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3587 && XSTRING (dir)->data[strlen (homedir)] == '/')
3588 {
3589 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3590 XSTRING (dir)->size - strlen (homedir) + 1);
3591 XSTRING (dir)->data[0] = '~';
3592 }
3593
3594 if (insert_default_directory)
3595 {
3596 insdef = dir;
85b5fe07 3597 insdef1 = dir;
265a9e55 3598 if (!NILP (initial))
570d7624 3599 {
15c65264 3600 Lisp_Object args[2], pos;
570d7624
JB
3601
3602 args[0] = insdef;
3603 args[1] = initial;
3604 insdef = Fconcat (2, args);
509b05ed 3605 pos = make_number (XSTRING (dir)->size);
6e710ae5 3606 insdef1 = Fcons (double_dollars (insdef), pos);
570d7624 3607 }
6e710ae5
RS
3608 else
3609 insdef1 = double_dollars (insdef);
570d7624
JB
3610 }
3611 else
85b5fe07 3612 insdef = Qnil, insdef1 = Qnil;
570d7624
JB
3613
3614#ifdef VMS
3615 count = specpdl_ptr - specpdl;
3616 specbind (intern ("completion-ignore-case"), Qt);
3617#endif
3618
3619 GCPRO2 (insdef, defalt);
3620 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
85b5fe07 3621 dir, mustmatch, insdef1,
15c65264 3622 Qfile_name_history);
570d7624
JB
3623
3624#ifdef VMS
3625 unbind_to (count, Qnil);
3626#endif
3627
3628 UNGCPRO;
265a9e55 3629 if (NILP (val))
570d7624
JB
3630 error ("No file name specified");
3631 tem = Fstring_equal (val, insdef);
265a9e55 3632 if (!NILP (tem) && !NILP (defalt))
570d7624 3633 return defalt;
b320926a 3634 if (XSTRING (val)->size == 0 && NILP (insdef))
d9bc1c99
RS
3635 {
3636 if (!NILP (defalt))
3637 return defalt;
3638 else
3639 error ("No default file name");
3640 }
570d7624
JB
3641 return Fsubstitute_in_file_name (val);
3642}
3643
3644#if 0 /* Old version */
3645DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3646 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3647Value is not expanded---you must call `expand-file-name' yourself.\n\
3648Default name to DEFAULT if user enters a null string.\n\
3649 (If DEFAULT is omitted, the visited file name is used.)\n\
3650Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3651 Non-nil and non-t means also require confirmation after completion.\n\
3652Fifth arg INITIAL specifies text to start with.\n\
3653DIR defaults to current buffer's directory default.")
3654 (prompt, dir, defalt, mustmatch, initial)
3655 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3656{
3657 Lisp_Object val, insdef, tem;
3658 struct gcpro gcpro1, gcpro2;
3659 register char *homedir;
3660 int count;
3661
265a9e55 3662 if (NILP (dir))
570d7624 3663 dir = current_buffer->directory;
265a9e55 3664 if (NILP (defalt))
570d7624
JB
3665 defalt = current_buffer->filename;
3666
3667 /* If dir starts with user's homedir, change that to ~. */
3668 homedir = (char *) egetenv ("HOME");
3669 if (homedir != 0
3670 && XTYPE (dir) == Lisp_String
3671 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3672 && XSTRING (dir)->data[strlen (homedir)] == '/')
3673 {
3674 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3675 XSTRING (dir)->size - strlen (homedir) + 1);
3676 XSTRING (dir)->data[0] = '~';
3677 }
3678
265a9e55 3679 if (!NILP (initial))
570d7624
JB
3680 insdef = initial;
3681 else if (insert_default_directory)
3682 insdef = dir;
3683 else
3684 insdef = build_string ("");
3685
3686#ifdef VMS
3687 count = specpdl_ptr - specpdl;
3688 specbind (intern ("completion-ignore-case"), Qt);
3689#endif
3690
3691 GCPRO2 (insdef, defalt);
3692 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3693 dir, mustmatch,
15c65264
RS
3694 insert_default_directory ? insdef : Qnil,
3695 Qfile_name_history);
570d7624
JB
3696
3697#ifdef VMS
3698 unbind_to (count, Qnil);
3699#endif
3700
3701 UNGCPRO;
265a9e55 3702 if (NILP (val))
570d7624
JB
3703 error ("No file name specified");
3704 tem = Fstring_equal (val, insdef);
265a9e55 3705 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
3706 return defalt;
3707 return Fsubstitute_in_file_name (val);
3708}
3709#endif /* Old version */
3710\f
3711syms_of_fileio ()
3712{
0bf2eed2
RS
3713 Qexpand_file_name = intern ("expand-file-name");
3714 Qdirectory_file_name = intern ("directory-file-name");
3715 Qfile_name_directory = intern ("file-name-directory");
3716 Qfile_name_nondirectory = intern ("file-name-nondirectory");
642ef245 3717 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
0bf2eed2 3718 Qfile_name_as_directory = intern ("file-name-as-directory");
32f4334d
RS
3719 Qcopy_file = intern ("copy-file");
3720 Qmake_directory = intern ("make-directory");
3721 Qdelete_directory = intern ("delete-directory");
3722 Qdelete_file = intern ("delete-file");
3723 Qrename_file = intern ("rename-file");
3724 Qadd_name_to_file = intern ("add-name-to-file");
3725 Qmake_symbolic_link = intern ("make-symbolic-link");
3726 Qfile_exists_p = intern ("file-exists-p");
3727 Qfile_executable_p = intern ("file-executable-p");
3728 Qfile_readable_p = intern ("file-readable-p");
3729 Qfile_symlink_p = intern ("file-symlink-p");
3730 Qfile_writable_p = intern ("file-writable-p");
3731 Qfile_directory_p = intern ("file-directory-p");
3732 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
3733 Qfile_modes = intern ("file-modes");
3734 Qset_file_modes = intern ("set-file-modes");
3735 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
3736 Qinsert_file_contents = intern ("insert-file-contents");
3737 Qwrite_region = intern ("write-region");
3738 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3ec46acd 3739 Qset_visited_file_modtime = intern ("set-visited-file-modtime");
32f4334d 3740
642ef245
JB
3741 staticpro (&Qexpand_file_name);
3742 staticpro (&Qdirectory_file_name);
3743 staticpro (&Qfile_name_directory);
3744 staticpro (&Qfile_name_nondirectory);
3745 staticpro (&Qunhandled_file_name_directory);
3746 staticpro (&Qfile_name_as_directory);
15c65264
RS
3747 staticpro (&Qcopy_file);
3748 staticpro (&Qmake_directory);
3749 staticpro (&Qdelete_directory);
3750 staticpro (&Qdelete_file);
3751 staticpro (&Qrename_file);
3752 staticpro (&Qadd_name_to_file);
3753 staticpro (&Qmake_symbolic_link);
3754 staticpro (&Qfile_exists_p);
3755 staticpro (&Qfile_executable_p);
3756 staticpro (&Qfile_readable_p);
3757 staticpro (&Qfile_symlink_p);
3758 staticpro (&Qfile_writable_p);
3759 staticpro (&Qfile_directory_p);
3760 staticpro (&Qfile_accessible_directory_p);
3761 staticpro (&Qfile_modes);
3762 staticpro (&Qset_file_modes);
3763 staticpro (&Qfile_newer_than_file_p);
3764 staticpro (&Qinsert_file_contents);
3765 staticpro (&Qwrite_region);
3766 staticpro (&Qverify_visited_file_modtime);
642ef245
JB
3767
3768 Qfile_name_history = intern ("file-name-history");
3769 Fset (Qfile_name_history, Qnil);
15c65264
RS
3770 staticpro (&Qfile_name_history);
3771
570d7624
JB
3772 Qfile_error = intern ("file-error");
3773 staticpro (&Qfile_error);
3774 Qfile_already_exists = intern("file-already-exists");
3775 staticpro (&Qfile_already_exists);
3776
4c3c22f3
RS
3777#ifdef MSDOS
3778 Qfind_buffer_file_type = intern ("find-buffer-file-type");
3779 staticpro (&Qfind_buffer_file_type);
3780#endif
3781
d6a3cc15
RS
3782 Qcar_less_than_car = intern ("car-less-than-car");
3783 staticpro (&Qcar_less_than_car);
3784
570d7624
JB
3785 Fput (Qfile_error, Qerror_conditions,
3786 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
3787 Fput (Qfile_error, Qerror_message,
3788 build_string ("File error"));
3789
3790 Fput (Qfile_already_exists, Qerror_conditions,
3791 Fcons (Qfile_already_exists,
3792 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
3793 Fput (Qfile_already_exists, Qerror_message,
3794 build_string ("File already exists"));
3795
3796 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
3797 "*Non-nil means when reading a filename start with default dir in minibuffer.");
3798 insert_default_directory = 1;
3799
3800 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
3801 "*Non-nil means write new files with record format `stmlf'.\n\
3802nil means use format `var'. This variable is meaningful only on VMS.");
3803 vms_stmlf_recfm = 0;
3804
1d1826db
RS
3805 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
3806 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
3807If a file name matches REGEXP, then all I/O on that file is done by calling\n\
3808HANDLER.\n\
3809\n\
3810The first argument given to HANDLER is the name of the I/O primitive\n\
3811to be handled; the remaining arguments are the arguments that were\n\
3812passed to that primitive. For example, if you do\n\
3813 (file-exists-p FILENAME)\n\
3814and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
642ef245
JB
3815 (funcall HANDLER 'file-exists-p FILENAME)\n\
3816The function `find-file-name-handler' checks this list for a handler\n\
3817for its argument.");
09121adc
RS
3818 Vfile_name_handler_alist = Qnil;
3819
d6a3cc15 3820 DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
246cfea5
RS
3821 "A list of functions to be called at the end of `insert-file-contents'.\n\
3822Each is passed one argument, the number of bytes inserted. It should return\n\
3823the new byte count, and leave point the same. If `insert-file-contents' is\n\
3824intercepted by a handler from `file-name-handler-alist', that handler is\n\
d6a3cc15
RS
3825responsible for calling the after-insert-file-functions if appropriate.");
3826 Vafter_insert_file_functions = Qnil;
3827
3828 DEFVAR_LISP ("write-region-annotate-functions", &Vwrite_region_annotate_functions,
246cfea5
RS
3829 "A list of functions to be called at the start of `write-region'.\n\
3830Each is passed two arguments, START and END as for `write-region'. It should\n\
3831return a list of pairs (POSITION . STRING) of strings to be effectively\n\
3832inserted at the specified positions of the file being written (1 means to\n\
3833insert before the first byte written). The POSITIONs must be sorted into\n\
3834increasing order. If there are several functions in the list, the several\n\
d6a3cc15
RS
3835lists are merged destructively.");
3836 Vwrite_region_annotate_functions = Qnil;
3837
642ef245 3838 defsubr (&Sfind_file_name_handler);
570d7624
JB
3839 defsubr (&Sfile_name_directory);
3840 defsubr (&Sfile_name_nondirectory);
642ef245 3841 defsubr (&Sunhandled_file_name_directory);
570d7624
JB
3842 defsubr (&Sfile_name_as_directory);
3843 defsubr (&Sdirectory_file_name);
3844 defsubr (&Smake_temp_name);
3845 defsubr (&Sexpand_file_name);
3846 defsubr (&Ssubstitute_in_file_name);
3847 defsubr (&Scopy_file);
9bbe01fb 3848 defsubr (&Smake_directory_internal);
aa734e17 3849 defsubr (&Sdelete_directory);
570d7624
JB
3850 defsubr (&Sdelete_file);
3851 defsubr (&Srename_file);
3852 defsubr (&Sadd_name_to_file);
3853#ifdef S_IFLNK
3854 defsubr (&Smake_symbolic_link);
3855#endif /* S_IFLNK */
3856#ifdef VMS
3857 defsubr (&Sdefine_logical_name);
3858#endif /* VMS */
3859#ifdef HPUX_NET
3860 defsubr (&Ssysnetunam);
3861#endif /* HPUX_NET */
3862 defsubr (&Sfile_name_absolute_p);
3863 defsubr (&Sfile_exists_p);
3864 defsubr (&Sfile_executable_p);
3865 defsubr (&Sfile_readable_p);
3866 defsubr (&Sfile_writable_p);
3867 defsubr (&Sfile_symlink_p);
3868 defsubr (&Sfile_directory_p);
b72dea2a 3869 defsubr (&Sfile_accessible_directory_p);
570d7624
JB
3870 defsubr (&Sfile_modes);
3871 defsubr (&Sset_file_modes);
c24e9a53
RS
3872 defsubr (&Sset_default_file_modes);
3873 defsubr (&Sdefault_file_modes);
570d7624
JB
3874 defsubr (&Sfile_newer_than_file_p);
3875 defsubr (&Sinsert_file_contents);
3876 defsubr (&Swrite_region);
d6a3cc15 3877 defsubr (&Scar_less_than_car);
570d7624
JB
3878 defsubr (&Sverify_visited_file_modtime);
3879 defsubr (&Sclear_visited_file_modtime);
f5d5eccf 3880 defsubr (&Svisited_file_modtime);
570d7624
JB
3881 defsubr (&Sset_visited_file_modtime);
3882 defsubr (&Sdo_auto_save);
3883 defsubr (&Sset_buffer_auto_saved);
b60247d9 3884 defsubr (&Sclear_buffer_auto_save_failure);
570d7624
JB
3885 defsubr (&Srecent_auto_save_p);
3886
3887 defsubr (&Sread_file_name_internal);
3888 defsubr (&Sread_file_name);
85ffea93 3889
483a2e10 3890#ifdef unix
85ffea93 3891 defsubr (&Sunix_sync);
483a2e10 3892#endif
570d7624 3893}