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