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