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