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