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