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