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