(hack_wm_protocols): Arrange to handle WM_SAVE_YOURSELF.
[bpt/emacs.git] / src / fileio.c
CommitLineData
570d7624 1/* File IO for GNU Emacs.
ce97267f 2 Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994 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
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
18160b98 20#include <config.h>
570d7624
JB
21
22#include <sys/types.h>
23#include <sys/stat.h>
bfb61299 24
29beb080
RS
25#ifdef HAVE_UNISTD_H
26#include <unistd.h>
27#endif
28
f73b0ada
BF
29#if !defined (S_ISLNK) && defined (S_IFLNK)
30# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
31#endif
32
33#if !defined (S_ISREG) && defined (S_IFREG)
34# define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
35#endif
36
bfb61299 37#ifdef VMS
de5bf5d3 38#include "vms-pwd.h"
bfb61299 39#else
570d7624 40#include <pwd.h>
bfb61299
JB
41#endif
42
4c3c22f3
RS
43#ifdef MSDOS
44#include "msdos.h"
45#include <sys/param.h>
46#endif
47
570d7624 48#include <ctype.h>
bfb61299
JB
49
50#ifdef VMS
3d9f5ce2 51#include "vmsdir.h"
bfb61299
JB
52#include <perror.h>
53#include <stddef.h>
54#include <string.h>
bfb61299
JB
55#endif
56
570d7624
JB
57#include <errno.h>
58
bfb61299 59#ifndef vax11c
570d7624 60extern int errno;
570d7624
JB
61#endif
62
ce97267f 63extern char *strerror ();
570d7624
JB
64
65#ifdef APOLLO
66#include <sys/time.h>
67#endif
68
6e23c83e
JB
69#ifndef USG
70#ifndef VMS
71#ifndef BSD4_1
72#define HAVE_FSYNC
73#endif
74#endif
75#endif
76
570d7624 77#include "lisp.h"
8d4e077b 78#include "intervals.h"
570d7624
JB
79#include "buffer.h"
80#include "window.h"
81
82#ifdef VMS
570d7624
JB
83#include <file.h>
84#include <rmsdef.h>
85#include <fab.h>
86#include <nam.h>
87#endif
88
de5bf5d3 89#include "systime.h"
570d7624
JB
90
91#ifdef HPUX
92#include <netio.h>
9b7828a5 93#ifndef HPUX8
47e7b9e5 94#ifndef HPUX9
570d7624
JB
95#include <errnet.h>
96#endif
9b7828a5 97#endif
47e7b9e5 98#endif
570d7624
JB
99
100#ifndef O_WRONLY
101#define O_WRONLY 1
102#endif
103
4018b5ef
RS
104#ifndef O_RDONLY
105#define O_RDONLY 0
106#endif
107
570d7624
JB
108#define min(a, b) ((a) < (b) ? (a) : (b))
109#define max(a, b) ((a) > (b) ? (a) : (b))
110
111/* Nonzero during writing of auto-save files */
112int auto_saving;
113
114/* Set by auto_save_1 to mode of original file so Fwrite_region will create
115 a new file with the same mode as the original */
116int auto_save_mode_bits;
117
32f4334d
RS
118/* Alist of elements (REGEXP . HANDLER) for file names
119 whose I/O is done with a special handler. */
120Lisp_Object Vfile_name_handler_alist;
121
d6a3cc15
RS
122/* Functions to be called to process text properties in inserted file. */
123Lisp_Object Vafter_insert_file_functions;
124
125/* Functions to be called to create text property annotations for file. */
126Lisp_Object Vwrite_region_annotate_functions;
127
6fc6f94b
RS
128/* During build_annotations, each time an annotation function is called,
129 this holds the annotations made by the previous functions. */
130Lisp_Object Vwrite_region_annotations_so_far;
131
e54d3b5d
RS
132/* File name in which we write a list of all our auto save files. */
133Lisp_Object Vauto_save_list_file_name;
134
570d7624
JB
135/* Nonzero means, when reading a filename in the minibuffer,
136 start out by inserting the default directory into the minibuffer. */
137int insert_default_directory;
138
139/* On VMS, nonzero means write new files with record format stmlf.
140 Zero means use var format. */
141int vms_stmlf_recfm;
142
a65970a0
RS
143/* These variables describe handlers that have "already" had a chance
144 to handle the current operation.
145
146 Vinhibit_file_name_handlers is a list of file name handlers.
147 Vinhibit_file_name_operation is the operation being handled.
148 If we try to handle that operation, we ignore those handlers. */
149
82c2d839 150static Lisp_Object Vinhibit_file_name_handlers;
a65970a0 151static Lisp_Object Vinhibit_file_name_operation;
82c2d839 152
1b50b4f2
KH
153extern Lisp_Object Qcompletion_ignored_extensions;
154
570d7624
JB
155Lisp_Object Qfile_error, Qfile_already_exists;
156
15c65264
RS
157Lisp_Object Qfile_name_history;
158
d6a3cc15
RS
159Lisp_Object Qcar_less_than_car;
160
570d7624
JB
161report_file_error (string, data)
162 char *string;
163 Lisp_Object data;
164{
165 Lisp_Object errstring;
166
a1f17b2d 167 errstring = build_string (strerror (errno));
570d7624
JB
168
169 /* System error messages are capitalized. Downcase the initial
170 unless it is followed by a slash. */
171 if (XSTRING (errstring)->data[1] != '/')
172 XSTRING (errstring)->data[0] = DOWNCASE (XSTRING (errstring)->data[0]);
173
174 while (1)
175 Fsignal (Qfile_error,
176 Fcons (build_string (string), Fcons (errstring, data)));
177}
b5148e85
RS
178
179close_file_unwind (fd)
180 Lisp_Object fd;
181{
182 close (XFASTINT (fd));
183}
a1d2b64a
RS
184
185/* Restore point, having saved it as a marker. */
186
187restore_point_unwind (location)
188 Lisp_Object location;
189{
190 SET_PT (marker_position (location));
191 Fset_marker (location, Qnil, Qnil);
192}
570d7624 193\f
0bf2eed2
RS
194Lisp_Object Qexpand_file_name;
195Lisp_Object Qdirectory_file_name;
196Lisp_Object Qfile_name_directory;
197Lisp_Object Qfile_name_nondirectory;
642ef245 198Lisp_Object Qunhandled_file_name_directory;
0bf2eed2 199Lisp_Object Qfile_name_as_directory;
32f4334d 200Lisp_Object Qcopy_file;
a6e6e718 201Lisp_Object Qmake_directory_internal;
32f4334d
RS
202Lisp_Object Qdelete_directory;
203Lisp_Object Qdelete_file;
204Lisp_Object Qrename_file;
205Lisp_Object Qadd_name_to_file;
206Lisp_Object Qmake_symbolic_link;
207Lisp_Object Qfile_exists_p;
208Lisp_Object Qfile_executable_p;
209Lisp_Object Qfile_readable_p;
210Lisp_Object Qfile_symlink_p;
211Lisp_Object Qfile_writable_p;
212Lisp_Object Qfile_directory_p;
213Lisp_Object Qfile_accessible_directory_p;
214Lisp_Object Qfile_modes;
215Lisp_Object Qset_file_modes;
216Lisp_Object Qfile_newer_than_file_p;
217Lisp_Object Qinsert_file_contents;
218Lisp_Object Qwrite_region;
219Lisp_Object Qverify_visited_file_modtime;
3ec46acd 220Lisp_Object Qset_visited_file_modtime;
32f4334d 221
49307295
KH
222DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 2, 2, 0,
223 "Return FILENAME's handler function for OPERATION, if it has one.\n\
642ef245
JB
224Otherwise, return nil.\n\
225A file name is handled if one of the regular expressions in\n\
82c2d839 226`file-name-handler-alist' matches it.\n\n\
a65970a0
RS
227If OPERATION equals `inhibit-file-name-operation', then we ignore\n\
228any handlers that are members of `inhibit-file-name-handlers',\n\
229but we still do run any other handlers. This lets handlers\n\
82c2d839 230use the standard functions without calling themselves recursively.")
49307295
KH
231 (filename, operation)
232 Lisp_Object filename, operation;
32f4334d 233{
642ef245 234 /* This function must not munge the match data. */
a65970a0 235 Lisp_Object chain, inhibited_handlers;
642ef245 236
e4432095
JB
237 CHECK_STRING (filename, 0);
238
a65970a0
RS
239 if (EQ (operation, Vinhibit_file_name_operation))
240 inhibited_handlers = Vinhibit_file_name_handlers;
241 else
242 inhibited_handlers = Qnil;
82c2d839 243
3eac9910 244 for (chain = Vfile_name_handler_alist; XTYPE (chain) == Lisp_Cons;
32f4334d
RS
245 chain = XCONS (chain)->cdr)
246 {
247 Lisp_Object elt;
248 elt = XCONS (chain)->car;
249 if (XTYPE (elt) == Lisp_Cons)
250 {
251 Lisp_Object string;
252 string = XCONS (elt)->car;
253 if (XTYPE (string) == Lisp_String
09121adc 254 && fast_string_match (string, filename) >= 0)
a65970a0
RS
255 {
256 Lisp_Object handler, tem;
257
258 handler = XCONS (elt)->cdr;
259 tem = Fmemq (handler, inhibited_handlers);
260 if (NILP (tem))
261 return handler;
262 }
32f4334d 263 }
642ef245
JB
264
265 QUIT;
32f4334d
RS
266 }
267 return Qnil;
268}
269\f
570d7624
JB
270DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory,
271 1, 1, 0,
272 "Return the directory component in file name NAME.\n\
273Return nil if NAME does not include a directory.\n\
274Otherwise return a directory spec.\n\
275Given a Unix syntax file name, returns a string ending in slash;\n\
276on VMS, perhaps instead a string ending in `:', `]' or `>'.")
277 (file)
278 Lisp_Object file;
279{
280 register unsigned char *beg;
281 register unsigned char *p;
0bf2eed2 282 Lisp_Object handler;
570d7624
JB
283
284 CHECK_STRING (file, 0);
285
0bf2eed2
RS
286 /* If the file name has special constructs in it,
287 call the corresponding file handler. */
49307295 288 handler = Ffind_file_name_handler (file, Qfile_name_directory);
0bf2eed2
RS
289 if (!NILP (handler))
290 return call2 (handler, Qfile_name_directory, file);
291
4c3c22f3
RS
292#ifdef FILE_SYSTEM_CASE
293 file = FILE_SYSTEM_CASE (file);
294#endif
570d7624
JB
295 beg = XSTRING (file)->data;
296 p = beg + XSTRING (file)->size;
297
298 while (p != beg && p[-1] != '/'
299#ifdef VMS
300 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
301#endif /* VMS */
4c3c22f3 302#ifdef MSDOS
a5a1cc06 303 && p[-1] != ':' && p[-1] != '\\'
4c3c22f3 304#endif
570d7624
JB
305 ) p--;
306
307 if (p == beg)
308 return Qnil;
4c3c22f3
RS
309#ifdef MSDOS
310 /* Expansion of "c:" to drive and default directory. */
311 if (p == beg + 2 && beg[1] == ':')
312 {
313 int drive = (*beg) - 'a';
314 /* MAXPATHLEN+1 is guaranteed to be enough space for getdefdir. */
315 unsigned char *res = alloca (MAXPATHLEN + 5);
316 if (getdefdir (drive + 1, res + 2))
317 {
318 res[0] = drive + 'a';
319 res[1] = ':';
320 if (res[strlen (res) - 1] != '/')
321 strcat (res, "/");
322 beg = res;
323 p = beg + strlen (beg);
324 }
325 }
326#endif
570d7624
JB
327 return make_string (beg, p - beg);
328}
329
330DEFUN ("file-name-nondirectory", Ffile_name_nondirectory, Sfile_name_nondirectory,
331 1, 1, 0,
332 "Return file name NAME sans its directory.\n\
333For example, in a Unix-syntax file name,\n\
334this is everything after the last slash,\n\
335or the entire name if it contains no slash.")
336 (file)
337 Lisp_Object file;
338{
339 register unsigned char *beg, *p, *end;
0bf2eed2 340 Lisp_Object handler;
570d7624
JB
341
342 CHECK_STRING (file, 0);
343
0bf2eed2
RS
344 /* If the file name has special constructs in it,
345 call the corresponding file handler. */
49307295 346 handler = Ffind_file_name_handler (file, Qfile_name_nondirectory);
0bf2eed2
RS
347 if (!NILP (handler))
348 return call2 (handler, Qfile_name_nondirectory, file);
349
570d7624
JB
350 beg = XSTRING (file)->data;
351 end = p = beg + XSTRING (file)->size;
352
353 while (p != beg && p[-1] != '/'
354#ifdef VMS
355 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
356#endif /* VMS */
4c3c22f3 357#ifdef MSDOS
a5a1cc06 358 && p[-1] != ':' && p[-1] != '\\'
4c3c22f3 359#endif
570d7624
JB
360 ) p--;
361
362 return make_string (p, end - p);
363}
642ef245
JB
364
365DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory, Sunhandled_file_name_directory, 1, 1, 0,
366 "Return a directly usable directory name somehow associated with FILENAME.\n\
367A `directly usable' directory name is one that may be used without the\n\
368intervention of any file handler.\n\
369If FILENAME is a directly usable file itself, return\n\
370(file-name-directory FILENAME).\n\
371The `call-process' and `start-process' functions use this function to\n\
372get a current directory to run processes in.")
373 (filename)
374 Lisp_Object filename;
375{
376 Lisp_Object handler;
377
378 /* If the file name has special constructs in it,
379 call the corresponding file handler. */
49307295 380 handler = Ffind_file_name_handler (filename, Qunhandled_file_name_directory);
642ef245
JB
381 if (!NILP (handler))
382 return call2 (handler, Qunhandled_file_name_directory, filename);
383
384 return Ffile_name_directory (filename);
385}
386
570d7624
JB
387\f
388char *
389file_name_as_directory (out, in)
390 char *out, *in;
391{
392 int size = strlen (in) - 1;
393
394 strcpy (out, in);
395
396#ifdef VMS
397 /* Is it already a directory string? */
398 if (in[size] == ':' || in[size] == ']' || in[size] == '>')
399 return out;
400 /* Is it a VMS directory file name? If so, hack VMS syntax. */
401 else if (! index (in, '/')
402 && ((size > 3 && ! strcmp (&in[size - 3], ".DIR"))
403 || (size > 3 && ! strcmp (&in[size - 3], ".dir"))
404 || (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4)
405 || ! strncmp (&in[size - 5], ".dir", 4))
406 && (in[size - 1] == '.' || in[size - 1] == ';')
407 && in[size] == '1')))
408 {
409 register char *p, *dot;
410 char brack;
411
412 /* x.dir -> [.x]
413 dir:x.dir --> dir:[x]
414 dir:[x]y.dir --> dir:[x.y] */
415 p = in + size;
416 while (p != in && *p != ':' && *p != '>' && *p != ']') p--;
417 if (p != in)
418 {
419 strncpy (out, in, p - in);
420 out[p - in] = '\0';
421 if (*p == ':')
422 {
423 brack = ']';
424 strcat (out, ":[");
425 }
426 else
427 {
428 brack = *p;
429 strcat (out, ".");
430 }
431 p++;
432 }
433 else
434 {
435 brack = ']';
436 strcpy (out, "[.");
437 }
bfb61299
JB
438 dot = index (p, '.');
439 if (dot)
570d7624
JB
440 {
441 /* blindly remove any extension */
442 size = strlen (out) + (dot - p);
443 strncat (out, p, dot - p);
444 }
445 else
446 {
447 strcat (out, p);
448 size = strlen (out);
449 }
450 out[size++] = brack;
451 out[size] = '\0';
452 }
453#else /* not VMS */
454 /* For Unix syntax, Append a slash if necessary */
4c3c22f3 455#ifdef MSDOS
a5a1cc06 456 if (out[size] != ':' && out[size] != '/' && out[size] != '\\')
4c3c22f3 457#else
570d7624 458 if (out[size] != '/')
4c3c22f3 459#endif
570d7624
JB
460 strcat (out, "/");
461#endif /* not VMS */
462 return out;
463}
464
465DEFUN ("file-name-as-directory", Ffile_name_as_directory,
466 Sfile_name_as_directory, 1, 1, 0,
467 "Return a string representing file FILENAME interpreted as a directory.\n\
468This operation exists because a directory is also a file, but its name as\n\
469a directory is different from its name as a file.\n\
470The result can be used as the value of `default-directory'\n\
471or passed as second argument to `expand-file-name'.\n\
472For a Unix-syntax file name, just appends a slash.\n\
473On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
474 (file)
475 Lisp_Object file;
476{
477 char *buf;
0bf2eed2 478 Lisp_Object handler;
570d7624
JB
479
480 CHECK_STRING (file, 0);
265a9e55 481 if (NILP (file))
570d7624 482 return Qnil;
0bf2eed2
RS
483
484 /* If the file name has special constructs in it,
485 call the corresponding file handler. */
49307295 486 handler = Ffind_file_name_handler (file, Qfile_name_as_directory);
0bf2eed2
RS
487 if (!NILP (handler))
488 return call2 (handler, Qfile_name_as_directory, file);
489
570d7624
JB
490 buf = (char *) alloca (XSTRING (file)->size + 10);
491 return build_string (file_name_as_directory (buf, XSTRING (file)->data));
492}
493\f
494/*
495 * Convert from directory name to filename.
496 * On VMS:
497 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
498 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
499 * On UNIX, it's simple: just make sure there is a terminating /
500
501 * Value is nonzero if the string output is different from the input.
502 */
503
504directory_file_name (src, dst)
505 char *src, *dst;
506{
507 long slen;
508#ifdef VMS
509 long rlen;
510 char * ptr, * rptr;
511 char bracket;
512 struct FAB fab = cc$rms_fab;
513 struct NAM nam = cc$rms_nam;
514 char esa[NAM$C_MAXRSS];
515#endif /* VMS */
516
517 slen = strlen (src);
518#ifdef VMS
519 if (! index (src, '/')
520 && (src[slen - 1] == ']'
521 || src[slen - 1] == ':'
522 || src[slen - 1] == '>'))
523 {
524 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
525 fab.fab$l_fna = src;
526 fab.fab$b_fns = slen;
527 fab.fab$l_nam = &nam;
528 fab.fab$l_fop = FAB$M_NAM;
529
530 nam.nam$l_esa = esa;
531 nam.nam$b_ess = sizeof esa;
532 nam.nam$b_nop |= NAM$M_SYNCHK;
533
534 /* We call SYS$PARSE to handle such things as [--] for us. */
535 if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
536 {
537 slen = nam.nam$b_esl;
538 if (esa[slen - 1] == ';' && esa[slen - 2] == '.')
539 slen -= 2;
540 esa[slen] = '\0';
541 src = esa;
542 }
543 if (src[slen - 1] != ']' && src[slen - 1] != '>')
544 {
545 /* what about when we have logical_name:???? */
546 if (src[slen - 1] == ':')
547 { /* Xlate logical name and see what we get */
548 ptr = strcpy (dst, src); /* upper case for getenv */
549 while (*ptr)
550 {
551 if ('a' <= *ptr && *ptr <= 'z')
552 *ptr -= 040;
553 ptr++;
554 }
555 dst[slen - 1] = 0; /* remove colon */
556 if (!(src = egetenv (dst)))
557 return 0;
558 /* should we jump to the beginning of this procedure?
559 Good points: allows us to use logical names that xlate
560 to Unix names,
561 Bad points: can be a problem if we just translated to a device
562 name...
563 For now, I'll punt and always expect VMS names, and hope for
564 the best! */
565 slen = strlen (src);
566 if (src[slen - 1] != ']' && src[slen - 1] != '>')
567 { /* no recursion here! */
568 strcpy (dst, src);
569 return 0;
570 }
571 }
572 else
573 { /* not a directory spec */
574 strcpy (dst, src);
575 return 0;
576 }
577 }
578 bracket = src[slen - 1];
579
580 /* If bracket is ']' or '>', bracket - 2 is the corresponding
581 opening bracket. */
bfb61299
JB
582 ptr = index (src, bracket - 2);
583 if (ptr == 0)
570d7624
JB
584 { /* no opening bracket */
585 strcpy (dst, src);
586 return 0;
587 }
588 if (!(rptr = rindex (src, '.')))
589 rptr = ptr;
590 slen = rptr - src;
591 strncpy (dst, src, slen);
592 dst[slen] = '\0';
593 if (*rptr == '.')
594 {
595 dst[slen++] = bracket;
596 dst[slen] = '\0';
597 }
598 else
599 {
600 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
601 then translate the device and recurse. */
602 if (dst[slen - 1] == ':'
603 && dst[slen - 2] != ':' /* skip decnet nodes */
604 && strcmp(src + slen, "[000000]") == 0)
605 {
606 dst[slen - 1] = '\0';
607 if ((ptr = egetenv (dst))
608 && (rlen = strlen (ptr) - 1) > 0
609 && (ptr[rlen] == ']' || ptr[rlen] == '>')
610 && ptr[rlen - 1] == '.')
611 {
72b21817
RS
612 char * buf = (char *) alloca (strlen (ptr) + 1);
613 strcpy (buf, ptr);
614 buf[rlen - 1] = ']';
615 buf[rlen] = '\0';
616 return directory_file_name (buf, dst);
570d7624
JB
617 }
618 else
619 dst[slen - 1] = ':';
620 }
621 strcat (dst, "[000000]");
622 slen += 8;
623 }
624 rptr++;
625 rlen = strlen (rptr) - 1;
626 strncat (dst, rptr, rlen);
627 dst[slen + rlen] = '\0';
628 strcat (dst, ".DIR.1");
629 return 1;
630 }
631#endif /* VMS */
632 /* Process as Unix format: just remove any final slash.
633 But leave "/" unchanged; do not change it to "". */
634 strcpy (dst, src);
4c3c22f3 635 if (slen > 1
4c3c22f3 636#ifdef MSDOS
a5a1cc06 637 && (dst[slen - 1] == '/' || dst[slen - 1] == '/')
4c3c22f3 638 && dst[slen - 2] != ':'
a5a1cc06
RS
639#else
640 && dst[slen - 1] == '/'
4c3c22f3
RS
641#endif
642 )
570d7624
JB
643 dst[slen - 1] = 0;
644 return 1;
645}
646
647DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name,
648 1, 1, 0,
649 "Returns the file name of the directory named DIR.\n\
650This is the name of the file that holds the data for the directory DIR.\n\
651This operation exists because a directory is also a file, but its name as\n\
652a directory is different from its name as a file.\n\
653In Unix-syntax, this function just removes the final slash.\n\
654On VMS, given a VMS-syntax directory name such as \"[X.Y]\",\n\
655it returns a file name such as \"[X]Y.DIR.1\".")
656 (directory)
657 Lisp_Object directory;
658{
659 char *buf;
0bf2eed2 660 Lisp_Object handler;
570d7624
JB
661
662 CHECK_STRING (directory, 0);
663
265a9e55 664 if (NILP (directory))
570d7624 665 return Qnil;
0bf2eed2
RS
666
667 /* If the file name has special constructs in it,
668 call the corresponding file handler. */
49307295 669 handler = Ffind_file_name_handler (directory, Qdirectory_file_name);
0bf2eed2
RS
670 if (!NILP (handler))
671 return call2 (handler, Qdirectory_file_name, directory);
672
570d7624
JB
673#ifdef VMS
674 /* 20 extra chars is insufficient for VMS, since we might perform a
675 logical name translation. an equivalence string can be up to 255
676 chars long, so grab that much extra space... - sss */
677 buf = (char *) alloca (XSTRING (directory)->size + 20 + 255);
678#else
679 buf = (char *) alloca (XSTRING (directory)->size + 20);
680#endif
681 directory_file_name (XSTRING (directory)->data, buf);
682 return build_string (buf);
683}
684
685DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0,
686 "Generate temporary file name (string) starting with PREFIX (a string).\n\
687The Emacs process number forms part of the result,\n\
688so there is no danger of generating a name being used by another process.")
689 (prefix)
690 Lisp_Object prefix;
691{
692 Lisp_Object val;
693 val = concat2 (prefix, build_string ("XXXXXX"));
694 mktemp (XSTRING (val)->data);
695 return val;
696}
697\f
698DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
699 "Convert FILENAME to absolute, and canonicalize it.\n\
700Second arg DEFAULT is directory to start with if FILENAME is relative\n\
701 (does not start with slash); if DEFAULT is nil or missing,\n\
702the current buffer's value of default-directory is used.\n\
b72dea2a
JB
703Path components that are `.' are removed, and \n\
704path components followed by `..' are removed, along with the `..' itself;\n\
705note that these simplifications are done without checking the resulting\n\
706paths in the file system.\n\
707An initial `~/' expands to your home directory.\n\
708An initial `~USER/' expands to USER's home directory.\n\
570d7624
JB
709See also the function `substitute-in-file-name'.")
710 (name, defalt)
711 Lisp_Object name, defalt;
712{
713 unsigned char *nm;
714
715 register unsigned char *newdir, *p, *o;
716 int tlen;
717 unsigned char *target;
718 struct passwd *pw;
570d7624
JB
719#ifdef VMS
720 unsigned char * colon = 0;
721 unsigned char * close = 0;
722 unsigned char * slash = 0;
723 unsigned char * brack = 0;
724 int lbrack = 0, rbrack = 0;
725 int dots = 0;
726#endif /* VMS */
4c3c22f3
RS
727#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
728 int drive = -1;
729 int relpath = 0;
730 unsigned char *tmp, *defdir;
731#endif
0bf2eed2 732 Lisp_Object handler;
570d7624
JB
733
734 CHECK_STRING (name, 0);
735
0bf2eed2
RS
736 /* If the file name has special constructs in it,
737 call the corresponding file handler. */
49307295 738 handler = Ffind_file_name_handler (name, Qexpand_file_name);
0bf2eed2 739 if (!NILP (handler))
09121adc 740 return call3 (handler, Qexpand_file_name, name, defalt);
0bf2eed2 741
4ad827c5
RS
742 /* Use the buffer's default-directory if DEFALT is omitted. */
743 if (NILP (defalt))
744 defalt = current_buffer->directory;
745 CHECK_STRING (defalt, 1);
746
f14b1c68
JB
747 /* Make sure DEFALT is properly expanded.
748 It would be better to do this down below where we actually use
749 defalt. Unfortunately, calling Fexpand_file_name recursively
750 could invoke GC, and the strings might be relocated. This would
751 be annoying because we have pointers into strings lying around
752 that would need adjusting, and people would add new pointers to
753 the code and forget to adjust them, resulting in intermittent bugs.
4ad827c5
RS
754 Putting this call here avoids all that crud.
755
756 The EQ test avoids infinite recursion. */
757 if (! NILP (defalt) && !EQ (defalt, name)
758 /* This saves time in a common case. */
759 && XSTRING (defalt)->data[0] != '/')
f14b1c68
JB
760 {
761 struct gcpro gcpro1;
762
763 GCPRO1 (name);
764 defalt = Fexpand_file_name (defalt, Qnil);
765 UNGCPRO;
766 }
767
570d7624
JB
768#ifdef VMS
769 /* Filenames on VMS are always upper case. */
770 name = Fupcase (name);
771#endif
4c3c22f3
RS
772#ifdef FILE_SYSTEM_CASE
773 name = FILE_SYSTEM_CASE (name);
774#endif
570d7624
JB
775
776 nm = XSTRING (name)->data;
777
4c3c22f3 778#ifdef MSDOS
a5a1cc06
RS
779 /* First map all backslashes to slashes. */
780 dostounix_filename (nm = strcpy (alloca (strlen (nm) + 1), nm));
781
782 /* Now strip drive name. */
4c3c22f3
RS
783 {
784 unsigned char *colon = rindex (nm, ':');
785 if (colon)
786 if (nm == colon)
787 nm++;
788 else
789 {
790 drive = tolower (colon[-1]) - 'a';
791 nm = colon + 1;
792 if (*nm != '/')
793 {
794 defdir = alloca (MAXPATHLEN + 1);
795 relpath = getdefdir (drive + 1, defdir);
796 }
797 }
798 }
799#endif
800
570d7624
JB
801 /* If nm is absolute, flush ...// and detect /./ and /../.
802 If no /./ or /../ we can return right away. */
803 if (
804 nm[0] == '/'
805#ifdef VMS
806 || index (nm, ':')
807#endif /* VMS */
808 )
809 {
f14b1c68
JB
810 /* If it turns out that the filename we want to return is just a
811 suffix of FILENAME, we don't need to go through and edit
812 things; we just need to construct a new string using data
813 starting at the middle of FILENAME. If we set lose to a
814 non-zero value, that means we've discovered that we can't do
815 that cool trick. */
816 int lose = 0;
817
570d7624 818 p = nm;
570d7624
JB
819 while (*p)
820 {
c77d647e
JB
821 /* Since we know the path is absolute, we can assume that each
822 element starts with a "/". */
823
824 /* "//" anywhere isn't necessarily hairy; we just start afresh
825 with the second slash. */
570d7624
JB
826 if (p[0] == '/' && p[1] == '/'
827#ifdef APOLLO
828 /* // at start of filename is meaningful on Apollo system */
829 && nm != p
830#endif /* APOLLO */
831 )
832 nm = p + 1;
c77d647e
JB
833
834 /* "~" is hairy as the start of any path element. */
570d7624
JB
835 if (p[0] == '/' && p[1] == '~')
836 nm = p + 1, lose = 1;
c77d647e
JB
837
838 /* "." and ".." are hairy. */
839 if (p[0] == '/'
840 && p[1] == '.'
841 && (p[2] == '/'
842 || p[2] == 0
843 || (p[2] == '.' && (p[3] == '/'
844 || p[3] == 0))))
570d7624
JB
845 lose = 1;
846#ifdef VMS
847 if (p[0] == '\\')
848 lose = 1;
849 if (p[0] == '/') {
850 /* if dev:[dir]/, move nm to / */
851 if (!slash && p > nm && (brack || colon)) {
852 nm = (brack ? brack + 1 : colon + 1);
853 lbrack = rbrack = 0;
854 brack = 0;
855 colon = 0;
856 }
857 slash = p;
858 }
859 if (p[0] == '-')
860#ifndef VMS4_4
861 /* VMS pre V4.4,convert '-'s in filenames. */
862 if (lbrack == rbrack)
863 {
864 if (dots < 2) /* this is to allow negative version numbers */
865 p[0] = '_';
866 }
867 else
868#endif /* VMS4_4 */
869 if (lbrack > rbrack &&
870 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
871 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
872 lose = 1;
873#ifndef VMS4_4
874 else
875 p[0] = '_';
876#endif /* VMS4_4 */
877 /* count open brackets, reset close bracket pointer */
878 if (p[0] == '[' || p[0] == '<')
879 lbrack++, brack = 0;
880 /* count close brackets, set close bracket pointer */
881 if (p[0] == ']' || p[0] == '>')
882 rbrack++, brack = p;
883 /* detect ][ or >< */
884 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
885 lose = 1;
886 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
887 nm = p + 1, lose = 1;
888 if (p[0] == ':' && (colon || slash))
889 /* if dev1:[dir]dev2:, move nm to dev2: */
890 if (brack)
891 {
892 nm = brack + 1;
893 brack = 0;
894 }
895 /* if /pathname/dev:, move nm to dev: */
896 else if (slash)
897 nm = slash + 1;
898 /* if node::dev:, move colon following dev */
899 else if (colon && colon[-1] == ':')
900 colon = p;
901 /* if dev1:dev2:, move nm to dev2: */
902 else if (colon && colon[-1] != ':')
903 {
904 nm = colon + 1;
905 colon = 0;
906 }
907 if (p[0] == ':' && !colon)
908 {
909 if (p[1] == ':')
910 p++;
911 colon = p;
912 }
913 if (lbrack == rbrack)
914 if (p[0] == ';')
915 dots = 2;
916 else if (p[0] == '.')
917 dots++;
918#endif /* VMS */
919 p++;
920 }
921 if (!lose)
922 {
923#ifdef VMS
924 if (index (nm, '/'))
925 return build_string (sys_translate_unix (nm));
926#endif /* VMS */
4c3c22f3 927#ifndef MSDOS
570d7624
JB
928 if (nm == XSTRING (name)->data)
929 return name;
930 return build_string (nm);
4c3c22f3 931#endif
570d7624
JB
932 }
933 }
934
935 /* Now determine directory to start with and put it in newdir */
936
937 newdir = 0;
938
939 if (nm[0] == '~') /* prefix ~ */
c77d647e
JB
940 {
941 if (nm[1] == '/'
570d7624 942#ifdef VMS
c77d647e
JB
943 || nm[1] == ':'
944#endif /* VMS */
945 || nm[1] == 0) /* ~ by itself */
946 {
947 if (!(newdir = (unsigned char *) egetenv ("HOME")))
948 newdir = (unsigned char *) "";
4c3c22f3
RS
949#ifdef MSDOS
950 dostounix_filename (newdir);
951#endif
c77d647e 952 nm++;
570d7624 953#ifdef VMS
c77d647e
JB
954 nm++; /* Don't leave the slash in nm. */
955#endif /* VMS */
956 }
957 else /* ~user/filename */
958 {
959 for (p = nm; *p && (*p != '/'
570d7624 960#ifdef VMS
c77d647e
JB
961 && *p != ':'
962#endif /* VMS */
963 ); p++);
964 o = (unsigned char *) alloca (p - nm + 1);
965 bcopy ((char *) nm, o, p - nm);
966 o [p - nm] = 0;
967
968 pw = (struct passwd *) getpwnam (o + 1);
969 if (pw)
970 {
971 newdir = (unsigned char *) pw -> pw_dir;
570d7624 972#ifdef VMS
c77d647e 973 nm = p + 1; /* skip the terminator */
570d7624 974#else
c77d647e
JB
975 nm = p;
976#endif /* VMS */
977 }
e5d77022 978
c77d647e
JB
979 /* If we don't find a user of that name, leave the name
980 unchanged; don't move nm forward to p. */
981 }
982 }
570d7624
JB
983
984 if (nm[0] != '/'
985#ifdef VMS
986 && !index (nm, ':')
987#endif /* not VMS */
4c3c22f3
RS
988#ifdef MSDOS
989 && drive == -1
990#endif
570d7624
JB
991 && !newdir)
992 {
570d7624
JB
993 newdir = XSTRING (defalt)->data;
994 }
995
4c3c22f3
RS
996#ifdef MSDOS
997 if (newdir == 0 && relpath)
998 newdir = defdir;
999#endif
bfb61299
JB
1000 if (newdir != 0)
1001 {
1002 /* Get rid of any slash at the end of newdir. */
1003 int length = strlen (newdir);
eabf01d4
RS
1004 /* Adding `length > 1 &&' makes ~ expand into / when homedir
1005 is the root dir. People disagree about whether that is right.
1006 Anyway, we can't take the risk of this change now. */
4c3c22f3
RS
1007#ifdef MSDOS
1008 if (newdir[1] != ':' && length > 1)
1009#endif
eabf01d4 1010 if (newdir[length - 1] == '/')
bfb61299
JB
1011 {
1012 unsigned char *temp = (unsigned char *) alloca (length);
1013 bcopy (newdir, temp, length - 1);
1014 temp[length - 1] = 0;
1015 newdir = temp;
1016 }
1017 tlen = length + 1;
1018 }
1019 else
1020 tlen = 0;
570d7624 1021
bfb61299
JB
1022 /* Now concatenate the directory and name to new space in the stack frame */
1023 tlen += strlen (nm) + 1;
4c3c22f3
RS
1024#ifdef MSDOS
1025 /* Add reserved space for drive name. */
1026 target = (unsigned char *) alloca (tlen + 2) + 2;
1027#else
570d7624 1028 target = (unsigned char *) alloca (tlen);
4c3c22f3 1029#endif
570d7624
JB
1030 *target = 0;
1031
1032 if (newdir)
1033 {
1034#ifndef VMS
1035 if (nm[0] == 0 || nm[0] == '/')
1036 strcpy (target, newdir);
1037 else
1038#endif
c77d647e 1039 file_name_as_directory (target, newdir);
570d7624
JB
1040 }
1041
1042 strcat (target, nm);
1043#ifdef VMS
1044 if (index (target, '/'))
1045 strcpy (target, sys_translate_unix (target));
1046#endif /* VMS */
1047
c77d647e 1048 /* Now canonicalize by removing /. and /foo/.. if they appear. */
570d7624
JB
1049
1050 p = target;
1051 o = target;
1052
1053 while (*p)
1054 {
1055#ifdef VMS
1056 if (*p != ']' && *p != '>' && *p != '-')
1057 {
1058 if (*p == '\\')
1059 p++;
1060 *o++ = *p++;
1061 }
1062 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
1063 /* brackets are offset from each other by 2 */
1064 {
1065 p += 2;
1066 if (*p != '.' && *p != '-' && o[-1] != '.')
1067 /* convert [foo][bar] to [bar] */
1068 while (o[-1] != '[' && o[-1] != '<')
1069 o--;
1070 else if (*p == '-' && *o != '.')
1071 *--p = '.';
1072 }
1073 else if (p[0] == '-' && o[-1] == '.' &&
1074 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1075 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1076 {
1077 do
1078 o--;
1079 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1080 if (p[1] == '.') /* foo.-.bar ==> bar*/
1081 p += 2;
1082 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1083 p++, o--;
1084 /* else [foo.-] ==> [-] */
1085 }
1086 else
1087 {
1088#ifndef VMS4_4
1089 if (*p == '-' &&
1090 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
1091 p[1] != ']' && p[1] != '>' && p[1] != '.')
1092 *p = '_';
1093#endif /* VMS4_4 */
1094 *o++ = *p++;
1095 }
1096#else /* not VMS */
1097 if (*p != '/')
1098 {
1099 *o++ = *p++;
1100 }
1101 else if (!strncmp (p, "//", 2)
1102#ifdef APOLLO
1103 /* // at start of filename is meaningful in Apollo system */
1104 && o != target
1105#endif /* APOLLO */
1106 )
1107 {
1108 o = target;
1109 p++;
1110 }
c77d647e
JB
1111 else if (p[0] == '/'
1112 && p[1] == '.'
1113 && (p[2] == '/'
1114 || p[2] == 0))
1115 {
1116 /* If "/." is the entire filename, keep the "/". Otherwise,
1117 just delete the whole "/.". */
1118 if (o == target && p[2] == '\0')
1119 *o++ = *p;
1120 p += 2;
1121 }
570d7624
JB
1122 else if (!strncmp (p, "/..", 3)
1123 /* `/../' is the "superroot" on certain file systems. */
1124 && o != target
1125 && (p[3] == '/' || p[3] == 0))
1126 {
1127 while (o != target && *--o != '/')
1128 ;
1129#ifdef APOLLO
1130 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
1131 ++o;
1132 else
1133#endif /* APOLLO */
1134 if (o == target && *o == '/')
1135 ++o;
1136 p += 3;
1137 }
1138 else
1139 {
1140 *o++ = *p++;
1141 }
1142#endif /* not VMS */
1143 }
1144
4c3c22f3
RS
1145#ifdef MSDOS
1146 /* at last, set drive name. */
1147 if (target[1] != ':')
1148 {
1149 target -= 2;
1150 target[0] = (drive < 0 ? getdisk () : drive) + 'a';
1151 target[1] = ':';
1152 }
1153#endif
1154
570d7624
JB
1155 return make_string (target, o - target);
1156}
1157#if 0
e5d77022
JB
1158/* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'.
1159DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
570d7624
JB
1160 "Convert FILENAME to absolute, and canonicalize it.\n\
1161Second arg DEFAULT is directory to start with if FILENAME is relative\n\
1162 (does not start with slash); if DEFAULT is nil or missing,\n\
1163the current buffer's value of default-directory is used.\n\
1164Filenames containing `.' or `..' as components are simplified;\n\
1165initial `~/' expands to your home directory.\n\
1166See also the function `substitute-in-file-name'.")
1167 (name, defalt)
1168 Lisp_Object name, defalt;
1169{
1170 unsigned char *nm;
1171
1172 register unsigned char *newdir, *p, *o;
1173 int tlen;
1174 unsigned char *target;
1175 struct passwd *pw;
1176 int lose;
1177#ifdef VMS
1178 unsigned char * colon = 0;
1179 unsigned char * close = 0;
1180 unsigned char * slash = 0;
1181 unsigned char * brack = 0;
1182 int lbrack = 0, rbrack = 0;
1183 int dots = 0;
1184#endif /* VMS */
1185
1186 CHECK_STRING (name, 0);
1187
1188#ifdef VMS
1189 /* Filenames on VMS are always upper case. */
1190 name = Fupcase (name);
1191#endif
1192
1193 nm = XSTRING (name)->data;
1194
1195 /* If nm is absolute, flush ...// and detect /./ and /../.
1196 If no /./ or /../ we can return right away. */
1197 if (
1198 nm[0] == '/'
1199#ifdef VMS
1200 || index (nm, ':')
1201#endif /* VMS */
1202 )
1203 {
1204 p = nm;
1205 lose = 0;
1206 while (*p)
1207 {
1208 if (p[0] == '/' && p[1] == '/'
1209#ifdef APOLLO
1210 /* // at start of filename is meaningful on Apollo system */
1211 && nm != p
1212#endif /* APOLLO */
1213 )
1214 nm = p + 1;
1215 if (p[0] == '/' && p[1] == '~')
1216 nm = p + 1, lose = 1;
1217 if (p[0] == '/' && p[1] == '.'
1218 && (p[2] == '/' || p[2] == 0
1219 || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
1220 lose = 1;
1221#ifdef VMS
1222 if (p[0] == '\\')
1223 lose = 1;
1224 if (p[0] == '/') {
1225 /* if dev:[dir]/, move nm to / */
1226 if (!slash && p > nm && (brack || colon)) {
1227 nm = (brack ? brack + 1 : colon + 1);
1228 lbrack = rbrack = 0;
1229 brack = 0;
1230 colon = 0;
1231 }
1232 slash = p;
1233 }
1234 if (p[0] == '-')
1235#ifndef VMS4_4
1236 /* VMS pre V4.4,convert '-'s in filenames. */
1237 if (lbrack == rbrack)
1238 {
1239 if (dots < 2) /* this is to allow negative version numbers */
1240 p[0] = '_';
1241 }
1242 else
1243#endif /* VMS4_4 */
1244 if (lbrack > rbrack &&
1245 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
1246 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
1247 lose = 1;
1248#ifndef VMS4_4
1249 else
1250 p[0] = '_';
1251#endif /* VMS4_4 */
1252 /* count open brackets, reset close bracket pointer */
1253 if (p[0] == '[' || p[0] == '<')
1254 lbrack++, brack = 0;
1255 /* count close brackets, set close bracket pointer */
1256 if (p[0] == ']' || p[0] == '>')
1257 rbrack++, brack = p;
1258 /* detect ][ or >< */
1259 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
1260 lose = 1;
1261 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
1262 nm = p + 1, lose = 1;
1263 if (p[0] == ':' && (colon || slash))
1264 /* if dev1:[dir]dev2:, move nm to dev2: */
1265 if (brack)
1266 {
1267 nm = brack + 1;
1268 brack = 0;
1269 }
1270 /* if /pathname/dev:, move nm to dev: */
1271 else if (slash)
1272 nm = slash + 1;
1273 /* if node::dev:, move colon following dev */
1274 else if (colon && colon[-1] == ':')
1275 colon = p;
1276 /* if dev1:dev2:, move nm to dev2: */
1277 else if (colon && colon[-1] != ':')
1278 {
1279 nm = colon + 1;
1280 colon = 0;
1281 }
1282 if (p[0] == ':' && !colon)
1283 {
1284 if (p[1] == ':')
1285 p++;
1286 colon = p;
1287 }
1288 if (lbrack == rbrack)
1289 if (p[0] == ';')
1290 dots = 2;
1291 else if (p[0] == '.')
1292 dots++;
1293#endif /* VMS */
1294 p++;
1295 }
1296 if (!lose)
1297 {
1298#ifdef VMS
1299 if (index (nm, '/'))
1300 return build_string (sys_translate_unix (nm));
1301#endif /* VMS */
1302 if (nm == XSTRING (name)->data)
1303 return name;
1304 return build_string (nm);
1305 }
1306 }
1307
1308 /* Now determine directory to start with and put it in NEWDIR */
1309
1310 newdir = 0;
1311
1312 if (nm[0] == '~') /* prefix ~ */
1313 if (nm[1] == '/'
1314#ifdef VMS
1315 || nm[1] == ':'
1316#endif /* VMS */
1317 || nm[1] == 0)/* ~/filename */
1318 {
1319 if (!(newdir = (unsigned char *) egetenv ("HOME")))
1320 newdir = (unsigned char *) "";
1321 nm++;
1322#ifdef VMS
1323 nm++; /* Don't leave the slash in nm. */
1324#endif /* VMS */
1325 }
1326 else /* ~user/filename */
1327 {
1328 /* Get past ~ to user */
1329 unsigned char *user = nm + 1;
1330 /* Find end of name. */
1331 unsigned char *ptr = (unsigned char *) index (user, '/');
1332 int len = ptr ? ptr - user : strlen (user);
1333#ifdef VMS
1334 unsigned char *ptr1 = index (user, ':');
1335 if (ptr1 != 0 && ptr1 - user < len)
1336 len = ptr1 - user;
1337#endif /* VMS */
1338 /* Copy the user name into temp storage. */
1339 o = (unsigned char *) alloca (len + 1);
1340 bcopy ((char *) user, o, len);
1341 o[len] = 0;
1342
1343 /* Look up the user name. */
1344 pw = (struct passwd *) getpwnam (o + 1);
1345 if (!pw)
1346 error ("\"%s\" isn't a registered user", o + 1);
1347
1348 newdir = (unsigned char *) pw->pw_dir;
1349
1350 /* Discard the user name from NM. */
1351 nm += len;
1352 }
1353
1354 if (nm[0] != '/'
1355#ifdef VMS
1356 && !index (nm, ':')
1357#endif /* not VMS */
1358 && !newdir)
1359 {
265a9e55 1360 if (NILP (defalt))
570d7624
JB
1361 defalt = current_buffer->directory;
1362 CHECK_STRING (defalt, 1);
1363 newdir = XSTRING (defalt)->data;
1364 }
1365
1366 /* Now concatenate the directory and name to new space in the stack frame */
1367
1368 tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1;
1369 target = (unsigned char *) alloca (tlen);
1370 *target = 0;
1371
1372 if (newdir)
1373 {
1374#ifndef VMS
1375 if (nm[0] == 0 || nm[0] == '/')
1376 strcpy (target, newdir);
1377 else
1378#endif
1379 file_name_as_directory (target, newdir);
1380 }
1381
1382 strcat (target, nm);
1383#ifdef VMS
1384 if (index (target, '/'))
1385 strcpy (target, sys_translate_unix (target));
1386#endif /* VMS */
1387
1388 /* Now canonicalize by removing /. and /foo/.. if they appear */
1389
1390 p = target;
1391 o = target;
1392
1393 while (*p)
1394 {
1395#ifdef VMS
1396 if (*p != ']' && *p != '>' && *p != '-')
1397 {
1398 if (*p == '\\')
1399 p++;
1400 *o++ = *p++;
1401 }
1402 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
1403 /* brackets are offset from each other by 2 */
1404 {
1405 p += 2;
1406 if (*p != '.' && *p != '-' && o[-1] != '.')
1407 /* convert [foo][bar] to [bar] */
1408 while (o[-1] != '[' && o[-1] != '<')
1409 o--;
1410 else if (*p == '-' && *o != '.')
1411 *--p = '.';
1412 }
1413 else if (p[0] == '-' && o[-1] == '.' &&
1414 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1415 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1416 {
1417 do
1418 o--;
1419 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1420 if (p[1] == '.') /* foo.-.bar ==> bar*/
1421 p += 2;
1422 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1423 p++, o--;
1424 /* else [foo.-] ==> [-] */
1425 }
1426 else
1427 {
1428#ifndef VMS4_4
1429 if (*p == '-' &&
1430 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
1431 p[1] != ']' && p[1] != '>' && p[1] != '.')
1432 *p = '_';
1433#endif /* VMS4_4 */
1434 *o++ = *p++;
1435 }
1436#else /* not VMS */
1437 if (*p != '/')
1438 {
1439 *o++ = *p++;
1440 }
1441 else if (!strncmp (p, "//", 2)
1442#ifdef APOLLO
1443 /* // at start of filename is meaningful in Apollo system */
1444 && o != target
1445#endif /* APOLLO */
1446 )
1447 {
1448 o = target;
1449 p++;
1450 }
1451 else if (p[0] == '/' && p[1] == '.' &&
1452 (p[2] == '/' || p[2] == 0))
1453 p += 2;
1454 else if (!strncmp (p, "/..", 3)
1455 /* `/../' is the "superroot" on certain file systems. */
1456 && o != target
1457 && (p[3] == '/' || p[3] == 0))
1458 {
1459 while (o != target && *--o != '/')
1460 ;
1461#ifdef APOLLO
1462 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
1463 ++o;
1464 else
1465#endif /* APOLLO */
1466 if (o == target && *o == '/')
1467 ++o;
1468 p += 3;
1469 }
1470 else
1471 {
1472 *o++ = *p++;
1473 }
1474#endif /* not VMS */
1475 }
1476
1477 return make_string (target, o - target);
1478}
1479#endif
1480\f
1481DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name,
1482 Ssubstitute_in_file_name, 1, 1, 0,
1483 "Substitute environment variables referred to in FILENAME.\n\
1484`$FOO' where FOO is an environment variable name means to substitute\n\
1485the value of that variable. The variable name should be terminated\n\
1486with a character not a letter, digit or underscore; otherwise, enclose\n\
1487the entire variable name in braces.\n\
1488If `/~' appears, all of FILENAME through that `/' is discarded.\n\n\
1489On VMS, `$' substitution is not done; this function does little and only\n\
1490duplicates what `expand-file-name' does.")
1491 (string)
1492 Lisp_Object string;
1493{
1494 unsigned char *nm;
1495
1496 register unsigned char *s, *p, *o, *x, *endp;
1497 unsigned char *target;
1498 int total = 0;
1499 int substituted = 0;
1500 unsigned char *xnm;
1501
1502 CHECK_STRING (string, 0);
1503
1504 nm = XSTRING (string)->data;
a5a1cc06
RS
1505#ifdef MSDOS
1506 dostounix_filename (nm = strcpy (alloca (strlen (nm) + 1), nm));
1507 substituted = !strcmp (nm, XSTRING (string)->data);
1508#endif
570d7624
JB
1509 endp = nm + XSTRING (string)->size;
1510
1511 /* If /~ or // appears, discard everything through first slash. */
1512
1513 for (p = nm; p != endp; p++)
1514 {
1515 if ((p[0] == '~' ||
1516#ifdef APOLLO
1517 /* // at start of file name is meaningful in Apollo system */
1518 (p[0] == '/' && p - 1 != nm)
1519#else /* not APOLLO */
1520 p[0] == '/'
1521#endif /* not APOLLO */
1522 )
1523 && p != nm &&
1524#ifdef VMS
1525 (p[-1] == ':' || p[-1] == ']' || p[-1] == '>' ||
1526#endif /* VMS */
1527 p[-1] == '/')
1528#ifdef VMS
1529 )
1530#endif /* VMS */
1531 {
1532 nm = p;
1533 substituted = 1;
1534 }
4c3c22f3
RS
1535#ifdef MSDOS
1536 if (p[0] && p[1] == ':')
1537 {
1538 nm = p;
1539 substituted = 1;
1540 }
1541#endif /* MSDOS */
570d7624
JB
1542 }
1543
1544#ifdef VMS
1545 return build_string (nm);
1546#else
1547
1548 /* See if any variables are substituted into the string
1549 and find the total length of their values in `total' */
1550
1551 for (p = nm; p != endp;)
1552 if (*p != '$')
1553 p++;
1554 else
1555 {
1556 p++;
1557 if (p == endp)
1558 goto badsubst;
1559 else if (*p == '$')
1560 {
1561 /* "$$" means a single "$" */
1562 p++;
1563 total -= 1;
1564 substituted = 1;
1565 continue;
1566 }
1567 else if (*p == '{')
1568 {
1569 o = ++p;
1570 while (p != endp && *p != '}') p++;
1571 if (*p != '}') goto missingclose;
1572 s = p;
1573 }
1574 else
1575 {
1576 o = p;
1577 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1578 s = p;
1579 }
1580
1581 /* Copy out the variable name */
1582 target = (unsigned char *) alloca (s - o + 1);
1583 strncpy (target, o, s - o);
1584 target[s - o] = 0;
4c3c22f3
RS
1585#ifdef MSDOS
1586 strupr (target); /* $home == $HOME etc. */
1587#endif
570d7624
JB
1588
1589 /* Get variable value */
1590 o = (unsigned char *) egetenv (target);
570d7624
JB
1591 if (!o) goto badvar;
1592 total += strlen (o);
1593 substituted = 1;
1594 }
1595
1596 if (!substituted)
1597 return string;
1598
1599 /* If substitution required, recopy the string and do it */
1600 /* Make space in stack frame for the new copy */
1601 xnm = (unsigned char *) alloca (XSTRING (string)->size + total + 1);
1602 x = xnm;
1603
1604 /* Copy the rest of the name through, replacing $ constructs with values */
1605 for (p = nm; *p;)
1606 if (*p != '$')
1607 *x++ = *p++;
1608 else
1609 {
1610 p++;
1611 if (p == endp)
1612 goto badsubst;
1613 else if (*p == '$')
1614 {
1615 *x++ = *p++;
1616 continue;
1617 }
1618 else if (*p == '{')
1619 {
1620 o = ++p;
1621 while (p != endp && *p != '}') p++;
1622 if (*p != '}') goto missingclose;
1623 s = p++;
1624 }
1625 else
1626 {
1627 o = p;
1628 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1629 s = p;
1630 }
1631
1632 /* Copy out the variable name */
1633 target = (unsigned char *) alloca (s - o + 1);
1634 strncpy (target, o, s - o);
1635 target[s - o] = 0;
4c3c22f3
RS
1636#ifdef MSDOS
1637 strupr (target); /* $home == $HOME etc. */
1638#endif
570d7624
JB
1639
1640 /* Get variable value */
1641 o = (unsigned char *) egetenv (target);
570d7624
JB
1642 if (!o)
1643 goto badvar;
1644
1645 strcpy (x, o);
1646 x += strlen (o);
1647 }
1648
1649 *x = 0;
1650
1651 /* If /~ or // appears, discard everything through first slash. */
1652
1653 for (p = xnm; p != x; p++)
1654 if ((p[0] == '~' ||
1655#ifdef APOLLO
1656 /* // at start of file name is meaningful in Apollo system */
1657 (p[0] == '/' && p - 1 != xnm)
1658#else /* not APOLLO */
1659 p[0] == '/'
1660#endif /* not APOLLO */
1661 )
1662 && p != nm && p[-1] == '/')
1663 xnm = p;
4c3c22f3
RS
1664#ifdef MSDOS
1665 else if (p[0] && p[1] == ':')
1666 xnm = p;
1667#endif
570d7624
JB
1668
1669 return make_string (xnm, x - xnm);
1670
1671 badsubst:
1672 error ("Bad format environment-variable substitution");
1673 missingclose:
1674 error ("Missing \"}\" in environment-variable substitution");
1675 badvar:
1676 error ("Substituting nonexistent environment variable \"%s\"", target);
1677
1678 /* NOTREACHED */
1679#endif /* not VMS */
1680}
1681\f
067ffa38 1682/* A slightly faster and more convenient way to get
298b760e 1683 (directory-file-name (expand-file-name FOO)). */
067ffa38 1684
570d7624
JB
1685Lisp_Object
1686expand_and_dir_to_file (filename, defdir)
1687 Lisp_Object filename, defdir;
1688{
1689 register Lisp_Object abspath;
1690
1691 abspath = Fexpand_file_name (filename, defdir);
1692#ifdef VMS
1693 {
1694 register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1];
1695 if (c == ':' || c == ']' || c == '>')
1696 abspath = Fdirectory_file_name (abspath);
1697 }
1698#else
1699 /* Remove final slash, if any (unless path is root).
1700 stat behaves differently depending! */
1701 if (XSTRING (abspath)->size > 1
1702 && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/')
ddc61f46
RS
1703 /* We cannot take shortcuts; they might be wrong for magic file names. */
1704 abspath = Fdirectory_file_name (abspath);
570d7624
JB
1705#endif
1706 return abspath;
1707}
1708\f
1709barf_or_query_if_file_exists (absname, querystring, interactive)
1710 Lisp_Object absname;
1711 unsigned char *querystring;
1712 int interactive;
1713{
1714 register Lisp_Object tem;
4018b5ef 1715 struct stat statbuf;
570d7624
JB
1716 struct gcpro gcpro1;
1717
4018b5ef
RS
1718 /* stat is a good way to tell whether the file exists,
1719 regardless of what access permissions it has. */
1720 if (stat (XSTRING (absname)->data, &statbuf) >= 0)
570d7624
JB
1721 {
1722 if (! interactive)
1723 Fsignal (Qfile_already_exists,
1724 Fcons (build_string ("File already exists"),
1725 Fcons (absname, Qnil)));
1726 GCPRO1 (absname);
1727 tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
1728 XSTRING (absname)->data, querystring));
1729 UNGCPRO;
265a9e55 1730 if (NILP (tem))
570d7624
JB
1731 Fsignal (Qfile_already_exists,
1732 Fcons (build_string ("File already exists"),
1733 Fcons (absname, Qnil)));
1734 }
1735 return;
1736}
1737
1738DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4,
349a7710 1739 "fCopy file: \nFCopy %s to file: \np\nP",
570d7624
JB
1740 "Copy FILE to NEWNAME. Both args must be strings.\n\
1741Signals a `file-already-exists' error if file NEWNAME already exists,\n\
1742unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\
1743A number as third arg means request confirmation if NEWNAME already exists.\n\
1744This is what happens in interactive use with M-x.\n\
349a7710
JB
1745Fourth arg KEEP-TIME non-nil means give the new file the same\n\
1746last-modified time as the old one. (This works on only some systems.)\n\
1747A prefix arg makes KEEP-TIME non-nil.")
570d7624
JB
1748 (filename, newname, ok_if_already_exists, keep_date)
1749 Lisp_Object filename, newname, ok_if_already_exists, keep_date;
1750{
1751 int ifd, ofd, n;
1752 char buf[16 * 1024];
1753 struct stat st;
32f4334d 1754 Lisp_Object handler;
570d7624 1755 struct gcpro gcpro1, gcpro2;
b5148e85 1756 int count = specpdl_ptr - specpdl;
f73b0ada 1757 int input_file_statable_p;
570d7624
JB
1758
1759 GCPRO2 (filename, newname);
1760 CHECK_STRING (filename, 0);
1761 CHECK_STRING (newname, 1);
1762 filename = Fexpand_file_name (filename, Qnil);
1763 newname = Fexpand_file_name (newname, Qnil);
32f4334d 1764
0bf2eed2 1765 /* If the input file name has special constructs in it,
32f4334d 1766 call the corresponding file handler. */
49307295 1767 handler = Ffind_file_name_handler (filename, Qcopy_file);
0bf2eed2 1768 /* Likewise for output file name. */
51cf6d37 1769 if (NILP (handler))
49307295 1770 handler = Ffind_file_name_handler (newname, Qcopy_file);
32f4334d 1771 if (!NILP (handler))
36712b0a
KH
1772 RETURN_UNGCPRO (call5 (handler, Qcopy_file, filename, newname,
1773 ok_if_already_exists, keep_date));
32f4334d 1774
265a9e55 1775 if (NILP (ok_if_already_exists)
570d7624
JB
1776 || XTYPE (ok_if_already_exists) == Lisp_Int)
1777 barf_or_query_if_file_exists (newname, "copy to it",
1778 XTYPE (ok_if_already_exists) == Lisp_Int);
1779
4018b5ef 1780 ifd = open (XSTRING (filename)->data, O_RDONLY);
570d7624
JB
1781 if (ifd < 0)
1782 report_file_error ("Opening input file", Fcons (filename, Qnil));
1783
b5148e85
RS
1784 record_unwind_protect (close_file_unwind, make_number (ifd));
1785
f73b0ada
BF
1786 /* We can only copy regular files and symbolic links. Other files are not
1787 copyable by us. */
1788 input_file_statable_p = (fstat (ifd, &st) >= 0);
1789
1790#if defined (S_ISREG) && defined (S_ISLNK)
1791 if (input_file_statable_p)
1792 {
1793 if (!(S_ISREG (st.st_mode)) && !(S_ISLNK (st.st_mode)))
1794 {
1795#if defined (EISDIR)
1796 /* Get a better looking error message. */
1797 errno = EISDIR;
1798#endif /* EISDIR */
1799 report_file_error ("Non-regular file", Fcons (filename, Qnil));
1800 }
1801 }
1802#endif /* S_ISREG && S_ISLNK */
1803
570d7624
JB
1804#ifdef VMS
1805 /* Create the copy file with the same record format as the input file */
1806 ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
1807#else
4c3c22f3
RS
1808#ifdef MSDOS
1809 /* System's default file type was set to binary by _fmode in emacs.c. */
1810 ofd = creat (XSTRING (newname)->data, S_IREAD | S_IWRITE);
1811#else /* not MSDOS */
570d7624 1812 ofd = creat (XSTRING (newname)->data, 0666);
4c3c22f3 1813#endif /* not MSDOS */
570d7624
JB
1814#endif /* VMS */
1815 if (ofd < 0)
66331187 1816 report_file_error ("Opening output file", Fcons (newname, Qnil));
b5148e85
RS
1817
1818 record_unwind_protect (close_file_unwind, make_number (ofd));
570d7624 1819
b5148e85
RS
1820 immediate_quit = 1;
1821 QUIT;
570d7624
JB
1822 while ((n = read (ifd, buf, sizeof buf)) > 0)
1823 if (write (ofd, buf, n) != n)
66331187 1824 report_file_error ("I/O error", Fcons (newname, Qnil));
b5148e85 1825 immediate_quit = 0;
570d7624 1826
5acac34e
RS
1827 /* Closing the output clobbers the file times on some systems. */
1828 if (close (ofd) < 0)
1829 report_file_error ("I/O error", Fcons (newname, Qnil));
1830
f73b0ada 1831 if (input_file_statable_p)
570d7624 1832 {
265a9e55 1833 if (!NILP (keep_date))
570d7624 1834 {
de5bf5d3
JB
1835 EMACS_TIME atime, mtime;
1836 EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
1837 EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
1838 EMACS_SET_UTIMES (XSTRING (newname)->data, atime, mtime);
570d7624 1839 }
570d7624
JB
1840#ifdef APOLLO
1841 if (!egetenv ("USE_DOMAIN_ACLS"))
1842#endif
de5bf5d3 1843 chmod (XSTRING (newname)->data, st.st_mode & 07777);
570d7624
JB
1844 }
1845
5acac34e
RS
1846 close (ifd);
1847
b5148e85
RS
1848 /* Discard the unwind protects. */
1849 specpdl_ptr = specpdl + count;
1850
570d7624
JB
1851 UNGCPRO;
1852 return Qnil;
1853}
1854
9bbe01fb 1855DEFUN ("make-directory-internal", Fmake_directory_internal,
353cfc19 1856 Smake_directory_internal, 1, 1, 0,
570d7624
JB
1857 "Create a directory. One argument, a file name string.")
1858 (dirname)
1859 Lisp_Object dirname;
1860{
1861 unsigned char *dir;
32f4334d 1862 Lisp_Object handler;
570d7624
JB
1863
1864 CHECK_STRING (dirname, 0);
1865 dirname = Fexpand_file_name (dirname, Qnil);
32f4334d 1866
a6e6e718 1867 handler = Ffind_file_name_handler (dirname, Qmake_directory_internal);
32f4334d 1868 if (!NILP (handler))
e508ad53 1869 return call2 (handler, Qmake_directory_internal, dirname);
9bbe01fb 1870
570d7624
JB
1871 dir = XSTRING (dirname)->data;
1872
1873 if (mkdir (dir, 0777) != 0)
1874 report_file_error ("Creating directory", Flist (1, &dirname));
1875
32f4334d 1876 return Qnil;
570d7624
JB
1877}
1878
aa734e17 1879DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
1691b32b 1880 "Delete a directory. One argument, a file name or directory name string.")
570d7624
JB
1881 (dirname)
1882 Lisp_Object dirname;
1883{
1884 unsigned char *dir;
32f4334d 1885 Lisp_Object handler;
570d7624
JB
1886
1887 CHECK_STRING (dirname, 0);
1691b32b 1888 dirname = Fdirectory_file_name (Fexpand_file_name (dirname, Qnil));
570d7624
JB
1889 dir = XSTRING (dirname)->data;
1890
49307295 1891 handler = Ffind_file_name_handler (dirname, Qdelete_directory);
32f4334d
RS
1892 if (!NILP (handler))
1893 return call2 (handler, Qdelete_directory, dirname);
1894
570d7624
JB
1895 if (rmdir (dir) != 0)
1896 report_file_error ("Removing directory", Flist (1, &dirname));
1897
1898 return Qnil;
1899}
1900
1901DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
1902 "Delete specified file. One argument, a file name string.\n\
1903If file has multiple names, it continues to exist with the other names.")
1904 (filename)
1905 Lisp_Object filename;
1906{
1b50b4f2 1907 int count = specpdl_ptr - specpdl;
32f4334d 1908 Lisp_Object handler;
570d7624
JB
1909 CHECK_STRING (filename, 0);
1910 filename = Fexpand_file_name (filename, Qnil);
32f4334d 1911
1b50b4f2 1912 specbind (Qcompletion_ignored_extensions, Qnil);
49307295 1913 handler = Ffind_file_name_handler (filename, Qdelete_file);
32f4334d 1914 if (!NILP (handler))
1b50b4f2 1915 return unbind_to (count, call2 (handler, Qdelete_file, filename));
32f4334d 1916
570d7624
JB
1917 if (0 > unlink (XSTRING (filename)->data))
1918 report_file_error ("Removing old name", Flist (1, &filename));
1b50b4f2 1919 return unbind_to (count, Qnil);
570d7624
JB
1920}
1921
1922DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
1923 "fRename file: \nFRename %s to file: \np",
1924 "Rename FILE as NEWNAME. Both args strings.\n\
1925If file has names other than FILE, it continues to have those names.\n\
1926Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1927unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1928A number as third arg means request confirmation if NEWNAME already exists.\n\
1929This is what happens in interactive use with M-x.")
1930 (filename, newname, ok_if_already_exists)
1931 Lisp_Object filename, newname, ok_if_already_exists;
1932{
1933#ifdef NO_ARG_ARRAY
1934 Lisp_Object args[2];
1935#endif
32f4334d 1936 Lisp_Object handler;
570d7624
JB
1937 struct gcpro gcpro1, gcpro2;
1938
1939 GCPRO2 (filename, newname);
1940 CHECK_STRING (filename, 0);
1941 CHECK_STRING (newname, 1);
1942 filename = Fexpand_file_name (filename, Qnil);
1943 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1944
1945 /* If the file name has special constructs in it,
1946 call the corresponding file handler. */
49307295 1947 handler = Ffind_file_name_handler (filename, Qrename_file);
51cf6d37 1948 if (NILP (handler))
49307295 1949 handler = Ffind_file_name_handler (newname, Qrename_file);
32f4334d 1950 if (!NILP (handler))
36712b0a
KH
1951 RETURN_UNGCPRO (call4 (handler, Qrename_file,
1952 filename, newname, ok_if_already_exists));
32f4334d 1953
265a9e55 1954 if (NILP (ok_if_already_exists)
570d7624
JB
1955 || XTYPE (ok_if_already_exists) == Lisp_Int)
1956 barf_or_query_if_file_exists (newname, "rename to it",
1957 XTYPE (ok_if_already_exists) == Lisp_Int);
1958#ifndef BSD4_1
1959 if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
1960#else
1961 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data)
1962 || 0 > unlink (XSTRING (filename)->data))
1963#endif
1964 {
1965 if (errno == EXDEV)
1966 {
d093c3ac
RM
1967 Fcopy_file (filename, newname,
1968 /* We have already prompted if it was an integer,
1969 so don't have copy-file prompt again. */
1970 NILP (ok_if_already_exists) ? Qnil : Qt, Qt);
570d7624
JB
1971 Fdelete_file (filename);
1972 }
1973 else
1974#ifdef NO_ARG_ARRAY
1975 {
1976 args[0] = filename;
1977 args[1] = newname;
1978 report_file_error ("Renaming", Flist (2, args));
1979 }
1980#else
1981 report_file_error ("Renaming", Flist (2, &filename));
1982#endif
1983 }
1984 UNGCPRO;
1985 return Qnil;
1986}
1987
1988DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3,
1989 "fAdd name to file: \nFName to add to %s: \np",
1990 "Give FILE additional name NEWNAME. Both args strings.\n\
1991Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1992unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1993A number as third arg means request confirmation if NEWNAME already exists.\n\
1994This is what happens in interactive use with M-x.")
1995 (filename, newname, ok_if_already_exists)
1996 Lisp_Object filename, newname, ok_if_already_exists;
1997{
1998#ifdef NO_ARG_ARRAY
1999 Lisp_Object args[2];
2000#endif
32f4334d 2001 Lisp_Object handler;
570d7624
JB
2002 struct gcpro gcpro1, gcpro2;
2003
2004 GCPRO2 (filename, newname);
2005 CHECK_STRING (filename, 0);
2006 CHECK_STRING (newname, 1);
2007 filename = Fexpand_file_name (filename, Qnil);
2008 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
2009
2010 /* If the file name has special constructs in it,
2011 call the corresponding file handler. */
49307295 2012 handler = Ffind_file_name_handler (filename, Qadd_name_to_file);
32f4334d 2013 if (!NILP (handler))
36712b0a
KH
2014 RETURN_UNGCPRO (call4 (handler, Qadd_name_to_file, filename,
2015 newname, ok_if_already_exists));
32f4334d 2016
265a9e55 2017 if (NILP (ok_if_already_exists)
570d7624
JB
2018 || XTYPE (ok_if_already_exists) == Lisp_Int)
2019 barf_or_query_if_file_exists (newname, "make it a new name",
2020 XTYPE (ok_if_already_exists) == Lisp_Int);
2021 unlink (XSTRING (newname)->data);
2022 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data))
2023 {
2024#ifdef NO_ARG_ARRAY
2025 args[0] = filename;
2026 args[1] = newname;
2027 report_file_error ("Adding new name", Flist (2, args));
2028#else
2029 report_file_error ("Adding new name", Flist (2, &filename));
2030#endif
2031 }
2032
2033 UNGCPRO;
2034 return Qnil;
2035}
2036
2037#ifdef S_IFLNK
2038DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
2039 "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",
2040 "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\
11183104 2041Signals a `file-already-exists' error if a file LINKNAME already exists\n\
570d7624 2042unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
11183104 2043A number as third arg means request confirmation if LINKNAME already exists.\n\
570d7624 2044This happens for interactive use with M-x.")
e5d77022
JB
2045 (filename, linkname, ok_if_already_exists)
2046 Lisp_Object filename, linkname, ok_if_already_exists;
570d7624
JB
2047{
2048#ifdef NO_ARG_ARRAY
2049 Lisp_Object args[2];
2050#endif
32f4334d 2051 Lisp_Object handler;
570d7624
JB
2052 struct gcpro gcpro1, gcpro2;
2053
e5d77022 2054 GCPRO2 (filename, linkname);
570d7624 2055 CHECK_STRING (filename, 0);
e5d77022 2056 CHECK_STRING (linkname, 1);
d9bc1c99
RS
2057 /* If the link target has a ~, we must expand it to get
2058 a truly valid file name. Otherwise, do not expand;
2059 we want to permit links to relative file names. */
2060 if (XSTRING (filename)->data[0] == '~')
2061 filename = Fexpand_file_name (filename, Qnil);
e5d77022 2062 linkname = Fexpand_file_name (linkname, Qnil);
32f4334d
RS
2063
2064 /* If the file name has special constructs in it,
2065 call the corresponding file handler. */
49307295 2066 handler = Ffind_file_name_handler (filename, Qmake_symbolic_link);
32f4334d 2067 if (!NILP (handler))
36712b0a
KH
2068 RETURN_UNGCPRO (call4 (handler, Qmake_symbolic_link, filename,
2069 linkname, ok_if_already_exists));
32f4334d 2070
265a9e55 2071 if (NILP (ok_if_already_exists)
570d7624 2072 || XTYPE (ok_if_already_exists) == Lisp_Int)
e5d77022 2073 barf_or_query_if_file_exists (linkname, "make it a link",
570d7624 2074 XTYPE (ok_if_already_exists) == Lisp_Int);
e5d77022 2075 if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
2076 {
2077 /* If we didn't complain already, silently delete existing file. */
2078 if (errno == EEXIST)
2079 {
9083124b 2080 unlink (XSTRING (linkname)->data);
e5d77022 2081 if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
1a04498e
KH
2082 {
2083 UNGCPRO;
2084 return Qnil;
2085 }
570d7624
JB
2086 }
2087
2088#ifdef NO_ARG_ARRAY
2089 args[0] = filename;
e5d77022 2090 args[1] = linkname;
570d7624
JB
2091 report_file_error ("Making symbolic link", Flist (2, args));
2092#else
2093 report_file_error ("Making symbolic link", Flist (2, &filename));
2094#endif
2095 }
2096 UNGCPRO;
2097 return Qnil;
2098}
2099#endif /* S_IFLNK */
2100
2101#ifdef VMS
2102
2103DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
2104 2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
2105 "Define the job-wide logical name NAME to have the value STRING.\n\
2106If STRING is nil or a null string, the logical name NAME is deleted.")
2107 (varname, string)
2108 Lisp_Object varname;
2109 Lisp_Object string;
2110{
2111 CHECK_STRING (varname, 0);
265a9e55 2112 if (NILP (string))
570d7624
JB
2113 delete_logical_name (XSTRING (varname)->data);
2114 else
2115 {
2116 CHECK_STRING (string, 1);
2117
2118 if (XSTRING (string)->size == 0)
2119 delete_logical_name (XSTRING (varname)->data);
2120 else
2121 define_logical_name (XSTRING (varname)->data, XSTRING (string)->data);
2122 }
2123
2124 return string;
2125}
2126#endif /* VMS */
2127
2128#ifdef HPUX_NET
2129
2130DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
2131 "Open a network connection to PATH using LOGIN as the login string.")
2132 (path, login)
2133 Lisp_Object path, login;
2134{
2135 int netresult;
2136
2137 CHECK_STRING (path, 0);
2138 CHECK_STRING (login, 0);
2139
2140 netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
2141
2142 if (netresult == -1)
2143 return Qnil;
2144 else
2145 return Qt;
2146}
2147#endif /* HPUX_NET */
2148\f
2149DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
2150 1, 1, 0,
2151 "Return t if file FILENAME specifies an absolute path name.\n\
2152On Unix, this is a name starting with a `/' or a `~'.")
2153 (filename)
2154 Lisp_Object filename;
2155{
2156 unsigned char *ptr;
2157
2158 CHECK_STRING (filename, 0);
2159 ptr = XSTRING (filename)->data;
2160 if (*ptr == '/' || *ptr == '~'
2161#ifdef VMS
2162/* ??? This criterion is probably wrong for '<'. */
2163 || index (ptr, ':') || index (ptr, '<')
2164 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
2165 && ptr[1] != '.')
2166#endif /* VMS */
4c3c22f3 2167#ifdef MSDOS
a5a1cc06 2168 || (*ptr != 0 && ptr[1] == ':' && (ptr[2] == '/' || ptr[2] == '\\'))
4c3c22f3 2169#endif
570d7624
JB
2170 )
2171 return Qt;
2172 else
2173 return Qnil;
2174}
2175
2176DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
2177 "Return t if file FILENAME exists. (This does not mean you can read it.)\n\
2178See also `file-readable-p' and `file-attributes'.")
2179 (filename)
2180 Lisp_Object filename;
2181{
2182 Lisp_Object abspath;
32f4334d 2183 Lisp_Object handler;
4018b5ef 2184 struct stat statbuf;
570d7624
JB
2185
2186 CHECK_STRING (filename, 0);
2187 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2188
2189 /* If the file name has special constructs in it,
2190 call the corresponding file handler. */
49307295 2191 handler = Ffind_file_name_handler (abspath, Qfile_exists_p);
32f4334d 2192 if (!NILP (handler))
09121adc 2193 return call2 (handler, Qfile_exists_p, abspath);
32f4334d 2194
4018b5ef 2195 return (stat (XSTRING (abspath)->data, &statbuf) >= 0) ? Qt : Qnil;
570d7624
JB
2196}
2197
2198DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
2199 "Return t if FILENAME can be executed by you.\n\
8b235fde 2200For a directory, this means you can access files in that directory.")
570d7624
JB
2201 (filename)
2202 Lisp_Object filename;
2203
2204{
2205 Lisp_Object abspath;
32f4334d 2206 Lisp_Object handler;
570d7624
JB
2207
2208 CHECK_STRING (filename, 0);
2209 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2210
2211 /* If the file name has special constructs in it,
2212 call the corresponding file handler. */
49307295 2213 handler = Ffind_file_name_handler (abspath, Qfile_executable_p);
32f4334d 2214 if (!NILP (handler))
09121adc 2215 return call2 (handler, Qfile_executable_p, abspath);
32f4334d 2216
570d7624
JB
2217 return (access (XSTRING (abspath)->data, 1) >= 0) ? Qt : Qnil;
2218}
2219
2220DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
2221 "Return t if file FILENAME exists and you can read it.\n\
2222See also `file-exists-p' and `file-attributes'.")
2223 (filename)
2224 Lisp_Object filename;
2225{
2226 Lisp_Object abspath;
32f4334d 2227 Lisp_Object handler;
4018b5ef 2228 int desc;
570d7624
JB
2229
2230 CHECK_STRING (filename, 0);
2231 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2232
2233 /* If the file name has special constructs in it,
2234 call the corresponding file handler. */
49307295 2235 handler = Ffind_file_name_handler (abspath, Qfile_readable_p);
32f4334d 2236 if (!NILP (handler))
09121adc 2237 return call2 (handler, Qfile_readable_p, abspath);
32f4334d 2238
4018b5ef
RS
2239 desc = open (XSTRING (abspath)->data, O_RDONLY);
2240 if (desc < 0)
2241 return Qnil;
2242 close (desc);
2243 return Qt;
570d7624
JB
2244}
2245
2246DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
89de89c7
RS
2247 "Return non-nil if file FILENAME is the name of a symbolic link.\n\
2248The value is the name of the file to which it is linked.\n\
2249Otherwise returns nil.")
570d7624
JB
2250 (filename)
2251 Lisp_Object filename;
2252{
2253#ifdef S_IFLNK
2254 char *buf;
2255 int bufsize;
2256 int valsize;
2257 Lisp_Object val;
32f4334d 2258 Lisp_Object handler;
570d7624
JB
2259
2260 CHECK_STRING (filename, 0);
2261 filename = Fexpand_file_name (filename, Qnil);
2262
32f4334d
RS
2263 /* If the file name has special constructs in it,
2264 call the corresponding file handler. */
49307295 2265 handler = Ffind_file_name_handler (filename, Qfile_symlink_p);
32f4334d
RS
2266 if (!NILP (handler))
2267 return call2 (handler, Qfile_symlink_p, filename);
2268
570d7624
JB
2269 bufsize = 100;
2270 while (1)
2271 {
2272 buf = (char *) xmalloc (bufsize);
2273 bzero (buf, bufsize);
2274 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
2275 if (valsize < bufsize) break;
2276 /* Buffer was not long enough */
9ac0d9e0 2277 xfree (buf);
570d7624
JB
2278 bufsize *= 2;
2279 }
2280 if (valsize == -1)
2281 {
9ac0d9e0 2282 xfree (buf);
570d7624
JB
2283 return Qnil;
2284 }
2285 val = make_string (buf, valsize);
9ac0d9e0 2286 xfree (buf);
570d7624
JB
2287 return val;
2288#else /* not S_IFLNK */
2289 return Qnil;
2290#endif /* not S_IFLNK */
2291}
2292
a253bab2
JB
2293#ifdef SOLARIS_BROKEN_ACCESS
2294/* In Solaris 2.1, the readonly-ness of the filesystem is not
2295 considered by the access system call. This is Sun's bug, but we
2296 still have to make Emacs work. */
2297
2298#include <sys/statvfs.h>
2299
2300static int
2301ro_fsys (path)
2302 char *path;
2303{
2304 struct statvfs statvfsb;
2305
2306 if (statvfs(path, &statvfsb))
2307 return 1; /* error from statvfs, be conservative and say not wrtable */
2308 else
2309 /* Otherwise, fsys is ro if bit is set. */
2310 return statvfsb.f_flag & ST_RDONLY;
2311}
2312#else
2313/* But on every other os, access has already done the right thing. */
2314#define ro_fsys(path) 0
2315#endif
2316
570d7624
JB
2317/* Having this before file-symlink-p mysteriously caused it to be forgotten
2318 on the RT/PC. */
2319DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
2320 "Return t if file FILENAME can be written or created by you.")
2321 (filename)
2322 Lisp_Object filename;
2323{
2324 Lisp_Object abspath, dir;
32f4334d 2325 Lisp_Object handler;
570d7624
JB
2326
2327 CHECK_STRING (filename, 0);
2328 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2329
2330 /* If the file name has special constructs in it,
2331 call the corresponding file handler. */
49307295 2332 handler = Ffind_file_name_handler (abspath, Qfile_writable_p);
32f4334d 2333 if (!NILP (handler))
09121adc 2334 return call2 (handler, Qfile_writable_p, abspath);
32f4334d 2335
570d7624 2336 if (access (XSTRING (abspath)->data, 0) >= 0)
a253bab2 2337 return ((access (XSTRING (abspath)->data, 2) >= 0
e7c7295c 2338 && ! ro_fsys ((char *) XSTRING (abspath)->data))
a253bab2 2339 ? Qt : Qnil);
570d7624
JB
2340 dir = Ffile_name_directory (abspath);
2341#ifdef VMS
265a9e55 2342 if (!NILP (dir))
570d7624
JB
2343 dir = Fdirectory_file_name (dir);
2344#endif /* VMS */
4c3c22f3
RS
2345#ifdef MSDOS
2346 if (!NILP (dir))
2347 dir = Fdirectory_file_name (dir);
2348#endif /* MSDOS */
a253bab2 2349 return ((access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
e7c7295c 2350 && ! ro_fsys ((char *) XSTRING (dir)->data))
570d7624
JB
2351 ? Qt : Qnil);
2352}
2353
2354DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
2355 "Return t if file FILENAME is the name of a directory as a file.\n\
2356A directory name spec may be given instead; then the value is t\n\
2357if the directory so specified exists and really is a directory.")
2358 (filename)
2359 Lisp_Object filename;
2360{
2361 register Lisp_Object abspath;
2362 struct stat st;
32f4334d 2363 Lisp_Object handler;
570d7624
JB
2364
2365 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2366
32f4334d
RS
2367 /* If the file name has special constructs in it,
2368 call the corresponding file handler. */
49307295 2369 handler = Ffind_file_name_handler (abspath, Qfile_directory_p);
32f4334d 2370 if (!NILP (handler))
09121adc 2371 return call2 (handler, Qfile_directory_p, abspath);
32f4334d 2372
570d7624
JB
2373 if (stat (XSTRING (abspath)->data, &st) < 0)
2374 return Qnil;
2375 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2376}
2377
b72dea2a
JB
2378DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
2379 "Return t if file FILENAME is the name of a directory as a file,\n\
2380and files in that directory can be opened by you. In order to use a\n\
2381directory as a buffer's current directory, this predicate must return true.\n\
2382A directory name spec may be given instead; then the value is t\n\
2383if the directory so specified exists and really is a readable and\n\
2384searchable directory.")
2385 (filename)
2386 Lisp_Object filename;
2387{
32f4334d 2388 Lisp_Object handler;
1a04498e 2389 int tem;
d26859eb 2390 struct gcpro gcpro1;
32f4334d
RS
2391
2392 /* If the file name has special constructs in it,
2393 call the corresponding file handler. */
49307295 2394 handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p);
32f4334d
RS
2395 if (!NILP (handler))
2396 return call2 (handler, Qfile_accessible_directory_p, filename);
2397
d26859eb
KH
2398 /* It's an unlikely combination, but yes we really do need to gcpro:
2399 Suppose that file-accessible-directory-p has no handler, but
2400 file-directory-p does have a handler; this handler causes a GC which
2401 relocates the string in `filename'; and finally file-directory-p
2402 returns non-nil. Then we would end up passing a garbaged string
2403 to file-executable-p. */
2404 GCPRO1 (filename);
1a04498e
KH
2405 tem = (NILP (Ffile_directory_p (filename))
2406 || NILP (Ffile_executable_p (filename)));
d26859eb 2407 UNGCPRO;
1a04498e 2408 return tem ? Qnil : Qt;
b72dea2a
JB
2409}
2410
570d7624
JB
2411DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2412 "Return mode bits of FILE, as an integer.")
2413 (filename)
2414 Lisp_Object filename;
2415{
2416 Lisp_Object abspath;
2417 struct stat st;
32f4334d 2418 Lisp_Object handler;
570d7624
JB
2419
2420 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2421
32f4334d
RS
2422 /* If the file name has special constructs in it,
2423 call the corresponding file handler. */
49307295 2424 handler = Ffind_file_name_handler (abspath, Qfile_modes);
32f4334d 2425 if (!NILP (handler))
09121adc 2426 return call2 (handler, Qfile_modes, abspath);
32f4334d 2427
570d7624
JB
2428 if (stat (XSTRING (abspath)->data, &st) < 0)
2429 return Qnil;
3ace87e3
KH
2430#ifdef MSDOS
2431 {
2432 int len;
2433 char *suffix;
2434 if (S_ISREG (st.st_mode)
2435 && (len = XSTRING (abspath)->size) >= 5
2436 && (stricmp ((suffix = XSTRING (abspath)->data + len-4), ".com") == 0
2437 || stricmp (suffix, ".exe") == 0
2438 || stricmp (suffix, ".bat") == 0))
2439 st.st_mode |= S_IEXEC;
2440 }
2441#endif /* MSDOS */
2442
570d7624
JB
2443 return make_number (st.st_mode & 07777);
2444}
2445
2446DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2447 "Set mode bits of FILE to MODE (an integer).\n\
2448Only the 12 low bits of MODE are used.")
2449 (filename, mode)
2450 Lisp_Object filename, mode;
2451{
2452 Lisp_Object abspath;
32f4334d 2453 Lisp_Object handler;
570d7624
JB
2454
2455 abspath = Fexpand_file_name (filename, current_buffer->directory);
2456 CHECK_NUMBER (mode, 1);
2457
32f4334d
RS
2458 /* If the file name has special constructs in it,
2459 call the corresponding file handler. */
49307295 2460 handler = Ffind_file_name_handler (abspath, Qset_file_modes);
32f4334d 2461 if (!NILP (handler))
09121adc 2462 return call3 (handler, Qset_file_modes, abspath, mode);
32f4334d 2463
570d7624
JB
2464#ifndef APOLLO
2465 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2466 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2467#else /* APOLLO */
2468 if (!egetenv ("USE_DOMAIN_ACLS"))
2469 {
2470 struct stat st;
2471 struct timeval tvp[2];
2472
2473 /* chmod on apollo also change the file's modtime; need to save the
2474 modtime and then restore it. */
2475 if (stat (XSTRING (abspath)->data, &st) < 0)
2476 {
2477 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2478 return (Qnil);
2479 }
2480
2481 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2482 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2483
2484 /* reset the old accessed and modified times. */
2485 tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
2486 tvp[0].tv_usec = 0;
2487 tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
2488 tvp[1].tv_usec = 0;
2489
2490 if (utimes (XSTRING (abspath)->data, tvp) < 0)
2491 report_file_error ("Doing utimes", Fcons (abspath, Qnil));
2492 }
2493#endif /* APOLLO */
2494
2495 return Qnil;
2496}
2497
c24e9a53 2498DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
5f85ea58
RS
2499 "Set the file permission bits for newly created files.\n\
2500The argument MODE should be an integer; only the low 9 bits are used.\n\
36a8c287 2501This setting is inherited by subprocesses.")
5f85ea58
RS
2502 (mode)
2503 Lisp_Object mode;
36a8c287 2504{
5f85ea58 2505 CHECK_NUMBER (mode, 0);
36a8c287 2506
5f85ea58 2507 umask ((~ XINT (mode)) & 0777);
36a8c287
JB
2508
2509 return Qnil;
2510}
2511
c24e9a53 2512DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
5f85ea58
RS
2513 "Return the default file protection for created files.\n\
2514The value is an integer.")
36a8c287
JB
2515 ()
2516{
5f85ea58
RS
2517 int realmask;
2518 Lisp_Object value;
36a8c287 2519
5f85ea58
RS
2520 realmask = umask (0);
2521 umask (realmask);
36a8c287 2522
5f85ea58
RS
2523 XSET (value, Lisp_Int, (~ realmask) & 0777);
2524 return value;
36a8c287
JB
2525}
2526
85ffea93
RS
2527#ifdef unix
2528
2529DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2530 "Tell Unix to finish all pending disk updates.")
2531 ()
2532{
2533 sync ();
2534 return Qnil;
2535}
2536
2537#endif /* unix */
2538
570d7624
JB
2539DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2540 "Return t if file FILE1 is newer than file FILE2.\n\
2541If FILE1 does not exist, the answer is nil;\n\
2542otherwise, if FILE2 does not exist, the answer is t.")
2543 (file1, file2)
2544 Lisp_Object file1, file2;
2545{
32f4334d 2546 Lisp_Object abspath1, abspath2;
570d7624
JB
2547 struct stat st;
2548 int mtime1;
32f4334d 2549 Lisp_Object handler;
09121adc 2550 struct gcpro gcpro1, gcpro2;
570d7624
JB
2551
2552 CHECK_STRING (file1, 0);
2553 CHECK_STRING (file2, 0);
2554
09121adc
RS
2555 abspath1 = Qnil;
2556 GCPRO2 (abspath1, file2);
32f4334d
RS
2557 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2558 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
09121adc 2559 UNGCPRO;
570d7624 2560
32f4334d
RS
2561 /* If the file name has special constructs in it,
2562 call the corresponding file handler. */
49307295 2563 handler = Ffind_file_name_handler (abspath1, Qfile_newer_than_file_p);
51cf6d37 2564 if (NILP (handler))
49307295 2565 handler = Ffind_file_name_handler (abspath2, Qfile_newer_than_file_p);
32f4334d
RS
2566 if (!NILP (handler))
2567 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2568
2569 if (stat (XSTRING (abspath1)->data, &st) < 0)
570d7624
JB
2570 return Qnil;
2571
2572 mtime1 = st.st_mtime;
2573
32f4334d 2574 if (stat (XSTRING (abspath2)->data, &st) < 0)
570d7624
JB
2575 return Qt;
2576
2577 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2578}
2579\f
4c3c22f3
RS
2580#ifdef MSDOS
2581Lisp_Object Qfind_buffer_file_type;
2582#endif
2583
570d7624 2584DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
3d0387c0 2585 1, 5, 0,
570d7624 2586 "Insert contents of file FILENAME after point.\n\
7fded690 2587Returns list of absolute file name and length of data inserted.\n\
570d7624
JB
2588If second argument VISIT is non-nil, the buffer's visited filename\n\
2589and last save file modtime are set, and it is marked unmodified.\n\
2590If visiting and the file does not exist, visiting is completed\n\
7fded690
JB
2591before the error is signaled.\n\n\
2592The optional third and fourth arguments BEG and END\n\
2593specify what portion of the file to insert.\n\
3d0387c0
RS
2594If VISIT is non-nil, BEG and END must be nil.\n\
2595If optional fifth argument REPLACE is non-nil,\n\
2596it means replace the current buffer contents (in the accessible portion)\n\
2597with the file contents. This is better than simply deleting and inserting\n\
2598the whole thing because (1) it preserves some marker positions\n\
2599and (2) it puts less data in the undo list.")
2600 (filename, visit, beg, end, replace)
2601 Lisp_Object filename, visit, beg, end, replace;
570d7624
JB
2602{
2603 struct stat st;
2604 register int fd;
2605 register int inserted = 0;
2606 register int how_much;
2607 int count = specpdl_ptr - specpdl;
1a04498e 2608 struct gcpro gcpro1, gcpro2, gcpro3;
d6a3cc15
RS
2609 Lisp_Object handler, val, insval;
2610 Lisp_Object p;
7fded690 2611 int total;
32f4334d
RS
2612
2613 val = Qnil;
d6a3cc15 2614 p = Qnil;
32f4334d 2615
1a04498e 2616 GCPRO3 (filename, val, p);
265a9e55 2617 if (!NILP (current_buffer->read_only))
570d7624
JB
2618 Fbarf_if_buffer_read_only();
2619
2620 CHECK_STRING (filename, 0);
2621 filename = Fexpand_file_name (filename, Qnil);
2622
32f4334d
RS
2623 /* If the file name has special constructs in it,
2624 call the corresponding file handler. */
49307295 2625 handler = Ffind_file_name_handler (filename, Qinsert_file_contents);
32f4334d
RS
2626 if (!NILP (handler))
2627 {
3d0387c0
RS
2628 val = call6 (handler, Qinsert_file_contents, filename,
2629 visit, beg, end, replace);
32f4334d
RS
2630 goto handled;
2631 }
2632
570d7624
JB
2633 fd = -1;
2634
2635#ifndef APOLLO
99bc28f4 2636 if (stat (XSTRING (filename)->data, &st) < 0)
570d7624 2637#else
4018b5ef 2638 if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0
570d7624
JB
2639 || fstat (fd, &st) < 0)
2640#endif /* not APOLLO */
2641 {
2642 if (fd >= 0) close (fd);
99bc28f4 2643 badopen:
265a9e55 2644 if (NILP (visit))
570d7624
JB
2645 report_file_error ("Opening input file", Fcons (filename, Qnil));
2646 st.st_mtime = -1;
2647 how_much = 0;
2648 goto notfound;
2649 }
2650
99bc28f4 2651#ifdef S_IFREG
be53b411
JB
2652 /* This code will need to be changed in order to work on named
2653 pipes, and it's probably just not worth it. So we should at
2654 least signal an error. */
99bc28f4 2655 if (!S_ISREG (st.st_mode))
be53b411 2656 Fsignal (Qfile_error,
99bc28f4 2657 Fcons (build_string ("not a regular file"),
be53b411
JB
2658 Fcons (filename, Qnil)));
2659#endif
2660
99bc28f4 2661 if (fd < 0)
4018b5ef 2662 if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0)
99bc28f4
KH
2663 goto badopen;
2664
2665 /* Replacement should preserve point as it preserves markers. */
2666 if (!NILP (replace))
2667 record_unwind_protect (restore_point_unwind, Fpoint_marker ());
2668
2669 record_unwind_protect (close_file_unwind, make_number (fd));
2670
570d7624
JB
2671 /* Supposedly happens on VMS. */
2672 if (st.st_size < 0)
2673 error ("File size is negative");
be53b411 2674
7fded690
JB
2675 if (!NILP (beg) || !NILP (end))
2676 if (!NILP (visit))
2677 error ("Attempt to visit less than an entire file");
2678
2679 if (!NILP (beg))
2680 CHECK_NUMBER (beg, 0);
2681 else
2682 XFASTINT (beg) = 0;
2683
2684 if (!NILP (end))
2685 CHECK_NUMBER (end, 0);
2686 else
2687 {
2688 XSETINT (end, st.st_size);
2689 if (XINT (end) != st.st_size)
2690 error ("maximum buffer size exceeded");
2691 }
2692
3d0387c0
RS
2693 /* If requested, replace the accessible part of the buffer
2694 with the file contents. Avoid replacing text at the
2695 beginning or end of the buffer that matches the file contents;
2696 that preserves markers pointing to the unchanged parts. */
e54d3b5d
RS
2697#ifdef MSDOS
2698 /* On MSDOS, replace mode doesn't really work, except for binary files,
2699 and it's not worth supporting just for them. */
2700 if (!NILP (replace))
2701 {
2702 replace = Qnil;
2703 XFASTINT (beg) = 0;
2704 XFASTINT (end) = st.st_size;
2705 del_range_1 (BEGV, ZV, 0);
2706 }
2707#else /* MSDOS */
3d0387c0
RS
2708 if (!NILP (replace))
2709 {
268466ed 2710 unsigned char buffer[1 << 14];
3d0387c0
RS
2711 int same_at_start = BEGV;
2712 int same_at_end = ZV;
9c28748f
RS
2713 int overlap;
2714
3d0387c0
RS
2715 immediate_quit = 1;
2716 QUIT;
2717 /* Count how many chars at the start of the file
2718 match the text at the beginning of the buffer. */
2719 while (1)
2720 {
2721 int nread, bufpos;
2722
2723 nread = read (fd, buffer, sizeof buffer);
2724 if (nread < 0)
2725 error ("IO error reading %s: %s",
2726 XSTRING (filename)->data, strerror (errno));
2727 else if (nread == 0)
2728 break;
2729 bufpos = 0;
2730 while (bufpos < nread && same_at_start < ZV
2731 && FETCH_CHAR (same_at_start) == buffer[bufpos])
2732 same_at_start++, bufpos++;
2733 /* If we found a discrepancy, stop the scan.
2734 Otherwise loop around and scan the next bufferfull. */
2735 if (bufpos != nread)
2736 break;
2737 }
2738 immediate_quit = 0;
2739 /* If the file matches the buffer completely,
2740 there's no need to replace anything. */
1051b3b3 2741 if (same_at_start - BEGV == st.st_size)
3d0387c0
RS
2742 {
2743 close (fd);
a1d2b64a 2744 specpdl_ptr--;
1051b3b3
RS
2745 /* Truncate the buffer to the size of the file. */
2746 del_range_1 (same_at_start, same_at_end, 0);
3d0387c0
RS
2747 goto handled;
2748 }
2749 immediate_quit = 1;
2750 QUIT;
2751 /* Count how many chars at the end of the file
2752 match the text at the end of the buffer. */
2753 while (1)
2754 {
2755 int total_read, nread, bufpos, curpos, trial;
2756
2757 /* At what file position are we now scanning? */
2758 curpos = st.st_size - (ZV - same_at_end);
fc81fa9e
KH
2759 /* If the entire file matches the buffer tail, stop the scan. */
2760 if (curpos == 0)
2761 break;
3d0387c0
RS
2762 /* How much can we scan in the next step? */
2763 trial = min (curpos, sizeof buffer);
2764 if (lseek (fd, curpos - trial, 0) < 0)
2765 report_file_error ("Setting file position",
2766 Fcons (filename, Qnil));
2767
2768 total_read = 0;
2769 while (total_read < trial)
2770 {
2771 nread = read (fd, buffer + total_read, trial - total_read);
2772 if (nread <= 0)
2773 error ("IO error reading %s: %s",
2774 XSTRING (filename)->data, strerror (errno));
2775 total_read += nread;
2776 }
2777 /* Scan this bufferfull from the end, comparing with
2778 the Emacs buffer. */
2779 bufpos = total_read;
2780 /* Compare with same_at_start to avoid counting some buffer text
2781 as matching both at the file's beginning and at the end. */
2782 while (bufpos > 0 && same_at_end > same_at_start
2783 && FETCH_CHAR (same_at_end - 1) == buffer[bufpos - 1])
2784 same_at_end--, bufpos--;
2785 /* If we found a discrepancy, stop the scan.
2786 Otherwise loop around and scan the preceding bufferfull. */
2787 if (bufpos != 0)
2788 break;
2789 }
2790 immediate_quit = 0;
9c28748f
RS
2791
2792 /* Don't try to reuse the same piece of text twice. */
2793 overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV);
2794 if (overlap > 0)
2795 same_at_end += overlap;
2796
3d0387c0
RS
2797 /* Arrange to read only the nonmatching middle part of the file. */
2798 XFASTINT (beg) = same_at_start - BEGV;
2799 XFASTINT (end) = st.st_size - (ZV - same_at_end);
9c28748f 2800
251f623e 2801 del_range_1 (same_at_start, same_at_end, 0);
a1d2b64a
RS
2802 /* Insert from the file at the proper position. */
2803 SET_PT (same_at_start);
3d0387c0 2804 }
e54d3b5d 2805#endif /* MSDOS */
3d0387c0 2806
7fded690
JB
2807 total = XINT (end) - XINT (beg);
2808
570d7624
JB
2809 {
2810 register Lisp_Object temp;
2811
2812 /* Make sure point-max won't overflow after this insertion. */
7fded690
JB
2813 XSET (temp, Lisp_Int, total);
2814 if (total != XINT (temp))
570d7624
JB
2815 error ("maximum buffer size exceeded");
2816 }
2817
57d8d468 2818 if (NILP (visit) && total > 0)
570d7624
JB
2819 prepare_to_modify_buffer (point, point);
2820
2821 move_gap (point);
7fded690
JB
2822 if (GAP_SIZE < total)
2823 make_gap (total - GAP_SIZE);
2824
a1d2b64a 2825 if (XINT (beg) != 0 || !NILP (replace))
7fded690
JB
2826 {
2827 if (lseek (fd, XINT (beg), 0) < 0)
2828 report_file_error ("Setting file position", Fcons (filename, Qnil));
2829 }
2830
a1d2b64a
RS
2831 how_much = 0;
2832 while (inserted < total)
570d7624 2833 {
7fded690 2834 int try = min (total - inserted, 64 << 10);
b5148e85
RS
2835 int this;
2836
2837 /* Allow quitting out of the actual I/O. */
2838 immediate_quit = 1;
2839 QUIT;
2840 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2841 immediate_quit = 0;
570d7624
JB
2842
2843 if (this <= 0)
2844 {
2845 how_much = this;
2846 break;
2847 }
2848
2849 GPT += this;
2850 GAP_SIZE -= this;
2851 ZV += this;
2852 Z += this;
2853 inserted += this;
2854 }
2855
4c3c22f3
RS
2856#ifdef MSDOS
2857 /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
2858 /* Determine file type from name and remove LFs from CR-LFs if the file
2859 is deemed to be a text file. */
2860 {
bf162ea8
RS
2861 current_buffer->buffer_file_type
2862 = call1 (Qfind_buffer_file_type, filename);
bf162ea8 2863 if (NILP (current_buffer->buffer_file_type))
4c3c22f3 2864 {
a1d2b64a
RS
2865 int reduced_size
2866 = inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
4c3c22f3
RS
2867 ZV -= reduced_size;
2868 Z -= reduced_size;
2869 GPT -= reduced_size;
2870 GAP_SIZE += reduced_size;
2871 inserted -= reduced_size;
2872 }
2873 }
2874#endif
2875
570d7624 2876 if (inserted > 0)
7d8451f1
RS
2877 {
2878 record_insert (point, inserted);
8d4e077b
JA
2879
2880 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2881 offset_intervals (current_buffer, point, inserted);
7d8451f1
RS
2882 MODIFF++;
2883 }
570d7624
JB
2884
2885 close (fd);
2886
a1d2b64a
RS
2887 /* Discard the unwind protect for closing the file. */
2888 specpdl_ptr--;
570d7624
JB
2889
2890 if (how_much < 0)
2891 error ("IO error reading %s: %s",
ce97267f 2892 XSTRING (filename)->data, strerror (errno));
570d7624
JB
2893
2894 notfound:
32f4334d 2895 handled:
570d7624 2896
265a9e55 2897 if (!NILP (visit))
570d7624 2898 {
cfadd376
RS
2899 if (!EQ (current_buffer->undo_list, Qt))
2900 current_buffer->undo_list = Qnil;
570d7624
JB
2901#ifdef APOLLO
2902 stat (XSTRING (filename)->data, &st);
2903#endif
62bcf009 2904
a7e82472
RS
2905 if (NILP (handler))
2906 {
2907 current_buffer->modtime = st.st_mtime;
2908 current_buffer->filename = filename;
2909 }
62bcf009 2910
570d7624
JB
2911 current_buffer->save_modified = MODIFF;
2912 current_buffer->auto_save_modified = MODIFF;
2913 XFASTINT (current_buffer->save_length) = Z - BEG;
2914#ifdef CLASH_DETECTION
32f4334d
RS
2915 if (NILP (handler))
2916 {
2917 if (!NILP (current_buffer->filename))
2918 unlock_file (current_buffer->filename);
2919 unlock_file (filename);
2920 }
570d7624 2921#endif /* CLASH_DETECTION */
570d7624 2922 /* If visiting nonexistent file, return nil. */
32f4334d 2923 if (current_buffer->modtime == -1)
570d7624
JB
2924 report_file_error ("Opening input file", Fcons (filename, Qnil));
2925 }
2926
62bcf009 2927 if (inserted > 0 && NILP (visit) && total > 0)
d2cad97d 2928 signal_after_change (point, 0, inserted);
570d7624 2929
d6a3cc15
RS
2930 if (inserted > 0)
2931 {
2932 p = Vafter_insert_file_functions;
2933 while (!NILP (p))
2934 {
2935 insval = call1 (Fcar (p), make_number (inserted));
2936 if (!NILP (insval))
2937 {
2938 CHECK_NUMBER (insval, 0);
2939 inserted = XFASTINT (insval);
2940 }
2941 QUIT;
2942 p = Fcdr (p);
2943 }
2944 }
2945
a1d2b64a
RS
2946 if (NILP (val))
2947 val = Fcons (filename,
2948 Fcons (make_number (inserted),
2949 Qnil));
2950
2951 RETURN_UNGCPRO (unbind_to (count, val));
570d7624 2952}
7fded690 2953\f
d6a3cc15
RS
2954static Lisp_Object build_annotations ();
2955
6fc6f94b
RS
2956/* If build_annotations switched buffers, switch back to BUF.
2957 Kill the temporary buffer that was selected in the meantime. */
2958
2959static Lisp_Object
2960build_annotations_unwind (buf)
2961 Lisp_Object buf;
2962{
2963 Lisp_Object tembuf;
2964
2965 if (XBUFFER (buf) == current_buffer)
2966 return Qnil;
2967 tembuf = Fcurrent_buffer ();
2968 Fset_buffer (buf);
2969 Fkill_buffer (tembuf);
2970 return Qnil;
2971}
2972
570d7624
JB
2973DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2974 "r\nFWrite region to file: ",
2975 "Write current region into specified file.\n\
2976When called from a program, takes three arguments:\n\
2977START, END and FILENAME. START and END are buffer positions.\n\
2978Optional fourth argument APPEND if non-nil means\n\
2979 append to existing file contents (if any).\n\
2980Optional fifth argument VISIT if t means\n\
2981 set the last-save-file-modtime of buffer to this file's modtime\n\
2982 and mark buffer not modified.\n\
3b7792ed
RS
2983If VISIT is a string, it is a second file name;\n\
2984 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
2985 VISIT is also the file name to lock and unlock for clash detection.\n\
1d386d28
RS
2986If VISIT is neither t nor nil nor a string,\n\
2987 that means do not print the \"Wrote file\" message.\n\
570d7624
JB
2988Kludgy feature: if START is a string, then that string is written\n\
2989to the file, instead of any buffer contents, and END is ignored.")
2990 (start, end, filename, append, visit)
2991 Lisp_Object start, end, filename, append, visit;
2992{
2993 register int desc;
2994 int failure;
2995 int save_errno;
2996 unsigned char *fn;
2997 struct stat st;
c975dd7a 2998 int tem;
570d7624 2999 int count = specpdl_ptr - specpdl;
6fc6f94b 3000 int count1;
570d7624
JB
3001#ifdef VMS
3002 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
3003#endif /* VMS */
3eac9910 3004 Lisp_Object handler;
4ad827c5 3005 Lisp_Object visit_file;
d6a3cc15
RS
3006 Lisp_Object annotations;
3007 int visiting, quietly;
3b7792ed 3008 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
6fc6f94b 3009 struct buffer *given_buffer;
4c3c22f3
RS
3010#ifdef MSDOS
3011 int buffer_file_type
3012 = NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
3013#endif
570d7624 3014
561cb8e1 3015 if (!NILP (start) && !STRINGP (start))
570d7624
JB
3016 validate_region (&start, &end);
3017
1a04498e 3018 GCPRO2 (filename, visit);
570d7624 3019 filename = Fexpand_file_name (filename, Qnil);
561cb8e1 3020 if (STRINGP (visit))
e5176bae 3021 visit_file = Fexpand_file_name (visit, Qnil);
4ad827c5
RS
3022 else
3023 visit_file = filename;
1a04498e 3024 UNGCPRO;
4ad827c5 3025
561cb8e1 3026 visiting = (EQ (visit, Qt) || STRINGP (visit));
d6a3cc15
RS
3027 quietly = !NILP (visit);
3028
3029 annotations = Qnil;
3030
3031 GCPRO4 (start, filename, annotations, visit_file);
570d7624 3032
32f4334d
RS
3033 /* If the file name has special constructs in it,
3034 call the corresponding file handler. */
49307295 3035 handler = Ffind_file_name_handler (filename, Qwrite_region);
b56ad927
RS
3036 /* If FILENAME has no handler, see if VISIT has one. */
3037 if (NILP (handler) && XTYPE (visit) == Lisp_String)
49307295 3038 handler = Ffind_file_name_handler (visit, Qwrite_region);
3eac9910 3039
32f4334d
RS
3040 if (!NILP (handler))
3041 {
32f4334d 3042 Lisp_Object val;
51cf6d37
RS
3043 val = call6 (handler, Qwrite_region, start, end,
3044 filename, append, visit);
32f4334d 3045
d6a3cc15 3046 if (visiting)
32f4334d 3047 {
32f4334d
RS
3048 current_buffer->save_modified = MODIFF;
3049 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 3050 current_buffer->filename = visit_file;
32f4334d 3051 }
09121adc 3052 UNGCPRO;
32f4334d
RS
3053 return val;
3054 }
3055
561cb8e1
RS
3056 /* Special kludge to simplify auto-saving. */
3057 if (NILP (start))
3058 {
3059 XFASTINT (start) = BEG;
3060 XFASTINT (end) = Z;
3061 }
3062
6fc6f94b
RS
3063 record_unwind_protect (build_annotations_unwind, Fcurrent_buffer ());
3064 count1 = specpdl_ptr - specpdl;
3065
3066 given_buffer = current_buffer;
d6a3cc15 3067 annotations = build_annotations (start, end);
6fc6f94b
RS
3068 if (current_buffer != given_buffer)
3069 {
3070 start = BEGV;
3071 end = ZV;
3072 }
d6a3cc15 3073
570d7624
JB
3074#ifdef CLASH_DETECTION
3075 if (!auto_saving)
3b7792ed 3076 lock_file (visit_file);
570d7624
JB
3077#endif /* CLASH_DETECTION */
3078
09121adc 3079 fn = XSTRING (filename)->data;
570d7624 3080 desc = -1;
265a9e55 3081 if (!NILP (append))
4c3c22f3
RS
3082#ifdef MSDOS
3083 desc = open (fn, O_WRONLY | buffer_file_type);
3084#else
570d7624 3085 desc = open (fn, O_WRONLY);
4c3c22f3 3086#endif
570d7624
JB
3087
3088 if (desc < 0)
3089#ifdef VMS
3090 if (auto_saving) /* Overwrite any previous version of autosave file */
3091 {
3092 vms_truncate (fn); /* if fn exists, truncate to zero length */
3093 desc = open (fn, O_RDWR);
3094 if (desc < 0)
561cb8e1 3095 desc = creat_copy_attrs (STRINGP (current_buffer->filename)
b72dea2a
JB
3096 ? XSTRING (current_buffer->filename)->data : 0,
3097 fn);
570d7624
JB
3098 }
3099 else /* Write to temporary name and rename if no errors */
3100 {
3101 Lisp_Object temp_name;
3102 temp_name = Ffile_name_directory (filename);
3103
265a9e55 3104 if (!NILP (temp_name))
570d7624
JB
3105 {
3106 temp_name = Fmake_temp_name (concat2 (temp_name,
3107 build_string ("$$SAVE$$")));
3108 fname = XSTRING (filename)->data;
3109 fn = XSTRING (temp_name)->data;
3110 desc = creat_copy_attrs (fname, fn);
3111 if (desc < 0)
3112 {
3113 /* If we can't open the temporary file, try creating a new
3114 version of the original file. VMS "creat" creates a
3115 new version rather than truncating an existing file. */
3116 fn = fname;
3117 fname = 0;
3118 desc = creat (fn, 0666);
3119#if 0 /* This can clobber an existing file and fail to replace it,
3120 if the user runs out of space. */
3121 if (desc < 0)
3122 {
3123 /* We can't make a new version;
3124 try to truncate and rewrite existing version if any. */
3125 vms_truncate (fn);
3126 desc = open (fn, O_RDWR);
3127 }
3128#endif
3129 }
3130 }
3131 else
3132 desc = creat (fn, 0666);
3133 }
3134#else /* not VMS */
4c3c22f3
RS
3135#ifdef MSDOS
3136 desc = open (fn,
3137 O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type,
3138 S_IREAD | S_IWRITE);
3139#else /* not MSDOS */
570d7624 3140 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
4c3c22f3 3141#endif /* not MSDOS */
570d7624
JB
3142#endif /* not VMS */
3143
09121adc
RS
3144 UNGCPRO;
3145
570d7624
JB
3146 if (desc < 0)
3147 {
3148#ifdef CLASH_DETECTION
3149 save_errno = errno;
3b7792ed 3150 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
3151 errno = save_errno;
3152#endif /* CLASH_DETECTION */
3153 report_file_error ("Opening output file", Fcons (filename, Qnil));
3154 }
3155
3156 record_unwind_protect (close_file_unwind, make_number (desc));
3157
265a9e55 3158 if (!NILP (append))
570d7624
JB
3159 if (lseek (desc, 0, 2) < 0)
3160 {
3161#ifdef CLASH_DETECTION
3b7792ed 3162 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
3163#endif /* CLASH_DETECTION */
3164 report_file_error ("Lseek error", Fcons (filename, Qnil));
3165 }
3166
3167#ifdef VMS
3168/*
3169 * Kludge Warning: The VMS C RTL likes to insert carriage returns
3170 * if we do writes that don't end with a carriage return. Furthermore
3171 * it cannot handle writes of more then 16K. The modified
3172 * version of "sys_write" in SYSDEP.C (see comment there) copes with
3173 * this EXCEPT for the last record (iff it doesn't end with a carriage
3174 * return). This implies that if your buffer doesn't end with a carriage
3175 * return, you get one free... tough. However it also means that if
3176 * we make two calls to sys_write (a la the following code) you can
3177 * get one at the gap as well. The easiest way to fix this (honest)
3178 * is to move the gap to the next newline (or the end of the buffer).
3179 * Thus this change.
3180 *
3181 * Yech!
3182 */
3183 if (GPT > BEG && GPT_ADDR[-1] != '\n')
3184 move_gap (find_next_newline (GPT, 1));
3185#endif
3186
3187 failure = 0;
3188 immediate_quit = 1;
3189
561cb8e1 3190 if (STRINGP (start))
570d7624 3191 {
d6a3cc15
RS
3192 failure = 0 > a_write (desc, XSTRING (start)->data,
3193 XSTRING (start)->size, 0, &annotations);
570d7624
JB
3194 save_errno = errno;
3195 }
3196 else if (XINT (start) != XINT (end))
3197 {
c975dd7a 3198 int nwritten = 0;
570d7624
JB
3199 if (XINT (start) < GPT)
3200 {
3201 register int end1 = XINT (end);
3202 tem = XINT (start);
d6a3cc15 3203 failure = 0 > a_write (desc, &FETCH_CHAR (tem),
c975dd7a
RS
3204 min (GPT, end1) - tem, tem, &annotations);
3205 nwritten += min (GPT, end1) - tem;
570d7624
JB
3206 save_errno = errno;
3207 }
3208
3209 if (XINT (end) > GPT && !failure)
3210 {
3211 tem = XINT (start);
3212 tem = max (tem, GPT);
d6a3cc15 3213 failure = 0 > a_write (desc, &FETCH_CHAR (tem), XINT (end) - tem,
c975dd7a
RS
3214 tem, &annotations);
3215 nwritten += XINT (end) - tem;
d6a3cc15
RS
3216 save_errno = errno;
3217 }
c975dd7a
RS
3218
3219 if (nwritten == 0)
d6a3cc15
RS
3220 {
3221 /* If file was empty, still need to write the annotations */
c975dd7a 3222 failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
570d7624
JB
3223 save_errno = errno;
3224 }
3225 }
3226
3227 immediate_quit = 0;
3228
6e23c83e 3229#ifdef HAVE_FSYNC
570d7624
JB
3230 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
3231 Disk full in NFS may be reported here. */
1daffa1c
RS
3232 /* mib says that closing the file will try to write as fast as NFS can do
3233 it, and that means the fsync here is not crucial for autosave files. */
3234 if (!auto_saving && fsync (desc) < 0)
570d7624 3235 failure = 1, save_errno = errno;
570d7624
JB
3236#endif
3237
3238 /* Spurious "file has changed on disk" warnings have been
3239 observed on Suns as well.
3240 It seems that `close' can change the modtime, under nfs.
3241
3242 (This has supposedly been fixed in Sunos 4,
3243 but who knows about all the other machines with NFS?) */
3244#if 0
3245
3246 /* On VMS and APOLLO, must do the stat after the close
3247 since closing changes the modtime. */
3248#ifndef VMS
3249#ifndef APOLLO
3250 /* Recall that #if defined does not work on VMS. */
3251#define FOO
3252 fstat (desc, &st);
3253#endif
3254#endif
3255#endif
3256
3257 /* NFS can report a write failure now. */
3258 if (close (desc) < 0)
3259 failure = 1, save_errno = errno;
3260
3261#ifdef VMS
3262 /* If we wrote to a temporary name and had no errors, rename to real name. */
3263 if (fname)
3264 {
3265 if (!failure)
3266 failure = (rename (fn, fname) != 0), save_errno = errno;
3267 fn = fname;
3268 }
3269#endif /* VMS */
3270
3271#ifndef FOO
3272 stat (fn, &st);
3273#endif
6fc6f94b
RS
3274 /* Discard the unwind protect for close_file_unwind. */
3275 specpdl_ptr = specpdl + count1;
3276 /* Restore the original current buffer. */
98295b48 3277 visit_file = unbind_to (count, visit_file);
570d7624
JB
3278
3279#ifdef CLASH_DETECTION
3280 if (!auto_saving)
3b7792ed 3281 unlock_file (visit_file);
570d7624
JB
3282#endif /* CLASH_DETECTION */
3283
3284 /* Do this before reporting IO error
3285 to avoid a "file has changed on disk" warning on
3286 next attempt to save. */
d6a3cc15 3287 if (visiting)
570d7624
JB
3288 current_buffer->modtime = st.st_mtime;
3289
3290 if (failure)
ce97267f 3291 error ("IO error writing %s: %s", fn, strerror (save_errno));
570d7624 3292
d6a3cc15 3293 if (visiting)
570d7624
JB
3294 {
3295 current_buffer->save_modified = MODIFF;
3296 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 3297 current_buffer->filename = visit_file;
f4226e89 3298 update_mode_lines++;
570d7624 3299 }
d6a3cc15 3300 else if (quietly)
570d7624
JB
3301 return Qnil;
3302
3303 if (!auto_saving)
3b7792ed 3304 message ("Wrote %s", XSTRING (visit_file)->data);
570d7624
JB
3305
3306 return Qnil;
3307}
3308
d6a3cc15
RS
3309Lisp_Object merge ();
3310
3311DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
2ba0ccff 3312 "Return t if (car A) is numerically less than (car B).")
d6a3cc15
RS
3313 (a, b)
3314 Lisp_Object a, b;
3315{
3316 return Flss (Fcar (a), Fcar (b));
3317}
3318
3319/* Build the complete list of annotations appropriate for writing out
3320 the text between START and END, by calling all the functions in
6fc6f94b
RS
3321 write-region-annotate-functions and merging the lists they return.
3322 If one of these functions switches to a different buffer, we assume
3323 that buffer contains altered text. Therefore, the caller must
3324 make sure to restore the current buffer in all cases,
3325 as save-excursion would do. */
d6a3cc15
RS
3326
3327static Lisp_Object
3328build_annotations (start, end)
3329 Lisp_Object start, end;
3330{
3331 Lisp_Object annotations;
3332 Lisp_Object p, res;
3333 struct gcpro gcpro1, gcpro2;
3334
3335 annotations = Qnil;
3336 p = Vwrite_region_annotate_functions;
3337 GCPRO2 (annotations, p);
3338 while (!NILP (p))
3339 {
6fc6f94b
RS
3340 struct buffer *given_buffer = current_buffer;
3341 Vwrite_region_annotations_so_far = annotations;
d6a3cc15 3342 res = call2 (Fcar (p), start, end);
6fc6f94b
RS
3343 /* If the function makes a different buffer current,
3344 assume that means this buffer contains altered text to be output.
3345 Reset START and END from the buffer bounds
3346 and discard all previous annotations because they should have
3347 been dealt with by this function. */
3348 if (current_buffer != given_buffer)
3349 {
6fc6f94b
RS
3350 start = BEGV;
3351 end = ZV;
3352 annotations = Qnil;
3353 }
d6a3cc15
RS
3354 Flength (res); /* Check basic validity of return value */
3355 annotations = merge (annotations, res, Qcar_less_than_car);
3356 p = Fcdr (p);
3357 }
3358 UNGCPRO;
3359 return annotations;
3360}
3361
3362/* Write to descriptor DESC the LEN characters starting at ADDR,
3363 assuming they start at position POS in the buffer.
3364 Intersperse with them the annotations from *ANNOT
3365 (those which fall within the range of positions POS to POS + LEN),
3366 each at its appropriate position.
3367
3368 Modify *ANNOT by discarding elements as we output them.
3369 The return value is negative in case of system call failure. */
3370
3371int
3372a_write (desc, addr, len, pos, annot)
3373 int desc;
3374 register char *addr;
3375 register int len;
3376 int pos;
3377 Lisp_Object *annot;
3378{
3379 Lisp_Object tem;
3380 int nextpos;
3381 int lastpos = pos + len;
3382
eb15aa18 3383 while (NILP (*annot) || CONSP (*annot))
d6a3cc15
RS
3384 {
3385 tem = Fcar_safe (Fcar (*annot));
3386 if (INTEGERP (tem) && XINT (tem) >= pos && XFASTINT (tem) <= lastpos)
3387 nextpos = XFASTINT (tem);
3388 else
3389 return e_write (desc, addr, lastpos - pos);
3390 if (nextpos > pos)
3391 {
3392 if (0 > e_write (desc, addr, nextpos - pos))
3393 return -1;
3394 addr += nextpos - pos;
3395 pos = nextpos;
3396 }
3397 tem = Fcdr (Fcar (*annot));
3398 if (STRINGP (tem))
3399 {
3400 if (0 > e_write (desc, XSTRING (tem)->data, XSTRING (tem)->size))
3401 return -1;
3402 }
3403 *annot = Fcdr (*annot);
3404 }
3405}
3406
570d7624
JB
3407int
3408e_write (desc, addr, len)
3409 int desc;
3410 register char *addr;
3411 register int len;
3412{
3413 char buf[16 * 1024];
3414 register char *p, *end;
3415
3416 if (!EQ (current_buffer->selective_display, Qt))
3417 return write (desc, addr, len) - len;
3418 else
3419 {
3420 p = buf;
3421 end = p + sizeof buf;
3422 while (len--)
3423 {
3424 if (p == end)
3425 {
3426 if (write (desc, buf, sizeof buf) != sizeof buf)
3427 return -1;
3428 p = buf;
3429 }
3430 *p = *addr++;
3431 if (*p++ == '\015')
3432 p[-1] = '\n';
3433 }
3434 if (p != buf)
3435 if (write (desc, buf, p - buf) != p - buf)
3436 return -1;
3437 }
3438 return 0;
3439}
3440
3441DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
3442 Sverify_visited_file_modtime, 1, 1, 0,
3443 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
3444This means that the file has not been changed since it was visited or saved.")
3445 (buf)
3446 Lisp_Object buf;
3447{
3448 struct buffer *b;
3449 struct stat st;
32f4334d 3450 Lisp_Object handler;
570d7624
JB
3451
3452 CHECK_BUFFER (buf, 0);
3453 b = XBUFFER (buf);
3454
3455 if (XTYPE (b->filename) != Lisp_String) return Qt;
3456 if (b->modtime == 0) return Qt;
3457
32f4334d
RS
3458 /* If the file name has special constructs in it,
3459 call the corresponding file handler. */
49307295
KH
3460 handler = Ffind_file_name_handler (b->filename,
3461 Qverify_visited_file_modtime);
32f4334d 3462 if (!NILP (handler))
09121adc 3463 return call2 (handler, Qverify_visited_file_modtime, buf);
32f4334d 3464
570d7624
JB
3465 if (stat (XSTRING (b->filename)->data, &st) < 0)
3466 {
3467 /* If the file doesn't exist now and didn't exist before,
3468 we say that it isn't modified, provided the error is a tame one. */
3469 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
3470 st.st_mtime = -1;
3471 else
3472 st.st_mtime = 0;
3473 }
3474 if (st.st_mtime == b->modtime
3475 /* If both are positive, accept them if they are off by one second. */
3476 || (st.st_mtime > 0 && b->modtime > 0
3477 && (st.st_mtime == b->modtime + 1
3478 || st.st_mtime == b->modtime - 1)))
3479 return Qt;
3480 return Qnil;
3481}
3482
3483DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
3484 Sclear_visited_file_modtime, 0, 0, 0,
3485 "Clear out records of last mod time of visited file.\n\
3486Next attempt to save will certainly not complain of a discrepancy.")
3487 ()
3488{
3489 current_buffer->modtime = 0;
3490 return Qnil;
3491}
3492
f5d5eccf
RS
3493DEFUN ("visited-file-modtime", Fvisited_file_modtime,
3494 Svisited_file_modtime, 0, 0, 0,
3495 "Return the current buffer's recorded visited file modification time.\n\
3496The value is a list of the form (HIGH . LOW), like the time values\n\
3497that `file-attributes' returns.")
3498 ()
3499{
3500 return long_to_cons (current_buffer->modtime);
3501}
3502
570d7624 3503DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
f5d5eccf 3504 Sset_visited_file_modtime, 0, 1, 0,
570d7624
JB
3505 "Update buffer's recorded modification time from the visited file's time.\n\
3506Useful if the buffer was not read from the file normally\n\
f5d5eccf
RS
3507or if the file itself has been changed for some known benign reason.\n\
3508An argument specifies the modification time value to use\n\
3509\(instead of that of the visited file), in the form of a list\n\
3510\(HIGH . LOW) or (HIGH LOW).")
3511 (time_list)
3512 Lisp_Object time_list;
570d7624 3513{
f5d5eccf
RS
3514 if (!NILP (time_list))
3515 current_buffer->modtime = cons_to_long (time_list);
3516 else
3517 {
3518 register Lisp_Object filename;
3519 struct stat st;
3520 Lisp_Object handler;
570d7624 3521
f5d5eccf 3522 filename = Fexpand_file_name (current_buffer->filename, Qnil);
32f4334d 3523
f5d5eccf
RS
3524 /* If the file name has special constructs in it,
3525 call the corresponding file handler. */
49307295 3526 handler = Ffind_file_name_handler (filename, Qset_visited_file_modtime);
f5d5eccf 3527 if (!NILP (handler))
caf3c431 3528 /* The handler can find the file name the same way we did. */
76c881b0 3529 return call2 (handler, Qset_visited_file_modtime, Qnil);
f5d5eccf
RS
3530 else if (stat (XSTRING (filename)->data, &st) >= 0)
3531 current_buffer->modtime = st.st_mtime;
3532 }
570d7624
JB
3533
3534 return Qnil;
3535}
3536\f
3537Lisp_Object
3538auto_save_error ()
3539{
570d7624 3540 ring_bell ();
1a04498e 3541 message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3542 Fsleep_for (make_number (1), Qnil);
1a04498e 3543 message ("Autosaving...error!for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3544 Fsleep_for (make_number (1), Qnil);
1a04498e 3545 message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3546 Fsleep_for (make_number (1), Qnil);
570d7624
JB
3547 return Qnil;
3548}
3549
3550Lisp_Object
3551auto_save_1 ()
3552{
3553 unsigned char *fn;
3554 struct stat st;
3555
3556 /* Get visited file's mode to become the auto save file's mode. */
3557 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
3558 /* But make sure we can overwrite it later! */
3559 auto_save_mode_bits = st.st_mode | 0600;
3560 else
3561 auto_save_mode_bits = 0666;
3562
3563 return
3564 Fwrite_region (Qnil, Qnil,
3565 current_buffer->auto_save_file_name,
3566 Qnil, Qlambda);
3567}
3568
e54d3b5d 3569static Lisp_Object
15fa1468
RS
3570do_auto_save_unwind (desc) /* used as unwind-protect function */
3571 Lisp_Object desc;
e54d3b5d 3572{
15fa1468 3573 close (XINT (desc));
e54d3b5d
RS
3574 return Qnil;
3575}
3576
570d7624
JB
3577DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
3578 "Auto-save all buffers that need it.\n\
3579This is all buffers that have auto-saving enabled\n\
3580and are changed since last auto-saved.\n\
3581Auto-saving writes the buffer into a file\n\
3582so that your editing is not lost if the system crashes.\n\
012d4cdc
RS
3583This file is not the file you visited; that changes only when you save.\n\
3584Normally we run the normal hook `auto-save-hook' before saving.\n\n\
570d7624 3585Non-nil first argument means do not print any message if successful.\n\
4746118a 3586Non-nil second argument means save only current buffer.")
17857782
JB
3587 (no_message, current_only)
3588 Lisp_Object no_message, current_only;
570d7624
JB
3589{
3590 struct buffer *old = current_buffer, *b;
3591 Lisp_Object tail, buf;
3592 int auto_saved = 0;
3593 char *omessage = echo_area_glyphs;
f05b275b 3594 int omessage_length = echo_area_glyphs_length;
f14b1c68
JB
3595 extern int minibuf_level;
3596 int do_handled_files;
ff4c9993 3597 Lisp_Object oquit;
e54d3b5d 3598 int listdesc;
e54d3b5d
RS
3599 int count = specpdl_ptr - specpdl;
3600 int *ptr;
ff4c9993
RS
3601
3602 /* Ordinarily don't quit within this function,
3603 but don't make it impossible to quit (in case we get hung in I/O). */
3604 oquit = Vquit_flag;
3605 Vquit_flag = Qnil;
570d7624
JB
3606
3607 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
3608 point to non-strings reached from Vbuffer_alist. */
3609
3610 auto_saving = 1;
3611 if (minibuf_level)
17857782 3612 no_message = Qt;
570d7624 3613
265a9e55 3614 if (!NILP (Vrun_hooks))
570d7624
JB
3615 call1 (Vrun_hooks, intern ("auto-save-hook"));
3616
e54d3b5d
RS
3617 if (STRINGP (Vauto_save_list_file_name))
3618 {
3619#ifdef MSDOS
3620 listdesc = open (XSTRING (Vauto_save_list_file_name)->data,
3621 O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
3622 S_IREAD | S_IWRITE);
3623#else /* not MSDOS */
3624 listdesc = creat (XSTRING (Vauto_save_list_file_name)->data, 0666);
3625#endif /* not MSDOS */
3626 }
3627 else
3628 listdesc = -1;
e54d3b5d 3629
15fa1468
RS
3630 /* Arrange to close that file whether or not we get an error. */
3631 if (listdesc >= 0)
3632 record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
e54d3b5d 3633
f14b1c68
JB
3634 /* First, save all files which don't have handlers. If Emacs is
3635 crashing, the handlers may tweak what is causing Emacs to crash
3636 in the first place, and it would be a shame if Emacs failed to
3637 autosave perfectly ordinary files because it couldn't handle some
3638 ange-ftp'd file. */
3639 for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
3640 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
3641 tail = XCONS (tail)->cdr)
3642 {
3643 buf = XCONS (XCONS (tail)->car)->cdr;
3644 b = XBUFFER (buf);
e54d3b5d
RS
3645
3646 /* Record all the buffers that have auto save mode
3647 in the special file that lists them. */
3648 if (XTYPE (b->auto_save_file_name) == Lisp_String
3649 && listdesc >= 0 && do_handled_files == 0)
3650 {
3651 write (listdesc, XSTRING (b->auto_save_file_name)->data,
3652 XSTRING (b->auto_save_file_name)->size);
3653 write (listdesc, "\n", 1);
3654 }
17857782 3655
f14b1c68
JB
3656 if (!NILP (current_only)
3657 && b != current_buffer)
3658 continue;
e54d3b5d 3659
f14b1c68
JB
3660 /* Check for auto save enabled
3661 and file changed since last auto save
3662 and file changed since last real save. */
3663 if (XTYPE (b->auto_save_file_name) == Lisp_String
3664 && b->save_modified < BUF_MODIFF (b)
3665 && b->auto_save_modified < BUF_MODIFF (b)
82c2d839
RS
3666 /* -1 means we've turned off autosaving for a while--see below. */
3667 && XINT (b->save_length) >= 0
f14b1c68 3668 && (do_handled_files
49307295
KH
3669 || NILP (Ffind_file_name_handler (b->auto_save_file_name,
3670 Qwrite_region))))
f14b1c68 3671 {
b60247d9
RS
3672 EMACS_TIME before_time, after_time;
3673
3674 EMACS_GET_TIME (before_time);
3675
3676 /* If we had a failure, don't try again for 20 minutes. */
3677 if (b->auto_save_failure_time >= 0
3678 && EMACS_SECS (before_time) - b->auto_save_failure_time < 1200)
3679 continue;
3680
f14b1c68
JB
3681 if ((XFASTINT (b->save_length) * 10
3682 > (BUF_Z (b) - BUF_BEG (b)) * 13)
3683 /* A short file is likely to change a large fraction;
3684 spare the user annoying messages. */
3685 && XFASTINT (b->save_length) > 5000
3686 /* These messages are frequent and annoying for `*mail*'. */
3687 && !EQ (b->filename, Qnil)
3688 && NILP (no_message))
3689 {
3690 /* It has shrunk too much; turn off auto-saving here. */
3691 message ("Buffer %s has shrunk a lot; auto save turned off there",
3692 XSTRING (b->name)->data);
82c2d839
RS
3693 /* Turn off auto-saving until there's a real save,
3694 and prevent any more warnings. */
3695 XSET (b->save_length, Lisp_Int, -1);
f14b1c68
JB
3696 Fsleep_for (make_number (1), Qnil);
3697 continue;
3698 }
3699 set_buffer_internal (b);
3700 if (!auto_saved && NILP (no_message))
3701 message1 ("Auto-saving...");
3702 internal_condition_case (auto_save_1, Qt, auto_save_error);
3703 auto_saved++;
3704 b->auto_save_modified = BUF_MODIFF (b);
3705 XFASTINT (current_buffer->save_length) = Z - BEG;
3706 set_buffer_internal (old);
b60247d9
RS
3707
3708 EMACS_GET_TIME (after_time);
3709
3710 /* If auto-save took more than 60 seconds,
3711 assume it was an NFS failure that got a timeout. */
3712 if (EMACS_SECS (after_time) - EMACS_SECS (before_time) > 60)
3713 b->auto_save_failure_time = EMACS_SECS (after_time);
f14b1c68
JB
3714 }
3715 }
570d7624 3716
b67f2ca5
RS
3717 /* Prevent another auto save till enough input events come in. */
3718 record_auto_save ();
570d7624 3719
17857782 3720 if (auto_saved && NILP (no_message))
f05b275b
KH
3721 {
3722 if (omessage)
3723 message2 (omessage, omessage_length);
3724 else
3725 message1 ("Auto-saving...done");
3726 }
570d7624 3727
ff4c9993
RS
3728 Vquit_flag = oquit;
3729
570d7624 3730 auto_saving = 0;
e54d3b5d 3731 unbind_to (count, Qnil);
570d7624
JB
3732 return Qnil;
3733}
3734
3735DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
3736 Sset_buffer_auto_saved, 0, 0, 0,
3737 "Mark current buffer as auto-saved with its current text.\n\
3738No auto-save file will be written until the buffer changes again.")
3739 ()
3740{
3741 current_buffer->auto_save_modified = MODIFF;
3742 XFASTINT (current_buffer->save_length) = Z - BEG;
b60247d9
RS
3743 current_buffer->auto_save_failure_time = -1;
3744 return Qnil;
3745}
3746
3747DEFUN ("clear-buffer-auto-save-failure", Fclear_buffer_auto_save_failure,
3748 Sclear_buffer_auto_save_failure, 0, 0, 0,
3749 "Clear any record of a recent auto-save failure in the current buffer.")
3750 ()
3751{
3752 current_buffer->auto_save_failure_time = -1;
570d7624
JB
3753 return Qnil;
3754}
3755
3756DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
3757 0, 0, 0,
3758 "Return t if buffer has been auto-saved since last read in or saved.")
3759 ()
3760{
3761 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
3762}
3763\f
3764/* Reading and completing file names */
3765extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
3766
6e710ae5
RS
3767/* In the string VAL, change each $ to $$ and return the result. */
3768
3769static Lisp_Object
3770double_dollars (val)
3771 Lisp_Object val;
3772{
3773 register unsigned char *old, *new;
3774 register int n;
3775 int osize, count;
3776
3777 osize = XSTRING (val)->size;
3778 /* Quote "$" as "$$" to get it past substitute-in-file-name */
3779 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
3780 if (*old++ == '$') count++;
3781 if (count > 0)
3782 {
3783 old = XSTRING (val)->data;
3784 val = Fmake_string (make_number (osize + count), make_number (0));
3785 new = XSTRING (val)->data;
3786 for (n = osize; n > 0; n--)
3787 if (*old != '$')
3788 *new++ = *old++;
3789 else
3790 {
3791 *new++ = '$';
3792 *new++ = '$';
3793 old++;
3794 }
3795 }
3796 return val;
3797}
3798
570d7624
JB
3799DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
3800 3, 3, 0,
3801 "Internal subroutine for read-file-name. Do not call this.")
3802 (string, dir, action)
3803 Lisp_Object string, dir, action;
3804 /* action is nil for complete, t for return list of completions,
3805 lambda for verify final value */
3806{
3807 Lisp_Object name, specdir, realdir, val, orig_string;
09121adc
RS
3808 int changed;
3809 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3810
3811 realdir = dir;
3812 name = string;
3813 orig_string = Qnil;
3814 specdir = Qnil;
3815 changed = 0;
3816 /* No need to protect ACTION--we only compare it with t and nil. */
3817 GCPRO4 (string, realdir, name, specdir);
570d7624
JB
3818
3819 if (XSTRING (string)->size == 0)
3820 {
570d7624 3821 if (EQ (action, Qlambda))
09121adc
RS
3822 {
3823 UNGCPRO;
3824 return Qnil;
3825 }
570d7624
JB
3826 }
3827 else
3828 {
3829 orig_string = string;
3830 string = Fsubstitute_in_file_name (string);
09121adc 3831 changed = NILP (Fstring_equal (string, orig_string));
570d7624 3832 name = Ffile_name_nondirectory (string);
09121adc
RS
3833 val = Ffile_name_directory (string);
3834 if (! NILP (val))
3835 realdir = Fexpand_file_name (val, realdir);
570d7624
JB
3836 }
3837
265a9e55 3838 if (NILP (action))
570d7624
JB
3839 {
3840 specdir = Ffile_name_directory (string);
3841 val = Ffile_name_completion (name, realdir);
09121adc 3842 UNGCPRO;
570d7624
JB
3843 if (XTYPE (val) != Lisp_String)
3844 {
09121adc 3845 if (changed)
dbd04e01 3846 return double_dollars (string);
09121adc 3847 return val;
570d7624
JB
3848 }
3849
265a9e55 3850 if (!NILP (specdir))
570d7624
JB
3851 val = concat2 (specdir, val);
3852#ifndef VMS
6e710ae5
RS
3853 return double_dollars (val);
3854#else /* not VMS */
09121adc 3855 return val;
6e710ae5 3856#endif /* not VMS */
570d7624 3857 }
09121adc 3858 UNGCPRO;
570d7624
JB
3859
3860 if (EQ (action, Qt))
3861 return Ffile_name_all_completions (name, realdir);
3862 /* Only other case actually used is ACTION = lambda */
3863#ifdef VMS
3864 /* Supposedly this helps commands such as `cd' that read directory names,
3865 but can someone explain how it helps them? -- RMS */
3866 if (XSTRING (name)->size == 0)
3867 return Qt;
3868#endif /* VMS */
3869 return Ffile_exists_p (string);
3870}
3871
3872DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3873 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3874Value is not expanded---you must call `expand-file-name' yourself.\n\
3875Default name to DEFAULT if user enters a null string.\n\
3876 (If DEFAULT is omitted, the visited file name is used.)\n\
3877Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3878 Non-nil and non-t means also require confirmation after completion.\n\
3879Fifth arg INITIAL specifies text to start with.\n\
3880DIR defaults to current buffer's directory default.")
3881 (prompt, dir, defalt, mustmatch, initial)
3882 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3883{
85b5fe07 3884 Lisp_Object val, insdef, insdef1, tem;
570d7624
JB
3885 struct gcpro gcpro1, gcpro2;
3886 register char *homedir;
3887 int count;
3888
265a9e55 3889 if (NILP (dir))
570d7624 3890 dir = current_buffer->directory;
265a9e55 3891 if (NILP (defalt))
570d7624
JB
3892 defalt = current_buffer->filename;
3893
3894 /* If dir starts with user's homedir, change that to ~. */
3895 homedir = (char *) egetenv ("HOME");
3896 if (homedir != 0
3897 && XTYPE (dir) == Lisp_String
3898 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3899 && XSTRING (dir)->data[strlen (homedir)] == '/')
3900 {
3901 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3902 XSTRING (dir)->size - strlen (homedir) + 1);
3903 XSTRING (dir)->data[0] = '~';
3904 }
3905
3906 if (insert_default_directory)
3907 {
3908 insdef = dir;
265a9e55 3909 if (!NILP (initial))
570d7624 3910 {
15c65264 3911 Lisp_Object args[2], pos;
570d7624
JB
3912
3913 args[0] = insdef;
3914 args[1] = initial;
3915 insdef = Fconcat (2, args);
351bd676 3916 pos = make_number (XSTRING (double_dollars (dir))->size);
6e710ae5 3917 insdef1 = Fcons (double_dollars (insdef), pos);
570d7624 3918 }
6e710ae5
RS
3919 else
3920 insdef1 = double_dollars (insdef);
570d7624 3921 }
351bd676
KH
3922 else if (!NILP (initial))
3923 {
3924 insdef = initial;
3925 insdef1 = Fcons (double_dollars (insdef), 0);
3926 }
570d7624 3927 else
85b5fe07 3928 insdef = Qnil, insdef1 = Qnil;
570d7624
JB
3929
3930#ifdef VMS
3931 count = specpdl_ptr - specpdl;
3932 specbind (intern ("completion-ignore-case"), Qt);
3933#endif
3934
3935 GCPRO2 (insdef, defalt);
3936 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
85b5fe07 3937 dir, mustmatch, insdef1,
15c65264 3938 Qfile_name_history);
570d7624
JB
3939
3940#ifdef VMS
3941 unbind_to (count, Qnil);
3942#endif
3943
3944 UNGCPRO;
265a9e55 3945 if (NILP (val))
570d7624
JB
3946 error ("No file name specified");
3947 tem = Fstring_equal (val, insdef);
265a9e55 3948 if (!NILP (tem) && !NILP (defalt))
570d7624 3949 return defalt;
b320926a 3950 if (XSTRING (val)->size == 0 && NILP (insdef))
d9bc1c99
RS
3951 {
3952 if (!NILP (defalt))
3953 return defalt;
3954 else
3955 error ("No default file name");
3956 }
570d7624
JB
3957 return Fsubstitute_in_file_name (val);
3958}
3959
3960#if 0 /* Old version */
3961DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
0de25302
KH
3962 /* Don't confuse make-docfile by having two doc strings for this function.
3963 make-docfile does not pay attention to #if, for good reason! */
3964 0)
570d7624
JB
3965 (prompt, dir, defalt, mustmatch, initial)
3966 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3967{
3968 Lisp_Object val, insdef, tem;
3969 struct gcpro gcpro1, gcpro2;
3970 register char *homedir;
3971 int count;
3972
265a9e55 3973 if (NILP (dir))
570d7624 3974 dir = current_buffer->directory;
265a9e55 3975 if (NILP (defalt))
570d7624
JB
3976 defalt = current_buffer->filename;
3977
3978 /* If dir starts with user's homedir, change that to ~. */
3979 homedir = (char *) egetenv ("HOME");
3980 if (homedir != 0
3981 && XTYPE (dir) == Lisp_String
3982 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3983 && XSTRING (dir)->data[strlen (homedir)] == '/')
3984 {
3985 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3986 XSTRING (dir)->size - strlen (homedir) + 1);
3987 XSTRING (dir)->data[0] = '~';
3988 }
3989
265a9e55 3990 if (!NILP (initial))
570d7624
JB
3991 insdef = initial;
3992 else if (insert_default_directory)
3993 insdef = dir;
3994 else
3995 insdef = build_string ("");
3996
3997#ifdef VMS
3998 count = specpdl_ptr - specpdl;
3999 specbind (intern ("completion-ignore-case"), Qt);
4000#endif
4001
4002 GCPRO2 (insdef, defalt);
4003 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4004 dir, mustmatch,
15c65264
RS
4005 insert_default_directory ? insdef : Qnil,
4006 Qfile_name_history);
570d7624
JB
4007
4008#ifdef VMS
4009 unbind_to (count, Qnil);
4010#endif
4011
4012 UNGCPRO;
265a9e55 4013 if (NILP (val))
570d7624
JB
4014 error ("No file name specified");
4015 tem = Fstring_equal (val, insdef);
265a9e55 4016 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
4017 return defalt;
4018 return Fsubstitute_in_file_name (val);
4019}
4020#endif /* Old version */
4021\f
4022syms_of_fileio ()
4023{
0bf2eed2
RS
4024 Qexpand_file_name = intern ("expand-file-name");
4025 Qdirectory_file_name = intern ("directory-file-name");
4026 Qfile_name_directory = intern ("file-name-directory");
4027 Qfile_name_nondirectory = intern ("file-name-nondirectory");
642ef245 4028 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
0bf2eed2 4029 Qfile_name_as_directory = intern ("file-name-as-directory");
32f4334d 4030 Qcopy_file = intern ("copy-file");
a6e6e718 4031 Qmake_directory_internal = intern ("make-directory-internal");
32f4334d
RS
4032 Qdelete_directory = intern ("delete-directory");
4033 Qdelete_file = intern ("delete-file");
4034 Qrename_file = intern ("rename-file");
4035 Qadd_name_to_file = intern ("add-name-to-file");
4036 Qmake_symbolic_link = intern ("make-symbolic-link");
4037 Qfile_exists_p = intern ("file-exists-p");
4038 Qfile_executable_p = intern ("file-executable-p");
4039 Qfile_readable_p = intern ("file-readable-p");
4040 Qfile_symlink_p = intern ("file-symlink-p");
4041 Qfile_writable_p = intern ("file-writable-p");
4042 Qfile_directory_p = intern ("file-directory-p");
4043 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
4044 Qfile_modes = intern ("file-modes");
4045 Qset_file_modes = intern ("set-file-modes");
4046 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
4047 Qinsert_file_contents = intern ("insert-file-contents");
4048 Qwrite_region = intern ("write-region");
4049 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3ec46acd 4050 Qset_visited_file_modtime = intern ("set-visited-file-modtime");
32f4334d 4051
642ef245
JB
4052 staticpro (&Qexpand_file_name);
4053 staticpro (&Qdirectory_file_name);
4054 staticpro (&Qfile_name_directory);
4055 staticpro (&Qfile_name_nondirectory);
4056 staticpro (&Qunhandled_file_name_directory);
4057 staticpro (&Qfile_name_as_directory);
15c65264 4058 staticpro (&Qcopy_file);
c34b559d 4059 staticpro (&Qmake_directory_internal);
15c65264
RS
4060 staticpro (&Qdelete_directory);
4061 staticpro (&Qdelete_file);
4062 staticpro (&Qrename_file);
4063 staticpro (&Qadd_name_to_file);
4064 staticpro (&Qmake_symbolic_link);
4065 staticpro (&Qfile_exists_p);
4066 staticpro (&Qfile_executable_p);
4067 staticpro (&Qfile_readable_p);
4068 staticpro (&Qfile_symlink_p);
4069 staticpro (&Qfile_writable_p);
4070 staticpro (&Qfile_directory_p);
4071 staticpro (&Qfile_accessible_directory_p);
4072 staticpro (&Qfile_modes);
4073 staticpro (&Qset_file_modes);
4074 staticpro (&Qfile_newer_than_file_p);
4075 staticpro (&Qinsert_file_contents);
4076 staticpro (&Qwrite_region);
4077 staticpro (&Qverify_visited_file_modtime);
642ef245
JB
4078
4079 Qfile_name_history = intern ("file-name-history");
4080 Fset (Qfile_name_history, Qnil);
15c65264
RS
4081 staticpro (&Qfile_name_history);
4082
570d7624
JB
4083 Qfile_error = intern ("file-error");
4084 staticpro (&Qfile_error);
4085 Qfile_already_exists = intern("file-already-exists");
4086 staticpro (&Qfile_already_exists);
4087
4c3c22f3
RS
4088#ifdef MSDOS
4089 Qfind_buffer_file_type = intern ("find-buffer-file-type");
4090 staticpro (&Qfind_buffer_file_type);
4091#endif
4092
d6a3cc15
RS
4093 Qcar_less_than_car = intern ("car-less-than-car");
4094 staticpro (&Qcar_less_than_car);
4095
570d7624
JB
4096 Fput (Qfile_error, Qerror_conditions,
4097 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
4098 Fput (Qfile_error, Qerror_message,
4099 build_string ("File error"));
4100
4101 Fput (Qfile_already_exists, Qerror_conditions,
4102 Fcons (Qfile_already_exists,
4103 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
4104 Fput (Qfile_already_exists, Qerror_message,
4105 build_string ("File already exists"));
4106
4107 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
4108 "*Non-nil means when reading a filename start with default dir in minibuffer.");
4109 insert_default_directory = 1;
4110
4111 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
4112 "*Non-nil means write new files with record format `stmlf'.\n\
4113nil means use format `var'. This variable is meaningful only on VMS.");
4114 vms_stmlf_recfm = 0;
4115
1d1826db
RS
4116 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
4117 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
4118If a file name matches REGEXP, then all I/O on that file is done by calling\n\
4119HANDLER.\n\
4120\n\
4121The first argument given to HANDLER is the name of the I/O primitive\n\
4122to be handled; the remaining arguments are the arguments that were\n\
4123passed to that primitive. For example, if you do\n\
4124 (file-exists-p FILENAME)\n\
4125and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
642ef245
JB
4126 (funcall HANDLER 'file-exists-p FILENAME)\n\
4127The function `find-file-name-handler' checks this list for a handler\n\
4128for its argument.");
09121adc
RS
4129 Vfile_name_handler_alist = Qnil;
4130
d6a3cc15 4131 DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
246cfea5
RS
4132 "A list of functions to be called at the end of `insert-file-contents'.\n\
4133Each is passed one argument, the number of bytes inserted. It should return\n\
4134the new byte count, and leave point the same. If `insert-file-contents' is\n\
4135intercepted by a handler from `file-name-handler-alist', that handler is\n\
d6a3cc15
RS
4136responsible for calling the after-insert-file-functions if appropriate.");
4137 Vafter_insert_file_functions = Qnil;
4138
4139 DEFVAR_LISP ("write-region-annotate-functions", &Vwrite_region_annotate_functions,
246cfea5
RS
4140 "A list of functions to be called at the start of `write-region'.\n\
4141Each is passed two arguments, START and END as for `write-region'. It should\n\
4142return a list of pairs (POSITION . STRING) of strings to be effectively\n\
4143inserted at the specified positions of the file being written (1 means to\n\
4144insert before the first byte written). The POSITIONs must be sorted into\n\
4145increasing order. If there are several functions in the list, the several\n\
d6a3cc15
RS
4146lists are merged destructively.");
4147 Vwrite_region_annotate_functions = Qnil;
4148
6fc6f94b
RS
4149 DEFVAR_LISP ("write-region-annotations-so-far",
4150 &Vwrite_region_annotations_so_far,
4151 "When an annotation function is called, this holds the previous annotations.\n\
4152These are the annotations made by other annotation functions\n\
4153that were already called. See also `write-region-annotate-functions'.");
4154 Vwrite_region_annotations_so_far = Qnil;
4155
82c2d839 4156 DEFVAR_LISP ("inhibit-file-name-handlers", &Vinhibit_file_name_handlers,
268466ed 4157 "A list of file name handlers that temporarily should not be used.\n\
e3e86241 4158This applies only to the operation `inhibit-file-name-operation'.");
82c2d839
RS
4159 Vinhibit_file_name_handlers = Qnil;
4160
a65970a0
RS
4161 DEFVAR_LISP ("inhibit-file-name-operation", &Vinhibit_file_name_operation,
4162 "The operation for which `inhibit-file-name-handlers' is applicable.");
4163 Vinhibit_file_name_operation = Qnil;
4164
e54d3b5d
RS
4165 DEFVAR_LISP ("auto-save-list-file-name", &Vauto_save_list_file_name,
4166 "File name in which we write a list of all auto save file names.");
4167 Vauto_save_list_file_name = Qnil;
4168
642ef245 4169 defsubr (&Sfind_file_name_handler);
570d7624
JB
4170 defsubr (&Sfile_name_directory);
4171 defsubr (&Sfile_name_nondirectory);
642ef245 4172 defsubr (&Sunhandled_file_name_directory);
570d7624
JB
4173 defsubr (&Sfile_name_as_directory);
4174 defsubr (&Sdirectory_file_name);
4175 defsubr (&Smake_temp_name);
4176 defsubr (&Sexpand_file_name);
4177 defsubr (&Ssubstitute_in_file_name);
4178 defsubr (&Scopy_file);
9bbe01fb 4179 defsubr (&Smake_directory_internal);
aa734e17 4180 defsubr (&Sdelete_directory);
570d7624
JB
4181 defsubr (&Sdelete_file);
4182 defsubr (&Srename_file);
4183 defsubr (&Sadd_name_to_file);
4184#ifdef S_IFLNK
4185 defsubr (&Smake_symbolic_link);
4186#endif /* S_IFLNK */
4187#ifdef VMS
4188 defsubr (&Sdefine_logical_name);
4189#endif /* VMS */
4190#ifdef HPUX_NET
4191 defsubr (&Ssysnetunam);
4192#endif /* HPUX_NET */
4193 defsubr (&Sfile_name_absolute_p);
4194 defsubr (&Sfile_exists_p);
4195 defsubr (&Sfile_executable_p);
4196 defsubr (&Sfile_readable_p);
4197 defsubr (&Sfile_writable_p);
4198 defsubr (&Sfile_symlink_p);
4199 defsubr (&Sfile_directory_p);
b72dea2a 4200 defsubr (&Sfile_accessible_directory_p);
570d7624
JB
4201 defsubr (&Sfile_modes);
4202 defsubr (&Sset_file_modes);
c24e9a53
RS
4203 defsubr (&Sset_default_file_modes);
4204 defsubr (&Sdefault_file_modes);
570d7624
JB
4205 defsubr (&Sfile_newer_than_file_p);
4206 defsubr (&Sinsert_file_contents);
4207 defsubr (&Swrite_region);
d6a3cc15 4208 defsubr (&Scar_less_than_car);
570d7624
JB
4209 defsubr (&Sverify_visited_file_modtime);
4210 defsubr (&Sclear_visited_file_modtime);
f5d5eccf 4211 defsubr (&Svisited_file_modtime);
570d7624
JB
4212 defsubr (&Sset_visited_file_modtime);
4213 defsubr (&Sdo_auto_save);
4214 defsubr (&Sset_buffer_auto_saved);
b60247d9 4215 defsubr (&Sclear_buffer_auto_save_failure);
570d7624
JB
4216 defsubr (&Srecent_auto_save_p);
4217
4218 defsubr (&Sread_file_name_internal);
4219 defsubr (&Sread_file_name);
85ffea93 4220
483a2e10 4221#ifdef unix
85ffea93 4222 defsubr (&Sunix_sync);
483a2e10 4223#endif
570d7624 4224}