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