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