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