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