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