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