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