(delete_temp_file): Use Fdelete_file.
[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;
d26859eb 2386 struct gcpro gcpro1;
32f4334d
RS
2387
2388 /* If the file name has special constructs in it,
2389 call the corresponding file handler. */
49307295 2390 handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p);
32f4334d
RS
2391 if (!NILP (handler))
2392 return call2 (handler, Qfile_accessible_directory_p, filename);
2393
d26859eb
KH
2394 /* It's an unlikely combination, but yes we really do need to gcpro:
2395 Suppose that file-accessible-directory-p has no handler, but
2396 file-directory-p does have a handler; this handler causes a GC which
2397 relocates the string in `filename'; and finally file-directory-p
2398 returns non-nil. Then we would end up passing a garbaged string
2399 to file-executable-p. */
2400 GCPRO1 (filename);
1a04498e
KH
2401 tem = (NILP (Ffile_directory_p (filename))
2402 || NILP (Ffile_executable_p (filename)));
d26859eb 2403 UNGCPRO;
1a04498e 2404 return tem ? Qnil : Qt;
b72dea2a
JB
2405}
2406
570d7624
JB
2407DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2408 "Return mode bits of FILE, as an integer.")
2409 (filename)
2410 Lisp_Object filename;
2411{
2412 Lisp_Object abspath;
2413 struct stat st;
32f4334d 2414 Lisp_Object handler;
570d7624
JB
2415
2416 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2417
32f4334d
RS
2418 /* If the file name has special constructs in it,
2419 call the corresponding file handler. */
49307295 2420 handler = Ffind_file_name_handler (abspath, Qfile_modes);
32f4334d 2421 if (!NILP (handler))
09121adc 2422 return call2 (handler, Qfile_modes, abspath);
32f4334d 2423
570d7624
JB
2424 if (stat (XSTRING (abspath)->data, &st) < 0)
2425 return Qnil;
3ace87e3
KH
2426#ifdef MSDOS
2427 {
2428 int len;
2429 char *suffix;
2430 if (S_ISREG (st.st_mode)
2431 && (len = XSTRING (abspath)->size) >= 5
2432 && (stricmp ((suffix = XSTRING (abspath)->data + len-4), ".com") == 0
2433 || stricmp (suffix, ".exe") == 0
2434 || stricmp (suffix, ".bat") == 0))
2435 st.st_mode |= S_IEXEC;
2436 }
2437#endif /* MSDOS */
2438
570d7624
JB
2439 return make_number (st.st_mode & 07777);
2440}
2441
2442DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2443 "Set mode bits of FILE to MODE (an integer).\n\
2444Only the 12 low bits of MODE are used.")
2445 (filename, mode)
2446 Lisp_Object filename, mode;
2447{
2448 Lisp_Object abspath;
32f4334d 2449 Lisp_Object handler;
570d7624
JB
2450
2451 abspath = Fexpand_file_name (filename, current_buffer->directory);
2452 CHECK_NUMBER (mode, 1);
2453
32f4334d
RS
2454 /* If the file name has special constructs in it,
2455 call the corresponding file handler. */
49307295 2456 handler = Ffind_file_name_handler (abspath, Qset_file_modes);
32f4334d 2457 if (!NILP (handler))
09121adc 2458 return call3 (handler, Qset_file_modes, abspath, mode);
32f4334d 2459
570d7624
JB
2460#ifndef APOLLO
2461 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2462 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2463#else /* APOLLO */
2464 if (!egetenv ("USE_DOMAIN_ACLS"))
2465 {
2466 struct stat st;
2467 struct timeval tvp[2];
2468
2469 /* chmod on apollo also change the file's modtime; need to save the
2470 modtime and then restore it. */
2471 if (stat (XSTRING (abspath)->data, &st) < 0)
2472 {
2473 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2474 return (Qnil);
2475 }
2476
2477 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2478 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2479
2480 /* reset the old accessed and modified times. */
2481 tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
2482 tvp[0].tv_usec = 0;
2483 tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
2484 tvp[1].tv_usec = 0;
2485
2486 if (utimes (XSTRING (abspath)->data, tvp) < 0)
2487 report_file_error ("Doing utimes", Fcons (abspath, Qnil));
2488 }
2489#endif /* APOLLO */
2490
2491 return Qnil;
2492}
2493
c24e9a53 2494DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
5f85ea58
RS
2495 "Set the file permission bits for newly created files.\n\
2496The argument MODE should be an integer; only the low 9 bits are used.\n\
36a8c287 2497This setting is inherited by subprocesses.")
5f85ea58
RS
2498 (mode)
2499 Lisp_Object mode;
36a8c287 2500{
5f85ea58 2501 CHECK_NUMBER (mode, 0);
36a8c287 2502
5f85ea58 2503 umask ((~ XINT (mode)) & 0777);
36a8c287
JB
2504
2505 return Qnil;
2506}
2507
c24e9a53 2508DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
5f85ea58
RS
2509 "Return the default file protection for created files.\n\
2510The value is an integer.")
36a8c287
JB
2511 ()
2512{
5f85ea58
RS
2513 int realmask;
2514 Lisp_Object value;
36a8c287 2515
5f85ea58
RS
2516 realmask = umask (0);
2517 umask (realmask);
36a8c287 2518
5f85ea58
RS
2519 XSET (value, Lisp_Int, (~ realmask) & 0777);
2520 return value;
36a8c287
JB
2521}
2522
85ffea93
RS
2523#ifdef unix
2524
2525DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2526 "Tell Unix to finish all pending disk updates.")
2527 ()
2528{
2529 sync ();
2530 return Qnil;
2531}
2532
2533#endif /* unix */
2534
570d7624
JB
2535DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2536 "Return t if file FILE1 is newer than file FILE2.\n\
2537If FILE1 does not exist, the answer is nil;\n\
2538otherwise, if FILE2 does not exist, the answer is t.")
2539 (file1, file2)
2540 Lisp_Object file1, file2;
2541{
32f4334d 2542 Lisp_Object abspath1, abspath2;
570d7624
JB
2543 struct stat st;
2544 int mtime1;
32f4334d 2545 Lisp_Object handler;
09121adc 2546 struct gcpro gcpro1, gcpro2;
570d7624
JB
2547
2548 CHECK_STRING (file1, 0);
2549 CHECK_STRING (file2, 0);
2550
09121adc
RS
2551 abspath1 = Qnil;
2552 GCPRO2 (abspath1, file2);
32f4334d
RS
2553 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2554 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
09121adc 2555 UNGCPRO;
570d7624 2556
32f4334d
RS
2557 /* If the file name has special constructs in it,
2558 call the corresponding file handler. */
49307295 2559 handler = Ffind_file_name_handler (abspath1, Qfile_newer_than_file_p);
51cf6d37 2560 if (NILP (handler))
49307295 2561 handler = Ffind_file_name_handler (abspath2, Qfile_newer_than_file_p);
32f4334d
RS
2562 if (!NILP (handler))
2563 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2564
2565 if (stat (XSTRING (abspath1)->data, &st) < 0)
570d7624
JB
2566 return Qnil;
2567
2568 mtime1 = st.st_mtime;
2569
32f4334d 2570 if (stat (XSTRING (abspath2)->data, &st) < 0)
570d7624
JB
2571 return Qt;
2572
2573 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2574}
2575\f
4c3c22f3
RS
2576#ifdef MSDOS
2577Lisp_Object Qfind_buffer_file_type;
2578#endif
2579
570d7624 2580DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
3d0387c0 2581 1, 5, 0,
570d7624 2582 "Insert contents of file FILENAME after point.\n\
7fded690 2583Returns list of absolute file name and length of data inserted.\n\
570d7624
JB
2584If second argument VISIT is non-nil, the buffer's visited filename\n\
2585and last save file modtime are set, and it is marked unmodified.\n\
2586If visiting and the file does not exist, visiting is completed\n\
7fded690
JB
2587before the error is signaled.\n\n\
2588The optional third and fourth arguments BEG and END\n\
2589specify what portion of the file to insert.\n\
3d0387c0
RS
2590If VISIT is non-nil, BEG and END must be nil.\n\
2591If optional fifth argument REPLACE is non-nil,\n\
2592it means replace the current buffer contents (in the accessible portion)\n\
2593with the file contents. This is better than simply deleting and inserting\n\
2594the whole thing because (1) it preserves some marker positions\n\
2595and (2) it puts less data in the undo list.")
2596 (filename, visit, beg, end, replace)
2597 Lisp_Object filename, visit, beg, end, replace;
570d7624
JB
2598{
2599 struct stat st;
2600 register int fd;
2601 register int inserted = 0;
2602 register int how_much;
2603 int count = specpdl_ptr - specpdl;
1a04498e 2604 struct gcpro gcpro1, gcpro2, gcpro3;
d6a3cc15
RS
2605 Lisp_Object handler, val, insval;
2606 Lisp_Object p;
7fded690 2607 int total;
32f4334d
RS
2608
2609 val = Qnil;
d6a3cc15 2610 p = Qnil;
32f4334d 2611
1a04498e 2612 GCPRO3 (filename, val, p);
265a9e55 2613 if (!NILP (current_buffer->read_only))
570d7624
JB
2614 Fbarf_if_buffer_read_only();
2615
2616 CHECK_STRING (filename, 0);
2617 filename = Fexpand_file_name (filename, Qnil);
2618
32f4334d
RS
2619 /* If the file name has special constructs in it,
2620 call the corresponding file handler. */
49307295 2621 handler = Ffind_file_name_handler (filename, Qinsert_file_contents);
32f4334d
RS
2622 if (!NILP (handler))
2623 {
3d0387c0
RS
2624 val = call6 (handler, Qinsert_file_contents, filename,
2625 visit, beg, end, replace);
32f4334d
RS
2626 goto handled;
2627 }
2628
570d7624
JB
2629 fd = -1;
2630
2631#ifndef APOLLO
99bc28f4 2632 if (stat (XSTRING (filename)->data, &st) < 0)
570d7624 2633#else
4018b5ef 2634 if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0
570d7624
JB
2635 || fstat (fd, &st) < 0)
2636#endif /* not APOLLO */
2637 {
2638 if (fd >= 0) close (fd);
99bc28f4 2639 badopen:
265a9e55 2640 if (NILP (visit))
570d7624
JB
2641 report_file_error ("Opening input file", Fcons (filename, Qnil));
2642 st.st_mtime = -1;
2643 how_much = 0;
2644 goto notfound;
2645 }
2646
99bc28f4 2647#ifdef S_IFREG
be53b411
JB
2648 /* This code will need to be changed in order to work on named
2649 pipes, and it's probably just not worth it. So we should at
2650 least signal an error. */
99bc28f4 2651 if (!S_ISREG (st.st_mode))
be53b411 2652 Fsignal (Qfile_error,
99bc28f4 2653 Fcons (build_string ("not a regular file"),
be53b411
JB
2654 Fcons (filename, Qnil)));
2655#endif
2656
99bc28f4 2657 if (fd < 0)
4018b5ef 2658 if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0)
99bc28f4
KH
2659 goto badopen;
2660
2661 /* Replacement should preserve point as it preserves markers. */
2662 if (!NILP (replace))
2663 record_unwind_protect (restore_point_unwind, Fpoint_marker ());
2664
2665 record_unwind_protect (close_file_unwind, make_number (fd));
2666
570d7624
JB
2667 /* Supposedly happens on VMS. */
2668 if (st.st_size < 0)
2669 error ("File size is negative");
be53b411 2670
7fded690
JB
2671 if (!NILP (beg) || !NILP (end))
2672 if (!NILP (visit))
2673 error ("Attempt to visit less than an entire file");
2674
2675 if (!NILP (beg))
2676 CHECK_NUMBER (beg, 0);
2677 else
2678 XFASTINT (beg) = 0;
2679
2680 if (!NILP (end))
2681 CHECK_NUMBER (end, 0);
2682 else
2683 {
2684 XSETINT (end, st.st_size);
2685 if (XINT (end) != st.st_size)
2686 error ("maximum buffer size exceeded");
2687 }
2688
3d0387c0
RS
2689 /* If requested, replace the accessible part of the buffer
2690 with the file contents. Avoid replacing text at the
2691 beginning or end of the buffer that matches the file contents;
2692 that preserves markers pointing to the unchanged parts. */
e54d3b5d
RS
2693#ifdef MSDOS
2694 /* On MSDOS, replace mode doesn't really work, except for binary files,
2695 and it's not worth supporting just for them. */
2696 if (!NILP (replace))
2697 {
2698 replace = Qnil;
2699 XFASTINT (beg) = 0;
2700 XFASTINT (end) = st.st_size;
2701 del_range_1 (BEGV, ZV, 0);
2702 }
2703#else /* MSDOS */
3d0387c0
RS
2704 if (!NILP (replace))
2705 {
268466ed 2706 unsigned char buffer[1 << 14];
3d0387c0
RS
2707 int same_at_start = BEGV;
2708 int same_at_end = ZV;
9c28748f
RS
2709 int overlap;
2710
3d0387c0
RS
2711 immediate_quit = 1;
2712 QUIT;
2713 /* Count how many chars at the start of the file
2714 match the text at the beginning of the buffer. */
2715 while (1)
2716 {
2717 int nread, bufpos;
2718
2719 nread = read (fd, buffer, sizeof buffer);
2720 if (nread < 0)
2721 error ("IO error reading %s: %s",
2722 XSTRING (filename)->data, strerror (errno));
2723 else if (nread == 0)
2724 break;
2725 bufpos = 0;
2726 while (bufpos < nread && same_at_start < ZV
2727 && FETCH_CHAR (same_at_start) == buffer[bufpos])
2728 same_at_start++, bufpos++;
2729 /* If we found a discrepancy, stop the scan.
2730 Otherwise loop around and scan the next bufferfull. */
2731 if (bufpos != nread)
2732 break;
2733 }
2734 immediate_quit = 0;
2735 /* If the file matches the buffer completely,
2736 there's no need to replace anything. */
1051b3b3 2737 if (same_at_start - BEGV == st.st_size)
3d0387c0
RS
2738 {
2739 close (fd);
a1d2b64a 2740 specpdl_ptr--;
1051b3b3
RS
2741 /* Truncate the buffer to the size of the file. */
2742 del_range_1 (same_at_start, same_at_end, 0);
3d0387c0
RS
2743 goto handled;
2744 }
2745 immediate_quit = 1;
2746 QUIT;
2747 /* Count how many chars at the end of the file
2748 match the text at the end of the buffer. */
2749 while (1)
2750 {
2751 int total_read, nread, bufpos, curpos, trial;
2752
2753 /* At what file position are we now scanning? */
2754 curpos = st.st_size - (ZV - same_at_end);
fc81fa9e
KH
2755 /* If the entire file matches the buffer tail, stop the scan. */
2756 if (curpos == 0)
2757 break;
3d0387c0
RS
2758 /* How much can we scan in the next step? */
2759 trial = min (curpos, sizeof buffer);
2760 if (lseek (fd, curpos - trial, 0) < 0)
2761 report_file_error ("Setting file position",
2762 Fcons (filename, Qnil));
2763
2764 total_read = 0;
2765 while (total_read < trial)
2766 {
2767 nread = read (fd, buffer + total_read, trial - total_read);
2768 if (nread <= 0)
2769 error ("IO error reading %s: %s",
2770 XSTRING (filename)->data, strerror (errno));
2771 total_read += nread;
2772 }
2773 /* Scan this bufferfull from the end, comparing with
2774 the Emacs buffer. */
2775 bufpos = total_read;
2776 /* Compare with same_at_start to avoid counting some buffer text
2777 as matching both at the file's beginning and at the end. */
2778 while (bufpos > 0 && same_at_end > same_at_start
2779 && FETCH_CHAR (same_at_end - 1) == buffer[bufpos - 1])
2780 same_at_end--, bufpos--;
2781 /* If we found a discrepancy, stop the scan.
2782 Otherwise loop around and scan the preceding bufferfull. */
2783 if (bufpos != 0)
2784 break;
2785 }
2786 immediate_quit = 0;
9c28748f
RS
2787
2788 /* Don't try to reuse the same piece of text twice. */
2789 overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV);
2790 if (overlap > 0)
2791 same_at_end += overlap;
2792
3d0387c0
RS
2793 /* Arrange to read only the nonmatching middle part of the file. */
2794 XFASTINT (beg) = same_at_start - BEGV;
2795 XFASTINT (end) = st.st_size - (ZV - same_at_end);
9c28748f 2796
251f623e 2797 del_range_1 (same_at_start, same_at_end, 0);
a1d2b64a
RS
2798 /* Insert from the file at the proper position. */
2799 SET_PT (same_at_start);
3d0387c0 2800 }
e54d3b5d 2801#endif /* MSDOS */
3d0387c0 2802
7fded690
JB
2803 total = XINT (end) - XINT (beg);
2804
570d7624
JB
2805 {
2806 register Lisp_Object temp;
2807
2808 /* Make sure point-max won't overflow after this insertion. */
7fded690
JB
2809 XSET (temp, Lisp_Int, total);
2810 if (total != XINT (temp))
570d7624
JB
2811 error ("maximum buffer size exceeded");
2812 }
2813
57d8d468 2814 if (NILP (visit) && total > 0)
570d7624
JB
2815 prepare_to_modify_buffer (point, point);
2816
2817 move_gap (point);
7fded690
JB
2818 if (GAP_SIZE < total)
2819 make_gap (total - GAP_SIZE);
2820
a1d2b64a 2821 if (XINT (beg) != 0 || !NILP (replace))
7fded690
JB
2822 {
2823 if (lseek (fd, XINT (beg), 0) < 0)
2824 report_file_error ("Setting file position", Fcons (filename, Qnil));
2825 }
2826
a1d2b64a
RS
2827 how_much = 0;
2828 while (inserted < total)
570d7624 2829 {
7fded690 2830 int try = min (total - inserted, 64 << 10);
b5148e85
RS
2831 int this;
2832
2833 /* Allow quitting out of the actual I/O. */
2834 immediate_quit = 1;
2835 QUIT;
2836 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2837 immediate_quit = 0;
570d7624
JB
2838
2839 if (this <= 0)
2840 {
2841 how_much = this;
2842 break;
2843 }
2844
2845 GPT += this;
2846 GAP_SIZE -= this;
2847 ZV += this;
2848 Z += this;
2849 inserted += this;
2850 }
2851
4c3c22f3
RS
2852#ifdef MSDOS
2853 /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
2854 /* Determine file type from name and remove LFs from CR-LFs if the file
2855 is deemed to be a text file. */
2856 {
2857 struct gcpro gcpro1;
e762e30a
KH
2858 Lisp_Object code;
2859 code = Qnil;
4c3c22f3 2860 GCPRO1 (filename);
bf162ea8
RS
2861 current_buffer->buffer_file_type
2862 = call1 (Qfind_buffer_file_type, filename);
4c3c22f3 2863 UNGCPRO;
bf162ea8 2864 if (NILP (current_buffer->buffer_file_type))
4c3c22f3 2865 {
a1d2b64a
RS
2866 int reduced_size
2867 = inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
4c3c22f3
RS
2868 ZV -= reduced_size;
2869 Z -= reduced_size;
2870 GPT -= reduced_size;
2871 GAP_SIZE += reduced_size;
2872 inserted -= reduced_size;
2873 }
2874 }
2875#endif
2876
570d7624 2877 if (inserted > 0)
7d8451f1
RS
2878 {
2879 record_insert (point, inserted);
8d4e077b
JA
2880
2881 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2882 offset_intervals (current_buffer, point, inserted);
7d8451f1
RS
2883 MODIFF++;
2884 }
570d7624
JB
2885
2886 close (fd);
2887
a1d2b64a
RS
2888 /* Discard the unwind protect for closing the file. */
2889 specpdl_ptr--;
570d7624
JB
2890
2891 if (how_much < 0)
2892 error ("IO error reading %s: %s",
ce97267f 2893 XSTRING (filename)->data, strerror (errno));
570d7624
JB
2894
2895 notfound:
32f4334d 2896 handled:
570d7624 2897
265a9e55 2898 if (!NILP (visit))
570d7624 2899 {
cfadd376
RS
2900 if (!EQ (current_buffer->undo_list, Qt))
2901 current_buffer->undo_list = Qnil;
570d7624
JB
2902#ifdef APOLLO
2903 stat (XSTRING (filename)->data, &st);
2904#endif
62bcf009 2905
a7e82472
RS
2906 if (NILP (handler))
2907 {
2908 current_buffer->modtime = st.st_mtime;
2909 current_buffer->filename = filename;
2910 }
62bcf009 2911
570d7624
JB
2912 current_buffer->save_modified = MODIFF;
2913 current_buffer->auto_save_modified = MODIFF;
2914 XFASTINT (current_buffer->save_length) = Z - BEG;
2915#ifdef CLASH_DETECTION
32f4334d
RS
2916 if (NILP (handler))
2917 {
2918 if (!NILP (current_buffer->filename))
2919 unlock_file (current_buffer->filename);
2920 unlock_file (filename);
2921 }
570d7624 2922#endif /* CLASH_DETECTION */
570d7624 2923 /* If visiting nonexistent file, return nil. */
32f4334d 2924 if (current_buffer->modtime == -1)
570d7624
JB
2925 report_file_error ("Opening input file", Fcons (filename, Qnil));
2926 }
2927
62bcf009 2928 if (inserted > 0 && NILP (visit) && total > 0)
d2cad97d 2929 signal_after_change (point, 0, inserted);
570d7624 2930
d6a3cc15
RS
2931 if (inserted > 0)
2932 {
2933 p = Vafter_insert_file_functions;
2934 while (!NILP (p))
2935 {
2936 insval = call1 (Fcar (p), make_number (inserted));
2937 if (!NILP (insval))
2938 {
2939 CHECK_NUMBER (insval, 0);
2940 inserted = XFASTINT (insval);
2941 }
2942 QUIT;
2943 p = Fcdr (p);
2944 }
2945 }
2946
a1d2b64a
RS
2947 if (NILP (val))
2948 val = Fcons (filename,
2949 Fcons (make_number (inserted),
2950 Qnil));
2951
2952 RETURN_UNGCPRO (unbind_to (count, val));
570d7624 2953}
7fded690 2954\f
d6a3cc15
RS
2955static Lisp_Object build_annotations ();
2956
6fc6f94b
RS
2957/* If build_annotations switched buffers, switch back to BUF.
2958 Kill the temporary buffer that was selected in the meantime. */
2959
2960static Lisp_Object
2961build_annotations_unwind (buf)
2962 Lisp_Object buf;
2963{
2964 Lisp_Object tembuf;
2965
2966 if (XBUFFER (buf) == current_buffer)
2967 return Qnil;
2968 tembuf = Fcurrent_buffer ();
2969 Fset_buffer (buf);
2970 Fkill_buffer (tembuf);
2971 return Qnil;
2972}
2973
570d7624
JB
2974DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2975 "r\nFWrite region to file: ",
2976 "Write current region into specified file.\n\
2977When called from a program, takes three arguments:\n\
2978START, END and FILENAME. START and END are buffer positions.\n\
2979Optional fourth argument APPEND if non-nil means\n\
2980 append to existing file contents (if any).\n\
2981Optional fifth argument VISIT if t means\n\
2982 set the last-save-file-modtime of buffer to this file's modtime\n\
2983 and mark buffer not modified.\n\
3b7792ed
RS
2984If VISIT is a string, it is a second file name;\n\
2985 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
2986 VISIT is also the file name to lock and unlock for clash detection.\n\
1d386d28
RS
2987If VISIT is neither t nor nil nor a string,\n\
2988 that means do not print the \"Wrote file\" message.\n\
570d7624
JB
2989Kludgy feature: if START is a string, then that string is written\n\
2990to the file, instead of any buffer contents, and END is ignored.")
2991 (start, end, filename, append, visit)
2992 Lisp_Object start, end, filename, append, visit;
2993{
2994 register int desc;
2995 int failure;
2996 int save_errno;
2997 unsigned char *fn;
2998 struct stat st;
c975dd7a 2999 int tem;
570d7624 3000 int count = specpdl_ptr - specpdl;
6fc6f94b 3001 int count1;
570d7624
JB
3002#ifdef VMS
3003 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
3004#endif /* VMS */
3eac9910 3005 Lisp_Object handler;
4ad827c5 3006 Lisp_Object visit_file;
d6a3cc15
RS
3007 Lisp_Object annotations;
3008 int visiting, quietly;
3b7792ed 3009 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
6fc6f94b 3010 struct buffer *given_buffer;
4c3c22f3
RS
3011#ifdef MSDOS
3012 int buffer_file_type
3013 = NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
3014#endif
570d7624 3015
561cb8e1 3016 if (!NILP (start) && !STRINGP (start))
570d7624
JB
3017 validate_region (&start, &end);
3018
1a04498e 3019 GCPRO2 (filename, visit);
570d7624 3020 filename = Fexpand_file_name (filename, Qnil);
561cb8e1 3021 if (STRINGP (visit))
e5176bae 3022 visit_file = Fexpand_file_name (visit, Qnil);
4ad827c5
RS
3023 else
3024 visit_file = filename;
1a04498e 3025 UNGCPRO;
4ad827c5 3026
561cb8e1 3027 visiting = (EQ (visit, Qt) || STRINGP (visit));
d6a3cc15
RS
3028 quietly = !NILP (visit);
3029
3030 annotations = Qnil;
3031
3032 GCPRO4 (start, filename, annotations, visit_file);
570d7624 3033
32f4334d
RS
3034 /* If the file name has special constructs in it,
3035 call the corresponding file handler. */
49307295 3036 handler = Ffind_file_name_handler (filename, Qwrite_region);
b56ad927
RS
3037 /* If FILENAME has no handler, see if VISIT has one. */
3038 if (NILP (handler) && XTYPE (visit) == Lisp_String)
49307295 3039 handler = Ffind_file_name_handler (visit, Qwrite_region);
3eac9910 3040
32f4334d
RS
3041 if (!NILP (handler))
3042 {
32f4334d 3043 Lisp_Object val;
51cf6d37
RS
3044 val = call6 (handler, Qwrite_region, start, end,
3045 filename, append, visit);
32f4334d 3046
d6a3cc15 3047 if (visiting)
32f4334d 3048 {
32f4334d
RS
3049 current_buffer->save_modified = MODIFF;
3050 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 3051 current_buffer->filename = visit_file;
32f4334d 3052 }
09121adc 3053 UNGCPRO;
32f4334d
RS
3054 return val;
3055 }
3056
561cb8e1
RS
3057 /* Special kludge to simplify auto-saving. */
3058 if (NILP (start))
3059 {
3060 XFASTINT (start) = BEG;
3061 XFASTINT (end) = Z;
3062 }
3063
6fc6f94b
RS
3064 record_unwind_protect (build_annotations_unwind, Fcurrent_buffer ());
3065 count1 = specpdl_ptr - specpdl;
3066
3067 given_buffer = current_buffer;
d6a3cc15 3068 annotations = build_annotations (start, end);
6fc6f94b
RS
3069 if (current_buffer != given_buffer)
3070 {
3071 start = BEGV;
3072 end = ZV;
3073 }
d6a3cc15 3074
570d7624
JB
3075#ifdef CLASH_DETECTION
3076 if (!auto_saving)
3b7792ed 3077 lock_file (visit_file);
570d7624
JB
3078#endif /* CLASH_DETECTION */
3079
09121adc 3080 fn = XSTRING (filename)->data;
570d7624 3081 desc = -1;
265a9e55 3082 if (!NILP (append))
4c3c22f3
RS
3083#ifdef MSDOS
3084 desc = open (fn, O_WRONLY | buffer_file_type);
3085#else
570d7624 3086 desc = open (fn, O_WRONLY);
4c3c22f3 3087#endif
570d7624
JB
3088
3089 if (desc < 0)
3090#ifdef VMS
3091 if (auto_saving) /* Overwrite any previous version of autosave file */
3092 {
3093 vms_truncate (fn); /* if fn exists, truncate to zero length */
3094 desc = open (fn, O_RDWR);
3095 if (desc < 0)
561cb8e1 3096 desc = creat_copy_attrs (STRINGP (current_buffer->filename)
b72dea2a
JB
3097 ? XSTRING (current_buffer->filename)->data : 0,
3098 fn);
570d7624
JB
3099 }
3100 else /* Write to temporary name and rename if no errors */
3101 {
3102 Lisp_Object temp_name;
3103 temp_name = Ffile_name_directory (filename);
3104
265a9e55 3105 if (!NILP (temp_name))
570d7624
JB
3106 {
3107 temp_name = Fmake_temp_name (concat2 (temp_name,
3108 build_string ("$$SAVE$$")));
3109 fname = XSTRING (filename)->data;
3110 fn = XSTRING (temp_name)->data;
3111 desc = creat_copy_attrs (fname, fn);
3112 if (desc < 0)
3113 {
3114 /* If we can't open the temporary file, try creating a new
3115 version of the original file. VMS "creat" creates a
3116 new version rather than truncating an existing file. */
3117 fn = fname;
3118 fname = 0;
3119 desc = creat (fn, 0666);
3120#if 0 /* This can clobber an existing file and fail to replace it,
3121 if the user runs out of space. */
3122 if (desc < 0)
3123 {
3124 /* We can't make a new version;
3125 try to truncate and rewrite existing version if any. */
3126 vms_truncate (fn);
3127 desc = open (fn, O_RDWR);
3128 }
3129#endif
3130 }
3131 }
3132 else
3133 desc = creat (fn, 0666);
3134 }
3135#else /* not VMS */
4c3c22f3
RS
3136#ifdef MSDOS
3137 desc = open (fn,
3138 O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type,
3139 S_IREAD | S_IWRITE);
3140#else /* not MSDOS */
570d7624 3141 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
4c3c22f3 3142#endif /* not MSDOS */
570d7624
JB
3143#endif /* not VMS */
3144
09121adc
RS
3145 UNGCPRO;
3146
570d7624
JB
3147 if (desc < 0)
3148 {
3149#ifdef CLASH_DETECTION
3150 save_errno = errno;
3b7792ed 3151 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
3152 errno = save_errno;
3153#endif /* CLASH_DETECTION */
3154 report_file_error ("Opening output file", Fcons (filename, Qnil));
3155 }
3156
3157 record_unwind_protect (close_file_unwind, make_number (desc));
3158
265a9e55 3159 if (!NILP (append))
570d7624
JB
3160 if (lseek (desc, 0, 2) < 0)
3161 {
3162#ifdef CLASH_DETECTION
3b7792ed 3163 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
3164#endif /* CLASH_DETECTION */
3165 report_file_error ("Lseek error", Fcons (filename, Qnil));
3166 }
3167
3168#ifdef VMS
3169/*
3170 * Kludge Warning: The VMS C RTL likes to insert carriage returns
3171 * if we do writes that don't end with a carriage return. Furthermore
3172 * it cannot handle writes of more then 16K. The modified
3173 * version of "sys_write" in SYSDEP.C (see comment there) copes with
3174 * this EXCEPT for the last record (iff it doesn't end with a carriage
3175 * return). This implies that if your buffer doesn't end with a carriage
3176 * return, you get one free... tough. However it also means that if
3177 * we make two calls to sys_write (a la the following code) you can
3178 * get one at the gap as well. The easiest way to fix this (honest)
3179 * is to move the gap to the next newline (or the end of the buffer).
3180 * Thus this change.
3181 *
3182 * Yech!
3183 */
3184 if (GPT > BEG && GPT_ADDR[-1] != '\n')
3185 move_gap (find_next_newline (GPT, 1));
3186#endif
3187
3188 failure = 0;
3189 immediate_quit = 1;
3190
561cb8e1 3191 if (STRINGP (start))
570d7624 3192 {
d6a3cc15
RS
3193 failure = 0 > a_write (desc, XSTRING (start)->data,
3194 XSTRING (start)->size, 0, &annotations);
570d7624
JB
3195 save_errno = errno;
3196 }
3197 else if (XINT (start) != XINT (end))
3198 {
c975dd7a 3199 int nwritten = 0;
570d7624
JB
3200 if (XINT (start) < GPT)
3201 {
3202 register int end1 = XINT (end);
3203 tem = XINT (start);
d6a3cc15 3204 failure = 0 > a_write (desc, &FETCH_CHAR (tem),
c975dd7a
RS
3205 min (GPT, end1) - tem, tem, &annotations);
3206 nwritten += min (GPT, end1) - tem;
570d7624
JB
3207 save_errno = errno;
3208 }
3209
3210 if (XINT (end) > GPT && !failure)
3211 {
3212 tem = XINT (start);
3213 tem = max (tem, GPT);
d6a3cc15 3214 failure = 0 > a_write (desc, &FETCH_CHAR (tem), XINT (end) - tem,
c975dd7a
RS
3215 tem, &annotations);
3216 nwritten += XINT (end) - tem;
d6a3cc15
RS
3217 save_errno = errno;
3218 }
c975dd7a
RS
3219
3220 if (nwritten == 0)
d6a3cc15
RS
3221 {
3222 /* If file was empty, still need to write the annotations */
c975dd7a 3223 failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
570d7624
JB
3224 save_errno = errno;
3225 }
3226 }
3227
3228 immediate_quit = 0;
3229
6e23c83e 3230#ifdef HAVE_FSYNC
570d7624
JB
3231 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
3232 Disk full in NFS may be reported here. */
1daffa1c
RS
3233 /* mib says that closing the file will try to write as fast as NFS can do
3234 it, and that means the fsync here is not crucial for autosave files. */
3235 if (!auto_saving && fsync (desc) < 0)
570d7624 3236 failure = 1, save_errno = errno;
570d7624
JB
3237#endif
3238
3239 /* Spurious "file has changed on disk" warnings have been
3240 observed on Suns as well.
3241 It seems that `close' can change the modtime, under nfs.
3242
3243 (This has supposedly been fixed in Sunos 4,
3244 but who knows about all the other machines with NFS?) */
3245#if 0
3246
3247 /* On VMS and APOLLO, must do the stat after the close
3248 since closing changes the modtime. */
3249#ifndef VMS
3250#ifndef APOLLO
3251 /* Recall that #if defined does not work on VMS. */
3252#define FOO
3253 fstat (desc, &st);
3254#endif
3255#endif
3256#endif
3257
3258 /* NFS can report a write failure now. */
3259 if (close (desc) < 0)
3260 failure = 1, save_errno = errno;
3261
3262#ifdef VMS
3263 /* If we wrote to a temporary name and had no errors, rename to real name. */
3264 if (fname)
3265 {
3266 if (!failure)
3267 failure = (rename (fn, fname) != 0), save_errno = errno;
3268 fn = fname;
3269 }
3270#endif /* VMS */
3271
3272#ifndef FOO
3273 stat (fn, &st);
3274#endif
6fc6f94b
RS
3275 /* Discard the unwind protect for close_file_unwind. */
3276 specpdl_ptr = specpdl + count1;
3277 /* Restore the original current buffer. */
98295b48 3278 visit_file = unbind_to (count, visit_file);
570d7624
JB
3279
3280#ifdef CLASH_DETECTION
3281 if (!auto_saving)
3b7792ed 3282 unlock_file (visit_file);
570d7624
JB
3283#endif /* CLASH_DETECTION */
3284
3285 /* Do this before reporting IO error
3286 to avoid a "file has changed on disk" warning on
3287 next attempt to save. */
d6a3cc15 3288 if (visiting)
570d7624
JB
3289 current_buffer->modtime = st.st_mtime;
3290
3291 if (failure)
ce97267f 3292 error ("IO error writing %s: %s", fn, strerror (save_errno));
570d7624 3293
d6a3cc15 3294 if (visiting)
570d7624
JB
3295 {
3296 current_buffer->save_modified = MODIFF;
3297 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 3298 current_buffer->filename = visit_file;
f4226e89 3299 update_mode_lines++;
570d7624 3300 }
d6a3cc15 3301 else if (quietly)
570d7624
JB
3302 return Qnil;
3303
3304 if (!auto_saving)
3b7792ed 3305 message ("Wrote %s", XSTRING (visit_file)->data);
570d7624
JB
3306
3307 return Qnil;
3308}
3309
d6a3cc15
RS
3310Lisp_Object merge ();
3311
3312DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
2ba0ccff 3313 "Return t if (car A) is numerically less than (car B).")
d6a3cc15
RS
3314 (a, b)
3315 Lisp_Object a, b;
3316{
3317 return Flss (Fcar (a), Fcar (b));
3318}
3319
3320/* Build the complete list of annotations appropriate for writing out
3321 the text between START and END, by calling all the functions in
6fc6f94b
RS
3322 write-region-annotate-functions and merging the lists they return.
3323 If one of these functions switches to a different buffer, we assume
3324 that buffer contains altered text. Therefore, the caller must
3325 make sure to restore the current buffer in all cases,
3326 as save-excursion would do. */
d6a3cc15
RS
3327
3328static Lisp_Object
3329build_annotations (start, end)
3330 Lisp_Object start, end;
3331{
3332 Lisp_Object annotations;
3333 Lisp_Object p, res;
3334 struct gcpro gcpro1, gcpro2;
3335
3336 annotations = Qnil;
3337 p = Vwrite_region_annotate_functions;
3338 GCPRO2 (annotations, p);
3339 while (!NILP (p))
3340 {
6fc6f94b
RS
3341 struct buffer *given_buffer = current_buffer;
3342 Vwrite_region_annotations_so_far = annotations;
d6a3cc15 3343 res = call2 (Fcar (p), start, end);
6fc6f94b
RS
3344 /* If the function makes a different buffer current,
3345 assume that means this buffer contains altered text to be output.
3346 Reset START and END from the buffer bounds
3347 and discard all previous annotations because they should have
3348 been dealt with by this function. */
3349 if (current_buffer != given_buffer)
3350 {
6fc6f94b
RS
3351 start = BEGV;
3352 end = ZV;
3353 annotations = Qnil;
3354 }
d6a3cc15
RS
3355 Flength (res); /* Check basic validity of return value */
3356 annotations = merge (annotations, res, Qcar_less_than_car);
3357 p = Fcdr (p);
3358 }
3359 UNGCPRO;
3360 return annotations;
3361}
3362
3363/* Write to descriptor DESC the LEN characters starting at ADDR,
3364 assuming they start at position POS in the buffer.
3365 Intersperse with them the annotations from *ANNOT
3366 (those which fall within the range of positions POS to POS + LEN),
3367 each at its appropriate position.
3368
3369 Modify *ANNOT by discarding elements as we output them.
3370 The return value is negative in case of system call failure. */
3371
3372int
3373a_write (desc, addr, len, pos, annot)
3374 int desc;
3375 register char *addr;
3376 register int len;
3377 int pos;
3378 Lisp_Object *annot;
3379{
3380 Lisp_Object tem;
3381 int nextpos;
3382 int lastpos = pos + len;
3383
eb15aa18 3384 while (NILP (*annot) || CONSP (*annot))
d6a3cc15
RS
3385 {
3386 tem = Fcar_safe (Fcar (*annot));
3387 if (INTEGERP (tem) && XINT (tem) >= pos && XFASTINT (tem) <= lastpos)
3388 nextpos = XFASTINT (tem);
3389 else
3390 return e_write (desc, addr, lastpos - pos);
3391 if (nextpos > pos)
3392 {
3393 if (0 > e_write (desc, addr, nextpos - pos))
3394 return -1;
3395 addr += nextpos - pos;
3396 pos = nextpos;
3397 }
3398 tem = Fcdr (Fcar (*annot));
3399 if (STRINGP (tem))
3400 {
3401 if (0 > e_write (desc, XSTRING (tem)->data, XSTRING (tem)->size))
3402 return -1;
3403 }
3404 *annot = Fcdr (*annot);
3405 }
3406}
3407
570d7624
JB
3408int
3409e_write (desc, addr, len)
3410 int desc;
3411 register char *addr;
3412 register int len;
3413{
3414 char buf[16 * 1024];
3415 register char *p, *end;
3416
3417 if (!EQ (current_buffer->selective_display, Qt))
3418 return write (desc, addr, len) - len;
3419 else
3420 {
3421 p = buf;
3422 end = p + sizeof buf;
3423 while (len--)
3424 {
3425 if (p == end)
3426 {
3427 if (write (desc, buf, sizeof buf) != sizeof buf)
3428 return -1;
3429 p = buf;
3430 }
3431 *p = *addr++;
3432 if (*p++ == '\015')
3433 p[-1] = '\n';
3434 }
3435 if (p != buf)
3436 if (write (desc, buf, p - buf) != p - buf)
3437 return -1;
3438 }
3439 return 0;
3440}
3441
3442DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
3443 Sverify_visited_file_modtime, 1, 1, 0,
3444 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
3445This means that the file has not been changed since it was visited or saved.")
3446 (buf)
3447 Lisp_Object buf;
3448{
3449 struct buffer *b;
3450 struct stat st;
32f4334d 3451 Lisp_Object handler;
570d7624
JB
3452
3453 CHECK_BUFFER (buf, 0);
3454 b = XBUFFER (buf);
3455
3456 if (XTYPE (b->filename) != Lisp_String) return Qt;
3457 if (b->modtime == 0) return Qt;
3458
32f4334d
RS
3459 /* If the file name has special constructs in it,
3460 call the corresponding file handler. */
49307295
KH
3461 handler = Ffind_file_name_handler (b->filename,
3462 Qverify_visited_file_modtime);
32f4334d 3463 if (!NILP (handler))
09121adc 3464 return call2 (handler, Qverify_visited_file_modtime, buf);
32f4334d 3465
570d7624
JB
3466 if (stat (XSTRING (b->filename)->data, &st) < 0)
3467 {
3468 /* If the file doesn't exist now and didn't exist before,
3469 we say that it isn't modified, provided the error is a tame one. */
3470 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
3471 st.st_mtime = -1;
3472 else
3473 st.st_mtime = 0;
3474 }
3475 if (st.st_mtime == b->modtime
3476 /* If both are positive, accept them if they are off by one second. */
3477 || (st.st_mtime > 0 && b->modtime > 0
3478 && (st.st_mtime == b->modtime + 1
3479 || st.st_mtime == b->modtime - 1)))
3480 return Qt;
3481 return Qnil;
3482}
3483
3484DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
3485 Sclear_visited_file_modtime, 0, 0, 0,
3486 "Clear out records of last mod time of visited file.\n\
3487Next attempt to save will certainly not complain of a discrepancy.")
3488 ()
3489{
3490 current_buffer->modtime = 0;
3491 return Qnil;
3492}
3493
f5d5eccf
RS
3494DEFUN ("visited-file-modtime", Fvisited_file_modtime,
3495 Svisited_file_modtime, 0, 0, 0,
3496 "Return the current buffer's recorded visited file modification time.\n\
3497The value is a list of the form (HIGH . LOW), like the time values\n\
3498that `file-attributes' returns.")
3499 ()
3500{
3501 return long_to_cons (current_buffer->modtime);
3502}
3503
570d7624 3504DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
f5d5eccf 3505 Sset_visited_file_modtime, 0, 1, 0,
570d7624
JB
3506 "Update buffer's recorded modification time from the visited file's time.\n\
3507Useful if the buffer was not read from the file normally\n\
f5d5eccf
RS
3508or if the file itself has been changed for some known benign reason.\n\
3509An argument specifies the modification time value to use\n\
3510\(instead of that of the visited file), in the form of a list\n\
3511\(HIGH . LOW) or (HIGH LOW).")
3512 (time_list)
3513 Lisp_Object time_list;
570d7624 3514{
f5d5eccf
RS
3515 if (!NILP (time_list))
3516 current_buffer->modtime = cons_to_long (time_list);
3517 else
3518 {
3519 register Lisp_Object filename;
3520 struct stat st;
3521 Lisp_Object handler;
570d7624 3522
f5d5eccf 3523 filename = Fexpand_file_name (current_buffer->filename, Qnil);
32f4334d 3524
f5d5eccf
RS
3525 /* If the file name has special constructs in it,
3526 call the corresponding file handler. */
49307295 3527 handler = Ffind_file_name_handler (filename, Qset_visited_file_modtime);
f5d5eccf 3528 if (!NILP (handler))
caf3c431 3529 /* The handler can find the file name the same way we did. */
76c881b0 3530 return call2 (handler, Qset_visited_file_modtime, Qnil);
f5d5eccf
RS
3531 else if (stat (XSTRING (filename)->data, &st) >= 0)
3532 current_buffer->modtime = st.st_mtime;
3533 }
570d7624
JB
3534
3535 return Qnil;
3536}
3537\f
3538Lisp_Object
3539auto_save_error ()
3540{
570d7624 3541 ring_bell ();
1a04498e 3542 message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3543 Fsleep_for (make_number (1), Qnil);
1a04498e 3544 message ("Autosaving...error!for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3545 Fsleep_for (make_number (1), Qnil);
1a04498e 3546 message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3547 Fsleep_for (make_number (1), Qnil);
570d7624
JB
3548 return Qnil;
3549}
3550
3551Lisp_Object
3552auto_save_1 ()
3553{
3554 unsigned char *fn;
3555 struct stat st;
3556
3557 /* Get visited file's mode to become the auto save file's mode. */
3558 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
3559 /* But make sure we can overwrite it later! */
3560 auto_save_mode_bits = st.st_mode | 0600;
3561 else
3562 auto_save_mode_bits = 0666;
3563
3564 return
3565 Fwrite_region (Qnil, Qnil,
3566 current_buffer->auto_save_file_name,
3567 Qnil, Qlambda);
3568}
3569
e54d3b5d 3570static Lisp_Object
15fa1468
RS
3571do_auto_save_unwind (desc) /* used as unwind-protect function */
3572 Lisp_Object desc;
e54d3b5d 3573{
15fa1468 3574 close (XINT (desc));
e54d3b5d
RS
3575 return Qnil;
3576}
3577
570d7624
JB
3578DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
3579 "Auto-save all buffers that need it.\n\
3580This is all buffers that have auto-saving enabled\n\
3581and are changed since last auto-saved.\n\
3582Auto-saving writes the buffer into a file\n\
3583so that your editing is not lost if the system crashes.\n\
012d4cdc
RS
3584This file is not the file you visited; that changes only when you save.\n\
3585Normally we run the normal hook `auto-save-hook' before saving.\n\n\
570d7624 3586Non-nil first argument means do not print any message if successful.\n\
4746118a 3587Non-nil second argument means save only current buffer.")
17857782
JB
3588 (no_message, current_only)
3589 Lisp_Object no_message, current_only;
570d7624
JB
3590{
3591 struct buffer *old = current_buffer, *b;
3592 Lisp_Object tail, buf;
3593 int auto_saved = 0;
3594 char *omessage = echo_area_glyphs;
f05b275b 3595 int omessage_length = echo_area_glyphs_length;
f14b1c68
JB
3596 extern int minibuf_level;
3597 int do_handled_files;
ff4c9993 3598 Lisp_Object oquit;
e54d3b5d 3599 int listdesc;
e54d3b5d
RS
3600 int count = specpdl_ptr - specpdl;
3601 int *ptr;
ff4c9993
RS
3602
3603 /* Ordinarily don't quit within this function,
3604 but don't make it impossible to quit (in case we get hung in I/O). */
3605 oquit = Vquit_flag;
3606 Vquit_flag = Qnil;
570d7624
JB
3607
3608 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
3609 point to non-strings reached from Vbuffer_alist. */
3610
3611 auto_saving = 1;
3612 if (minibuf_level)
17857782 3613 no_message = Qt;
570d7624 3614
265a9e55 3615 if (!NILP (Vrun_hooks))
570d7624
JB
3616 call1 (Vrun_hooks, intern ("auto-save-hook"));
3617
e54d3b5d
RS
3618 if (STRINGP (Vauto_save_list_file_name))
3619 {
3620#ifdef MSDOS
3621 listdesc = open (XSTRING (Vauto_save_list_file_name)->data,
3622 O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
3623 S_IREAD | S_IWRITE);
3624#else /* not MSDOS */
3625 listdesc = creat (XSTRING (Vauto_save_list_file_name)->data, 0666);
3626#endif /* not MSDOS */
3627 }
3628 else
3629 listdesc = -1;
e54d3b5d 3630
15fa1468
RS
3631 /* Arrange to close that file whether or not we get an error. */
3632 if (listdesc >= 0)
3633 record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
e54d3b5d 3634
f14b1c68
JB
3635 /* First, save all files which don't have handlers. If Emacs is
3636 crashing, the handlers may tweak what is causing Emacs to crash
3637 in the first place, and it would be a shame if Emacs failed to
3638 autosave perfectly ordinary files because it couldn't handle some
3639 ange-ftp'd file. */
3640 for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
3641 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
3642 tail = XCONS (tail)->cdr)
3643 {
3644 buf = XCONS (XCONS (tail)->car)->cdr;
3645 b = XBUFFER (buf);
e54d3b5d
RS
3646
3647 /* Record all the buffers that have auto save mode
3648 in the special file that lists them. */
3649 if (XTYPE (b->auto_save_file_name) == Lisp_String
3650 && listdesc >= 0 && do_handled_files == 0)
3651 {
3652 write (listdesc, XSTRING (b->auto_save_file_name)->data,
3653 XSTRING (b->auto_save_file_name)->size);
3654 write (listdesc, "\n", 1);
3655 }
17857782 3656
f14b1c68
JB
3657 if (!NILP (current_only)
3658 && b != current_buffer)
3659 continue;
e54d3b5d 3660
f14b1c68
JB
3661 /* Check for auto save enabled
3662 and file changed since last auto save
3663 and file changed since last real save. */
3664 if (XTYPE (b->auto_save_file_name) == Lisp_String
3665 && b->save_modified < BUF_MODIFF (b)
3666 && b->auto_save_modified < BUF_MODIFF (b)
82c2d839
RS
3667 /* -1 means we've turned off autosaving for a while--see below. */
3668 && XINT (b->save_length) >= 0
f14b1c68 3669 && (do_handled_files
49307295
KH
3670 || NILP (Ffind_file_name_handler (b->auto_save_file_name,
3671 Qwrite_region))))
f14b1c68 3672 {
b60247d9
RS
3673 EMACS_TIME before_time, after_time;
3674
3675 EMACS_GET_TIME (before_time);
3676
3677 /* If we had a failure, don't try again for 20 minutes. */
3678 if (b->auto_save_failure_time >= 0
3679 && EMACS_SECS (before_time) - b->auto_save_failure_time < 1200)
3680 continue;
3681
f14b1c68
JB
3682 if ((XFASTINT (b->save_length) * 10
3683 > (BUF_Z (b) - BUF_BEG (b)) * 13)
3684 /* A short file is likely to change a large fraction;
3685 spare the user annoying messages. */
3686 && XFASTINT (b->save_length) > 5000
3687 /* These messages are frequent and annoying for `*mail*'. */
3688 && !EQ (b->filename, Qnil)
3689 && NILP (no_message))
3690 {
3691 /* It has shrunk too much; turn off auto-saving here. */
3692 message ("Buffer %s has shrunk a lot; auto save turned off there",
3693 XSTRING (b->name)->data);
82c2d839
RS
3694 /* Turn off auto-saving until there's a real save,
3695 and prevent any more warnings. */
3696 XSET (b->save_length, Lisp_Int, -1);
f14b1c68
JB
3697 Fsleep_for (make_number (1), Qnil);
3698 continue;
3699 }
3700 set_buffer_internal (b);
3701 if (!auto_saved && NILP (no_message))
3702 message1 ("Auto-saving...");
3703 internal_condition_case (auto_save_1, Qt, auto_save_error);
3704 auto_saved++;
3705 b->auto_save_modified = BUF_MODIFF (b);
3706 XFASTINT (current_buffer->save_length) = Z - BEG;
3707 set_buffer_internal (old);
b60247d9
RS
3708
3709 EMACS_GET_TIME (after_time);
3710
3711 /* If auto-save took more than 60 seconds,
3712 assume it was an NFS failure that got a timeout. */
3713 if (EMACS_SECS (after_time) - EMACS_SECS (before_time) > 60)
3714 b->auto_save_failure_time = EMACS_SECS (after_time);
f14b1c68
JB
3715 }
3716 }
570d7624 3717
b67f2ca5
RS
3718 /* Prevent another auto save till enough input events come in. */
3719 record_auto_save ();
570d7624 3720
17857782 3721 if (auto_saved && NILP (no_message))
f05b275b
KH
3722 {
3723 if (omessage)
3724 message2 (omessage, omessage_length);
3725 else
3726 message1 ("Auto-saving...done");
3727 }
570d7624 3728
ff4c9993
RS
3729 Vquit_flag = oquit;
3730
570d7624 3731 auto_saving = 0;
e54d3b5d 3732 unbind_to (count, Qnil);
570d7624
JB
3733 return Qnil;
3734}
3735
3736DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
3737 Sset_buffer_auto_saved, 0, 0, 0,
3738 "Mark current buffer as auto-saved with its current text.\n\
3739No auto-save file will be written until the buffer changes again.")
3740 ()
3741{
3742 current_buffer->auto_save_modified = MODIFF;
3743 XFASTINT (current_buffer->save_length) = Z - BEG;
b60247d9
RS
3744 current_buffer->auto_save_failure_time = -1;
3745 return Qnil;
3746}
3747
3748DEFUN ("clear-buffer-auto-save-failure", Fclear_buffer_auto_save_failure,
3749 Sclear_buffer_auto_save_failure, 0, 0, 0,
3750 "Clear any record of a recent auto-save failure in the current buffer.")
3751 ()
3752{
3753 current_buffer->auto_save_failure_time = -1;
570d7624
JB
3754 return Qnil;
3755}
3756
3757DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
3758 0, 0, 0,
3759 "Return t if buffer has been auto-saved since last read in or saved.")
3760 ()
3761{
3762 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
3763}
3764\f
3765/* Reading and completing file names */
3766extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
3767
6e710ae5
RS
3768/* In the string VAL, change each $ to $$ and return the result. */
3769
3770static Lisp_Object
3771double_dollars (val)
3772 Lisp_Object val;
3773{
3774 register unsigned char *old, *new;
3775 register int n;
3776 int osize, count;
3777
3778 osize = XSTRING (val)->size;
3779 /* Quote "$" as "$$" to get it past substitute-in-file-name */
3780 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
3781 if (*old++ == '$') count++;
3782 if (count > 0)
3783 {
3784 old = XSTRING (val)->data;
3785 val = Fmake_string (make_number (osize + count), make_number (0));
3786 new = XSTRING (val)->data;
3787 for (n = osize; n > 0; n--)
3788 if (*old != '$')
3789 *new++ = *old++;
3790 else
3791 {
3792 *new++ = '$';
3793 *new++ = '$';
3794 old++;
3795 }
3796 }
3797 return val;
3798}
3799
570d7624
JB
3800DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
3801 3, 3, 0,
3802 "Internal subroutine for read-file-name. Do not call this.")
3803 (string, dir, action)
3804 Lisp_Object string, dir, action;
3805 /* action is nil for complete, t for return list of completions,
3806 lambda for verify final value */
3807{
3808 Lisp_Object name, specdir, realdir, val, orig_string;
09121adc
RS
3809 int changed;
3810 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3811
3812 realdir = dir;
3813 name = string;
3814 orig_string = Qnil;
3815 specdir = Qnil;
3816 changed = 0;
3817 /* No need to protect ACTION--we only compare it with t and nil. */
3818 GCPRO4 (string, realdir, name, specdir);
570d7624
JB
3819
3820 if (XSTRING (string)->size == 0)
3821 {
570d7624 3822 if (EQ (action, Qlambda))
09121adc
RS
3823 {
3824 UNGCPRO;
3825 return Qnil;
3826 }
570d7624
JB
3827 }
3828 else
3829 {
3830 orig_string = string;
3831 string = Fsubstitute_in_file_name (string);
09121adc 3832 changed = NILP (Fstring_equal (string, orig_string));
570d7624 3833 name = Ffile_name_nondirectory (string);
09121adc
RS
3834 val = Ffile_name_directory (string);
3835 if (! NILP (val))
3836 realdir = Fexpand_file_name (val, realdir);
570d7624
JB
3837 }
3838
265a9e55 3839 if (NILP (action))
570d7624
JB
3840 {
3841 specdir = Ffile_name_directory (string);
3842 val = Ffile_name_completion (name, realdir);
09121adc 3843 UNGCPRO;
570d7624
JB
3844 if (XTYPE (val) != Lisp_String)
3845 {
09121adc 3846 if (changed)
dbd04e01 3847 return double_dollars (string);
09121adc 3848 return val;
570d7624
JB
3849 }
3850
265a9e55 3851 if (!NILP (specdir))
570d7624
JB
3852 val = concat2 (specdir, val);
3853#ifndef VMS
6e710ae5
RS
3854 return double_dollars (val);
3855#else /* not VMS */
09121adc 3856 return val;
6e710ae5 3857#endif /* not VMS */
570d7624 3858 }
09121adc 3859 UNGCPRO;
570d7624
JB
3860
3861 if (EQ (action, Qt))
3862 return Ffile_name_all_completions (name, realdir);
3863 /* Only other case actually used is ACTION = lambda */
3864#ifdef VMS
3865 /* Supposedly this helps commands such as `cd' that read directory names,
3866 but can someone explain how it helps them? -- RMS */
3867 if (XSTRING (name)->size == 0)
3868 return Qt;
3869#endif /* VMS */
3870 return Ffile_exists_p (string);
3871}
3872
3873DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3874 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3875Value is not expanded---you must call `expand-file-name' yourself.\n\
3876Default name to DEFAULT if user enters a null string.\n\
3877 (If DEFAULT is omitted, the visited file name is used.)\n\
3878Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3879 Non-nil and non-t means also require confirmation after completion.\n\
3880Fifth arg INITIAL specifies text to start with.\n\
3881DIR defaults to current buffer's directory default.")
3882 (prompt, dir, defalt, mustmatch, initial)
3883 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3884{
85b5fe07 3885 Lisp_Object val, insdef, insdef1, tem;
570d7624
JB
3886 struct gcpro gcpro1, gcpro2;
3887 register char *homedir;
3888 int count;
3889
265a9e55 3890 if (NILP (dir))
570d7624 3891 dir = current_buffer->directory;
265a9e55 3892 if (NILP (defalt))
570d7624
JB
3893 defalt = current_buffer->filename;
3894
3895 /* If dir starts with user's homedir, change that to ~. */
3896 homedir = (char *) egetenv ("HOME");
3897 if (homedir != 0
3898 && XTYPE (dir) == Lisp_String
3899 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3900 && XSTRING (dir)->data[strlen (homedir)] == '/')
3901 {
3902 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3903 XSTRING (dir)->size - strlen (homedir) + 1);
3904 XSTRING (dir)->data[0] = '~';
3905 }
3906
3907 if (insert_default_directory)
3908 {
3909 insdef = dir;
265a9e55 3910 if (!NILP (initial))
570d7624 3911 {
15c65264 3912 Lisp_Object args[2], pos;
570d7624
JB
3913
3914 args[0] = insdef;
3915 args[1] = initial;
3916 insdef = Fconcat (2, args);
351bd676 3917 pos = make_number (XSTRING (double_dollars (dir))->size);
6e710ae5 3918 insdef1 = Fcons (double_dollars (insdef), pos);
570d7624 3919 }
6e710ae5
RS
3920 else
3921 insdef1 = double_dollars (insdef);
570d7624 3922 }
351bd676
KH
3923 else if (!NILP (initial))
3924 {
3925 insdef = initial;
3926 insdef1 = Fcons (double_dollars (insdef), 0);
3927 }
570d7624 3928 else
85b5fe07 3929 insdef = Qnil, insdef1 = Qnil;
570d7624
JB
3930
3931#ifdef VMS
3932 count = specpdl_ptr - specpdl;
3933 specbind (intern ("completion-ignore-case"), Qt);
3934#endif
3935
3936 GCPRO2 (insdef, defalt);
3937 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
85b5fe07 3938 dir, mustmatch, insdef1,
15c65264 3939 Qfile_name_history);
570d7624
JB
3940
3941#ifdef VMS
3942 unbind_to (count, Qnil);
3943#endif
3944
3945 UNGCPRO;
265a9e55 3946 if (NILP (val))
570d7624
JB
3947 error ("No file name specified");
3948 tem = Fstring_equal (val, insdef);
265a9e55 3949 if (!NILP (tem) && !NILP (defalt))
570d7624 3950 return defalt;
b320926a 3951 if (XSTRING (val)->size == 0 && NILP (insdef))
d9bc1c99
RS
3952 {
3953 if (!NILP (defalt))
3954 return defalt;
3955 else
3956 error ("No default file name");
3957 }
570d7624
JB
3958 return Fsubstitute_in_file_name (val);
3959}
3960
3961#if 0 /* Old version */
3962DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
0de25302
KH
3963 /* Don't confuse make-docfile by having two doc strings for this function.
3964 make-docfile does not pay attention to #if, for good reason! */
3965 0)
570d7624
JB
3966 (prompt, dir, defalt, mustmatch, initial)
3967 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3968{
3969 Lisp_Object val, insdef, tem;
3970 struct gcpro gcpro1, gcpro2;
3971 register char *homedir;
3972 int count;
3973
265a9e55 3974 if (NILP (dir))
570d7624 3975 dir = current_buffer->directory;
265a9e55 3976 if (NILP (defalt))
570d7624
JB
3977 defalt = current_buffer->filename;
3978
3979 /* If dir starts with user's homedir, change that to ~. */
3980 homedir = (char *) egetenv ("HOME");
3981 if (homedir != 0
3982 && XTYPE (dir) == Lisp_String
3983 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3984 && XSTRING (dir)->data[strlen (homedir)] == '/')
3985 {
3986 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3987 XSTRING (dir)->size - strlen (homedir) + 1);
3988 XSTRING (dir)->data[0] = '~';
3989 }
3990
265a9e55 3991 if (!NILP (initial))
570d7624
JB
3992 insdef = initial;
3993 else if (insert_default_directory)
3994 insdef = dir;
3995 else
3996 insdef = build_string ("");
3997
3998#ifdef VMS
3999 count = specpdl_ptr - specpdl;
4000 specbind (intern ("completion-ignore-case"), Qt);
4001#endif
4002
4003 GCPRO2 (insdef, defalt);
4004 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4005 dir, mustmatch,
15c65264
RS
4006 insert_default_directory ? insdef : Qnil,
4007 Qfile_name_history);
570d7624
JB
4008
4009#ifdef VMS
4010 unbind_to (count, Qnil);
4011#endif
4012
4013 UNGCPRO;
265a9e55 4014 if (NILP (val))
570d7624
JB
4015 error ("No file name specified");
4016 tem = Fstring_equal (val, insdef);
265a9e55 4017 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
4018 return defalt;
4019 return Fsubstitute_in_file_name (val);
4020}
4021#endif /* Old version */
4022\f
4023syms_of_fileio ()
4024{
0bf2eed2
RS
4025 Qexpand_file_name = intern ("expand-file-name");
4026 Qdirectory_file_name = intern ("directory-file-name");
4027 Qfile_name_directory = intern ("file-name-directory");
4028 Qfile_name_nondirectory = intern ("file-name-nondirectory");
642ef245 4029 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
0bf2eed2 4030 Qfile_name_as_directory = intern ("file-name-as-directory");
32f4334d 4031 Qcopy_file = intern ("copy-file");
a6e6e718 4032 Qmake_directory_internal = intern ("make-directory-internal");
32f4334d
RS
4033 Qdelete_directory = intern ("delete-directory");
4034 Qdelete_file = intern ("delete-file");
4035 Qrename_file = intern ("rename-file");
4036 Qadd_name_to_file = intern ("add-name-to-file");
4037 Qmake_symbolic_link = intern ("make-symbolic-link");
4038 Qfile_exists_p = intern ("file-exists-p");
4039 Qfile_executable_p = intern ("file-executable-p");
4040 Qfile_readable_p = intern ("file-readable-p");
4041 Qfile_symlink_p = intern ("file-symlink-p");
4042 Qfile_writable_p = intern ("file-writable-p");
4043 Qfile_directory_p = intern ("file-directory-p");
4044 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
4045 Qfile_modes = intern ("file-modes");
4046 Qset_file_modes = intern ("set-file-modes");
4047 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
4048 Qinsert_file_contents = intern ("insert-file-contents");
4049 Qwrite_region = intern ("write-region");
4050 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3ec46acd 4051 Qset_visited_file_modtime = intern ("set-visited-file-modtime");
32f4334d 4052
642ef245
JB
4053 staticpro (&Qexpand_file_name);
4054 staticpro (&Qdirectory_file_name);
4055 staticpro (&Qfile_name_directory);
4056 staticpro (&Qfile_name_nondirectory);
4057 staticpro (&Qunhandled_file_name_directory);
4058 staticpro (&Qfile_name_as_directory);
15c65264 4059 staticpro (&Qcopy_file);
c34b559d 4060 staticpro (&Qmake_directory_internal);
15c65264
RS
4061 staticpro (&Qdelete_directory);
4062 staticpro (&Qdelete_file);
4063 staticpro (&Qrename_file);
4064 staticpro (&Qadd_name_to_file);
4065 staticpro (&Qmake_symbolic_link);
4066 staticpro (&Qfile_exists_p);
4067 staticpro (&Qfile_executable_p);
4068 staticpro (&Qfile_readable_p);
4069 staticpro (&Qfile_symlink_p);
4070 staticpro (&Qfile_writable_p);
4071 staticpro (&Qfile_directory_p);
4072 staticpro (&Qfile_accessible_directory_p);
4073 staticpro (&Qfile_modes);
4074 staticpro (&Qset_file_modes);
4075 staticpro (&Qfile_newer_than_file_p);
4076 staticpro (&Qinsert_file_contents);
4077 staticpro (&Qwrite_region);
4078 staticpro (&Qverify_visited_file_modtime);
642ef245
JB
4079
4080 Qfile_name_history = intern ("file-name-history");
4081 Fset (Qfile_name_history, Qnil);
15c65264
RS
4082 staticpro (&Qfile_name_history);
4083
570d7624
JB
4084 Qfile_error = intern ("file-error");
4085 staticpro (&Qfile_error);
4086 Qfile_already_exists = intern("file-already-exists");
4087 staticpro (&Qfile_already_exists);
4088
4c3c22f3
RS
4089#ifdef MSDOS
4090 Qfind_buffer_file_type = intern ("find-buffer-file-type");
4091 staticpro (&Qfind_buffer_file_type);
4092#endif
4093
d6a3cc15
RS
4094 Qcar_less_than_car = intern ("car-less-than-car");
4095 staticpro (&Qcar_less_than_car);
4096
570d7624
JB
4097 Fput (Qfile_error, Qerror_conditions,
4098 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
4099 Fput (Qfile_error, Qerror_message,
4100 build_string ("File error"));
4101
4102 Fput (Qfile_already_exists, Qerror_conditions,
4103 Fcons (Qfile_already_exists,
4104 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
4105 Fput (Qfile_already_exists, Qerror_message,
4106 build_string ("File already exists"));
4107
4108 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
4109 "*Non-nil means when reading a filename start with default dir in minibuffer.");
4110 insert_default_directory = 1;
4111
4112 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
4113 "*Non-nil means write new files with record format `stmlf'.\n\
4114nil means use format `var'. This variable is meaningful only on VMS.");
4115 vms_stmlf_recfm = 0;
4116
1d1826db
RS
4117 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
4118 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
4119If a file name matches REGEXP, then all I/O on that file is done by calling\n\
4120HANDLER.\n\
4121\n\
4122The first argument given to HANDLER is the name of the I/O primitive\n\
4123to be handled; the remaining arguments are the arguments that were\n\
4124passed to that primitive. For example, if you do\n\
4125 (file-exists-p FILENAME)\n\
4126and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
642ef245
JB
4127 (funcall HANDLER 'file-exists-p FILENAME)\n\
4128The function `find-file-name-handler' checks this list for a handler\n\
4129for its argument.");
09121adc
RS
4130 Vfile_name_handler_alist = Qnil;
4131
d6a3cc15 4132 DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
246cfea5
RS
4133 "A list of functions to be called at the end of `insert-file-contents'.\n\
4134Each is passed one argument, the number of bytes inserted. It should return\n\
4135the new byte count, and leave point the same. If `insert-file-contents' is\n\
4136intercepted by a handler from `file-name-handler-alist', that handler is\n\
d6a3cc15
RS
4137responsible for calling the after-insert-file-functions if appropriate.");
4138 Vafter_insert_file_functions = Qnil;
4139
4140 DEFVAR_LISP ("write-region-annotate-functions", &Vwrite_region_annotate_functions,
246cfea5
RS
4141 "A list of functions to be called at the start of `write-region'.\n\
4142Each is passed two arguments, START and END as for `write-region'. It should\n\
4143return a list of pairs (POSITION . STRING) of strings to be effectively\n\
4144inserted at the specified positions of the file being written (1 means to\n\
4145insert before the first byte written). The POSITIONs must be sorted into\n\
4146increasing order. If there are several functions in the list, the several\n\
d6a3cc15
RS
4147lists are merged destructively.");
4148 Vwrite_region_annotate_functions = Qnil;
4149
6fc6f94b
RS
4150 DEFVAR_LISP ("write-region-annotations-so-far",
4151 &Vwrite_region_annotations_so_far,
4152 "When an annotation function is called, this holds the previous annotations.\n\
4153These are the annotations made by other annotation functions\n\
4154that were already called. See also `write-region-annotate-functions'.");
4155 Vwrite_region_annotations_so_far = Qnil;
4156
82c2d839 4157 DEFVAR_LISP ("inhibit-file-name-handlers", &Vinhibit_file_name_handlers,
268466ed 4158 "A list of file name handlers that temporarily should not be used.\n\
e3e86241 4159This applies only to the operation `inhibit-file-name-operation'.");
82c2d839
RS
4160 Vinhibit_file_name_handlers = Qnil;
4161
a65970a0
RS
4162 DEFVAR_LISP ("inhibit-file-name-operation", &Vinhibit_file_name_operation,
4163 "The operation for which `inhibit-file-name-handlers' is applicable.");
4164 Vinhibit_file_name_operation = Qnil;
4165
e54d3b5d
RS
4166 DEFVAR_LISP ("auto-save-list-file-name", &Vauto_save_list_file_name,
4167 "File name in which we write a list of all auto save file names.");
4168 Vauto_save_list_file_name = Qnil;
4169
642ef245 4170 defsubr (&Sfind_file_name_handler);
570d7624
JB
4171 defsubr (&Sfile_name_directory);
4172 defsubr (&Sfile_name_nondirectory);
642ef245 4173 defsubr (&Sunhandled_file_name_directory);
570d7624
JB
4174 defsubr (&Sfile_name_as_directory);
4175 defsubr (&Sdirectory_file_name);
4176 defsubr (&Smake_temp_name);
4177 defsubr (&Sexpand_file_name);
4178 defsubr (&Ssubstitute_in_file_name);
4179 defsubr (&Scopy_file);
9bbe01fb 4180 defsubr (&Smake_directory_internal);
aa734e17 4181 defsubr (&Sdelete_directory);
570d7624
JB
4182 defsubr (&Sdelete_file);
4183 defsubr (&Srename_file);
4184 defsubr (&Sadd_name_to_file);
4185#ifdef S_IFLNK
4186 defsubr (&Smake_symbolic_link);
4187#endif /* S_IFLNK */
4188#ifdef VMS
4189 defsubr (&Sdefine_logical_name);
4190#endif /* VMS */
4191#ifdef HPUX_NET
4192 defsubr (&Ssysnetunam);
4193#endif /* HPUX_NET */
4194 defsubr (&Sfile_name_absolute_p);
4195 defsubr (&Sfile_exists_p);
4196 defsubr (&Sfile_executable_p);
4197 defsubr (&Sfile_readable_p);
4198 defsubr (&Sfile_writable_p);
4199 defsubr (&Sfile_symlink_p);
4200 defsubr (&Sfile_directory_p);
b72dea2a 4201 defsubr (&Sfile_accessible_directory_p);
570d7624
JB
4202 defsubr (&Sfile_modes);
4203 defsubr (&Sset_file_modes);
c24e9a53
RS
4204 defsubr (&Sset_default_file_modes);
4205 defsubr (&Sdefault_file_modes);
570d7624
JB
4206 defsubr (&Sfile_newer_than_file_p);
4207 defsubr (&Sinsert_file_contents);
4208 defsubr (&Swrite_region);
d6a3cc15 4209 defsubr (&Scar_less_than_car);
570d7624
JB
4210 defsubr (&Sverify_visited_file_modtime);
4211 defsubr (&Sclear_visited_file_modtime);
f5d5eccf 4212 defsubr (&Svisited_file_modtime);
570d7624
JB
4213 defsubr (&Sset_visited_file_modtime);
4214 defsubr (&Sdo_auto_save);
4215 defsubr (&Sset_buffer_auto_saved);
b60247d9 4216 defsubr (&Sclear_buffer_auto_save_failure);
570d7624
JB
4217 defsubr (&Srecent_auto_save_p);
4218
4219 defsubr (&Sread_file_name_internal);
4220 defsubr (&Sread_file_name);
85ffea93 4221
483a2e10 4222#ifdef unix
85ffea93 4223 defsubr (&Sunix_sync);
483a2e10 4224#endif
570d7624 4225}