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