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