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