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