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