Comment fixes.
[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
a8a7d065
RS
2463#ifdef MSDOS
2464 /* Under MS-DOS, open does not work't right, because it doesn't work for
2465 directories (MS-DOS won't let you open a directory). */
2466 if (access (XSTRING (abspath)->data, 0) == 0)
2467 return Qt;
2468 return Qnil;
2469#else /* not MSDOS */
4018b5ef
RS
2470 desc = open (XSTRING (abspath)->data, O_RDONLY);
2471 if (desc < 0)
2472 return Qnil;
2473 close (desc);
2474 return Qt;
a8a7d065 2475#endif /* not MSDOS */
570d7624
JB
2476}
2477
f793dc6c
RS
2478/* Having this before file-symlink-p mysteriously caused it to be forgotten
2479 on the RT/PC. */
2480DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
2481 "Return t if file FILENAME can be written or created by you.")
2482 (filename)
2483 Lisp_Object filename;
2484{
2485 Lisp_Object abspath, dir;
2486 Lisp_Object handler;
2487 struct stat statbuf;
2488
2489 CHECK_STRING (filename, 0);
2490 abspath = Fexpand_file_name (filename, Qnil);
2491
2492 /* If the file name has special constructs in it,
2493 call the corresponding file handler. */
2494 handler = Ffind_file_name_handler (abspath, Qfile_writable_p);
2495 if (!NILP (handler))
2496 return call2 (handler, Qfile_writable_p, abspath);
2497
2498 if (stat (XSTRING (abspath)->data, &statbuf) >= 0)
2499 return (check_writable (XSTRING (abspath)->data)
2500 ? Qt : Qnil);
2501 dir = Ffile_name_directory (abspath);
2502#ifdef VMS
2503 if (!NILP (dir))
2504 dir = Fdirectory_file_name (dir);
2505#endif /* VMS */
2506#ifdef MSDOS
2507 if (!NILP (dir))
2508 dir = Fdirectory_file_name (dir);
2509#endif /* MSDOS */
2510 return (check_writable (!NILP (dir) ? (char *) XSTRING (dir)->data : "")
2511 ? Qt : Qnil);
2512}
2513\f
570d7624 2514DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
89de89c7
RS
2515 "Return non-nil if file FILENAME is the name of a symbolic link.\n\
2516The value is the name of the file to which it is linked.\n\
2517Otherwise returns nil.")
570d7624
JB
2518 (filename)
2519 Lisp_Object filename;
2520{
2521#ifdef S_IFLNK
2522 char *buf;
2523 int bufsize;
2524 int valsize;
2525 Lisp_Object val;
32f4334d 2526 Lisp_Object handler;
570d7624
JB
2527
2528 CHECK_STRING (filename, 0);
2529 filename = Fexpand_file_name (filename, Qnil);
2530
32f4334d
RS
2531 /* If the file name has special constructs in it,
2532 call the corresponding file handler. */
49307295 2533 handler = Ffind_file_name_handler (filename, Qfile_symlink_p);
32f4334d
RS
2534 if (!NILP (handler))
2535 return call2 (handler, Qfile_symlink_p, filename);
2536
570d7624
JB
2537 bufsize = 100;
2538 while (1)
2539 {
2540 buf = (char *) xmalloc (bufsize);
2541 bzero (buf, bufsize);
2542 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
2543 if (valsize < bufsize) break;
2544 /* Buffer was not long enough */
9ac0d9e0 2545 xfree (buf);
570d7624
JB
2546 bufsize *= 2;
2547 }
2548 if (valsize == -1)
2549 {
9ac0d9e0 2550 xfree (buf);
570d7624
JB
2551 return Qnil;
2552 }
2553 val = make_string (buf, valsize);
9ac0d9e0 2554 xfree (buf);
570d7624
JB
2555 return val;
2556#else /* not S_IFLNK */
2557 return Qnil;
2558#endif /* not S_IFLNK */
2559}
2560
570d7624
JB
2561DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
2562 "Return t if file FILENAME is the name of a directory as a file.\n\
2563A directory name spec may be given instead; then the value is t\n\
2564if the directory so specified exists and really is a directory.")
2565 (filename)
2566 Lisp_Object filename;
2567{
2568 register Lisp_Object abspath;
2569 struct stat st;
32f4334d 2570 Lisp_Object handler;
570d7624
JB
2571
2572 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2573
32f4334d
RS
2574 /* If the file name has special constructs in it,
2575 call the corresponding file handler. */
49307295 2576 handler = Ffind_file_name_handler (abspath, Qfile_directory_p);
32f4334d 2577 if (!NILP (handler))
09121adc 2578 return call2 (handler, Qfile_directory_p, abspath);
32f4334d 2579
570d7624
JB
2580 if (stat (XSTRING (abspath)->data, &st) < 0)
2581 return Qnil;
2582 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2583}
2584
b72dea2a
JB
2585DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
2586 "Return t if file FILENAME is the name of a directory as a file,\n\
2587and files in that directory can be opened by you. In order to use a\n\
2588directory as a buffer's current directory, this predicate must return true.\n\
2589A directory name spec may be given instead; then the value is t\n\
2590if the directory so specified exists and really is a readable and\n\
2591searchable directory.")
2592 (filename)
2593 Lisp_Object filename;
2594{
32f4334d 2595 Lisp_Object handler;
1a04498e 2596 int tem;
d26859eb 2597 struct gcpro gcpro1;
32f4334d
RS
2598
2599 /* If the file name has special constructs in it,
2600 call the corresponding file handler. */
49307295 2601 handler = Ffind_file_name_handler (filename, Qfile_accessible_directory_p);
32f4334d
RS
2602 if (!NILP (handler))
2603 return call2 (handler, Qfile_accessible_directory_p, filename);
2604
d26859eb
KH
2605 /* It's an unlikely combination, but yes we really do need to gcpro:
2606 Suppose that file-accessible-directory-p has no handler, but
2607 file-directory-p does have a handler; this handler causes a GC which
2608 relocates the string in `filename'; and finally file-directory-p
2609 returns non-nil. Then we would end up passing a garbaged string
2610 to file-executable-p. */
2611 GCPRO1 (filename);
1a04498e
KH
2612 tem = (NILP (Ffile_directory_p (filename))
2613 || NILP (Ffile_executable_p (filename)));
d26859eb 2614 UNGCPRO;
1a04498e 2615 return tem ? Qnil : Qt;
b72dea2a
JB
2616}
2617
f793dc6c
RS
2618DEFUN ("file-regular-p", Ffile_regular_p, Sfile_regular_p, 1, 1, 0,
2619 "Return t if file FILENAME is the name of a regular file.\n\
2620This is the sort of file that holds an ordinary stream of data bytes.")
2621 (filename)
2622 Lisp_Object filename;
2623{
2624 register Lisp_Object abspath;
2625 struct stat st;
2626 Lisp_Object handler;
2627
2628 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2629
2630 /* If the file name has special constructs in it,
2631 call the corresponding file handler. */
adedc71d 2632 handler = Ffind_file_name_handler (abspath, Qfile_regular_p);
f793dc6c 2633 if (!NILP (handler))
adedc71d 2634 return call2 (handler, Qfile_regular_p, abspath);
f793dc6c
RS
2635
2636 if (stat (XSTRING (abspath)->data, &st) < 0)
2637 return Qnil;
2638 return (st.st_mode & S_IFMT) == S_IFREG ? Qt : Qnil;
2639}
2640\f
570d7624
JB
2641DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2642 "Return mode bits of FILE, as an integer.")
2643 (filename)
2644 Lisp_Object filename;
2645{
2646 Lisp_Object abspath;
2647 struct stat st;
32f4334d 2648 Lisp_Object handler;
570d7624
JB
2649
2650 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2651
32f4334d
RS
2652 /* If the file name has special constructs in it,
2653 call the corresponding file handler. */
49307295 2654 handler = Ffind_file_name_handler (abspath, Qfile_modes);
32f4334d 2655 if (!NILP (handler))
09121adc 2656 return call2 (handler, Qfile_modes, abspath);
32f4334d 2657
570d7624
JB
2658 if (stat (XSTRING (abspath)->data, &st) < 0)
2659 return Qnil;
5e570b75 2660#ifdef DOS_NT
3be3c08e
RS
2661 if (check_executable (XSTRING (abspath)->data))
2662 st.st_mode |= S_IEXEC;
5e570b75 2663#endif /* DOS_NT */
3ace87e3 2664
570d7624
JB
2665 return make_number (st.st_mode & 07777);
2666}
2667
2668DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2669 "Set mode bits of FILE to MODE (an integer).\n\
2670Only the 12 low bits of MODE are used.")
2671 (filename, mode)
2672 Lisp_Object filename, mode;
2673{
2674 Lisp_Object abspath;
32f4334d 2675 Lisp_Object handler;
570d7624
JB
2676
2677 abspath = Fexpand_file_name (filename, current_buffer->directory);
2678 CHECK_NUMBER (mode, 1);
2679
32f4334d
RS
2680 /* If the file name has special constructs in it,
2681 call the corresponding file handler. */
49307295 2682 handler = Ffind_file_name_handler (abspath, Qset_file_modes);
32f4334d 2683 if (!NILP (handler))
09121adc 2684 return call3 (handler, Qset_file_modes, abspath, mode);
32f4334d 2685
570d7624
JB
2686 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2687 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
570d7624
JB
2688
2689 return Qnil;
2690}
2691
c24e9a53 2692DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
5f85ea58
RS
2693 "Set the file permission bits for newly created files.\n\
2694The argument MODE should be an integer; only the low 9 bits are used.\n\
36a8c287 2695This setting is inherited by subprocesses.")
5f85ea58
RS
2696 (mode)
2697 Lisp_Object mode;
36a8c287 2698{
5f85ea58 2699 CHECK_NUMBER (mode, 0);
36a8c287 2700
5f85ea58 2701 umask ((~ XINT (mode)) & 0777);
36a8c287
JB
2702
2703 return Qnil;
2704}
2705
c24e9a53 2706DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
5f85ea58
RS
2707 "Return the default file protection for created files.\n\
2708The value is an integer.")
36a8c287
JB
2709 ()
2710{
5f85ea58
RS
2711 int realmask;
2712 Lisp_Object value;
36a8c287 2713
5f85ea58
RS
2714 realmask = umask (0);
2715 umask (realmask);
36a8c287 2716
46283abe 2717 XSETINT (value, (~ realmask) & 0777);
5f85ea58 2718 return value;
36a8c287 2719}
f793dc6c 2720\f
85ffea93
RS
2721#ifdef unix
2722
2723DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2724 "Tell Unix to finish all pending disk updates.")
2725 ()
2726{
2727 sync ();
2728 return Qnil;
2729}
2730
2731#endif /* unix */
2732
570d7624
JB
2733DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2734 "Return t if file FILE1 is newer than file FILE2.\n\
2735If FILE1 does not exist, the answer is nil;\n\
2736otherwise, if FILE2 does not exist, the answer is t.")
2737 (file1, file2)
2738 Lisp_Object file1, file2;
2739{
32f4334d 2740 Lisp_Object abspath1, abspath2;
570d7624
JB
2741 struct stat st;
2742 int mtime1;
32f4334d 2743 Lisp_Object handler;
09121adc 2744 struct gcpro gcpro1, gcpro2;
570d7624
JB
2745
2746 CHECK_STRING (file1, 0);
2747 CHECK_STRING (file2, 0);
2748
09121adc
RS
2749 abspath1 = Qnil;
2750 GCPRO2 (abspath1, file2);
32f4334d
RS
2751 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2752 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
09121adc 2753 UNGCPRO;
570d7624 2754
32f4334d
RS
2755 /* If the file name has special constructs in it,
2756 call the corresponding file handler. */
49307295 2757 handler = Ffind_file_name_handler (abspath1, Qfile_newer_than_file_p);
51cf6d37 2758 if (NILP (handler))
49307295 2759 handler = Ffind_file_name_handler (abspath2, Qfile_newer_than_file_p);
32f4334d
RS
2760 if (!NILP (handler))
2761 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2762
2763 if (stat (XSTRING (abspath1)->data, &st) < 0)
570d7624
JB
2764 return Qnil;
2765
2766 mtime1 = st.st_mtime;
2767
32f4334d 2768 if (stat (XSTRING (abspath2)->data, &st) < 0)
570d7624
JB
2769 return Qt;
2770
2771 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2772}
2773\f
5e570b75 2774#ifdef DOS_NT
4c3c22f3 2775Lisp_Object Qfind_buffer_file_type;
5e570b75 2776#endif /* DOS_NT */
4c3c22f3 2777
570d7624 2778DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
3d0387c0 2779 1, 5, 0,
570d7624 2780 "Insert contents of file FILENAME after point.\n\
7fded690 2781Returns list of absolute file name and length of data inserted.\n\
570d7624
JB
2782If second argument VISIT is non-nil, the buffer's visited filename\n\
2783and last save file modtime are set, and it is marked unmodified.\n\
2784If visiting and the file does not exist, visiting is completed\n\
7fded690
JB
2785before the error is signaled.\n\n\
2786The optional third and fourth arguments BEG and END\n\
2787specify what portion of the file to insert.\n\
3d0387c0
RS
2788If VISIT is non-nil, BEG and END must be nil.\n\
2789If optional fifth argument REPLACE is non-nil,\n\
2790it means replace the current buffer contents (in the accessible portion)\n\
2791with the file contents. This is better than simply deleting and inserting\n\
2792the whole thing because (1) it preserves some marker positions\n\
2793and (2) it puts less data in the undo list.")
2794 (filename, visit, beg, end, replace)
2795 Lisp_Object filename, visit, beg, end, replace;
570d7624
JB
2796{
2797 struct stat st;
2798 register int fd;
2799 register int inserted = 0;
2800 register int how_much;
2801 int count = specpdl_ptr - specpdl;
1a04498e 2802 struct gcpro gcpro1, gcpro2, gcpro3;
d6a3cc15
RS
2803 Lisp_Object handler, val, insval;
2804 Lisp_Object p;
7fded690 2805 int total;
53c34c46 2806 int not_regular = 0;
32f4334d 2807
95385625
RS
2808 if (current_buffer->base_buffer && ! NILP (visit))
2809 error ("Cannot do file visiting in an indirect buffer");
2810
2811 if (!NILP (current_buffer->read_only))
2812 Fbarf_if_buffer_read_only ();
2813
32f4334d 2814 val = Qnil;
d6a3cc15 2815 p = Qnil;
32f4334d 2816
1a04498e 2817 GCPRO3 (filename, val, p);
570d7624
JB
2818
2819 CHECK_STRING (filename, 0);
2820 filename = Fexpand_file_name (filename, Qnil);
2821
32f4334d
RS
2822 /* If the file name has special constructs in it,
2823 call the corresponding file handler. */
49307295 2824 handler = Ffind_file_name_handler (filename, Qinsert_file_contents);
32f4334d
RS
2825 if (!NILP (handler))
2826 {
3d0387c0
RS
2827 val = call6 (handler, Qinsert_file_contents, filename,
2828 visit, beg, end, replace);
32f4334d
RS
2829 goto handled;
2830 }
2831
570d7624
JB
2832 fd = -1;
2833
2834#ifndef APOLLO
99bc28f4 2835 if (stat (XSTRING (filename)->data, &st) < 0)
570d7624 2836#else
4018b5ef 2837 if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0
570d7624
JB
2838 || fstat (fd, &st) < 0)
2839#endif /* not APOLLO */
2840 {
2841 if (fd >= 0) close (fd);
99bc28f4 2842 badopen:
265a9e55 2843 if (NILP (visit))
570d7624
JB
2844 report_file_error ("Opening input file", Fcons (filename, Qnil));
2845 st.st_mtime = -1;
2846 how_much = 0;
2847 goto notfound;
2848 }
2849
99bc28f4 2850#ifdef S_IFREG
be53b411
JB
2851 /* This code will need to be changed in order to work on named
2852 pipes, and it's probably just not worth it. So we should at
2853 least signal an error. */
99bc28f4 2854 if (!S_ISREG (st.st_mode))
330bfe57
RS
2855 {
2856 if (NILP (visit))
2857 Fsignal (Qfile_error,
2858 Fcons (build_string ("not a regular file"),
2859 Fcons (filename, Qnil)));
2860
2861 not_regular = 1;
2862 goto notfound;
2863 }
be53b411
JB
2864#endif
2865
99bc28f4 2866 if (fd < 0)
4018b5ef 2867 if ((fd = open (XSTRING (filename)->data, O_RDONLY)) < 0)
99bc28f4
KH
2868 goto badopen;
2869
2870 /* Replacement should preserve point as it preserves markers. */
2871 if (!NILP (replace))
2872 record_unwind_protect (restore_point_unwind, Fpoint_marker ());
2873
2874 record_unwind_protect (close_file_unwind, make_number (fd));
2875
570d7624
JB
2876 /* Supposedly happens on VMS. */
2877 if (st.st_size < 0)
2878 error ("File size is negative");
be53b411 2879
7fded690
JB
2880 if (!NILP (beg) || !NILP (end))
2881 if (!NILP (visit))
2882 error ("Attempt to visit less than an entire file");
2883
2884 if (!NILP (beg))
2885 CHECK_NUMBER (beg, 0);
2886 else
2acfd7ae 2887 XSETFASTINT (beg, 0);
7fded690
JB
2888
2889 if (!NILP (end))
2890 CHECK_NUMBER (end, 0);
2891 else
2892 {
2893 XSETINT (end, st.st_size);
2894 if (XINT (end) != st.st_size)
2895 error ("maximum buffer size exceeded");
2896 }
2897
3d0387c0
RS
2898 /* If requested, replace the accessible part of the buffer
2899 with the file contents. Avoid replacing text at the
2900 beginning or end of the buffer that matches the file contents;
2901 that preserves markers pointing to the unchanged parts. */
5e570b75 2902#ifdef DOS_NT
e54d3b5d
RS
2903 /* On MSDOS, replace mode doesn't really work, except for binary files,
2904 and it's not worth supporting just for them. */
2905 if (!NILP (replace))
2906 {
2907 replace = Qnil;
2acfd7ae
KH
2908 XSETFASTINT (beg, 0);
2909 XSETFASTINT (end, st.st_size);
e54d3b5d
RS
2910 del_range_1 (BEGV, ZV, 0);
2911 }
5e570b75 2912#else /* not DOS_NT */
3d0387c0
RS
2913 if (!NILP (replace))
2914 {
268466ed 2915 unsigned char buffer[1 << 14];
3d0387c0
RS
2916 int same_at_start = BEGV;
2917 int same_at_end = ZV;
9c28748f
RS
2918 int overlap;
2919
3d0387c0
RS
2920 immediate_quit = 1;
2921 QUIT;
2922 /* Count how many chars at the start of the file
2923 match the text at the beginning of the buffer. */
2924 while (1)
2925 {
2926 int nread, bufpos;
2927
2928 nread = read (fd, buffer, sizeof buffer);
2929 if (nread < 0)
2930 error ("IO error reading %s: %s",
2931 XSTRING (filename)->data, strerror (errno));
2932 else if (nread == 0)
2933 break;
2934 bufpos = 0;
2935 while (bufpos < nread && same_at_start < ZV
2936 && FETCH_CHAR (same_at_start) == buffer[bufpos])
2937 same_at_start++, bufpos++;
2938 /* If we found a discrepancy, stop the scan.
8e6208c5 2939 Otherwise loop around and scan the next bufferful. */
3d0387c0
RS
2940 if (bufpos != nread)
2941 break;
2942 }
2943 immediate_quit = 0;
2944 /* If the file matches the buffer completely,
2945 there's no need to replace anything. */
1051b3b3 2946 if (same_at_start - BEGV == st.st_size)
3d0387c0
RS
2947 {
2948 close (fd);
a1d2b64a 2949 specpdl_ptr--;
1051b3b3
RS
2950 /* Truncate the buffer to the size of the file. */
2951 del_range_1 (same_at_start, same_at_end, 0);
3d0387c0
RS
2952 goto handled;
2953 }
2954 immediate_quit = 1;
2955 QUIT;
2956 /* Count how many chars at the end of the file
2957 match the text at the end of the buffer. */
2958 while (1)
2959 {
2960 int total_read, nread, bufpos, curpos, trial;
2961
2962 /* At what file position are we now scanning? */
2963 curpos = st.st_size - (ZV - same_at_end);
fc81fa9e
KH
2964 /* If the entire file matches the buffer tail, stop the scan. */
2965 if (curpos == 0)
2966 break;
3d0387c0
RS
2967 /* How much can we scan in the next step? */
2968 trial = min (curpos, sizeof buffer);
2969 if (lseek (fd, curpos - trial, 0) < 0)
2970 report_file_error ("Setting file position",
2971 Fcons (filename, Qnil));
2972
2973 total_read = 0;
2974 while (total_read < trial)
2975 {
2976 nread = read (fd, buffer + total_read, trial - total_read);
2977 if (nread <= 0)
2978 error ("IO error reading %s: %s",
2979 XSTRING (filename)->data, strerror (errno));
2980 total_read += nread;
2981 }
8e6208c5 2982 /* Scan this bufferful from the end, comparing with
3d0387c0
RS
2983 the Emacs buffer. */
2984 bufpos = total_read;
2985 /* Compare with same_at_start to avoid counting some buffer text
2986 as matching both at the file's beginning and at the end. */
2987 while (bufpos > 0 && same_at_end > same_at_start
2988 && FETCH_CHAR (same_at_end - 1) == buffer[bufpos - 1])
2989 same_at_end--, bufpos--;
2990 /* If we found a discrepancy, stop the scan.
8e6208c5 2991 Otherwise loop around and scan the preceding bufferful. */
3d0387c0
RS
2992 if (bufpos != 0)
2993 break;
26fb39b5
RS
2994 /* If display current starts at beginning of line,
2995 keep it that way. */
2996 if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
2997 XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
3d0387c0
RS
2998 }
2999 immediate_quit = 0;
9c28748f
RS
3000
3001 /* Don't try to reuse the same piece of text twice. */
3002 overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV);
3003 if (overlap > 0)
3004 same_at_end += overlap;
3005
3d0387c0 3006 /* Arrange to read only the nonmatching middle part of the file. */
2acfd7ae
KH
3007 XSETFASTINT (beg, same_at_start - BEGV);
3008 XSETFASTINT (end, st.st_size - (ZV - same_at_end));
9c28748f 3009
251f623e 3010 del_range_1 (same_at_start, same_at_end, 0);
a1d2b64a
RS
3011 /* Insert from the file at the proper position. */
3012 SET_PT (same_at_start);
3d0387c0 3013 }
5e570b75 3014#endif /* not DOS_NT */
3d0387c0 3015
7fded690
JB
3016 total = XINT (end) - XINT (beg);
3017
570d7624
JB
3018 {
3019 register Lisp_Object temp;
3020
3021 /* Make sure point-max won't overflow after this insertion. */
46283abe 3022 XSETINT (temp, total);
7fded690 3023 if (total != XINT (temp))
570d7624
JB
3024 error ("maximum buffer size exceeded");
3025 }
3026
57d8d468 3027 if (NILP (visit) && total > 0)
570d7624
JB
3028 prepare_to_modify_buffer (point, point);
3029
3030 move_gap (point);
7fded690
JB
3031 if (GAP_SIZE < total)
3032 make_gap (total - GAP_SIZE);
3033
a1d2b64a 3034 if (XINT (beg) != 0 || !NILP (replace))
7fded690
JB
3035 {
3036 if (lseek (fd, XINT (beg), 0) < 0)
3037 report_file_error ("Setting file position", Fcons (filename, Qnil));
3038 }
3039
a1d2b64a
RS
3040 how_much = 0;
3041 while (inserted < total)
570d7624 3042 {
5e570b75
RS
3043 /* try is reserved in some compilers (Microsoft C) */
3044 int trytry = min (total - inserted, 64 << 10);
b5148e85
RS
3045 int this;
3046
3047 /* Allow quitting out of the actual I/O. */
3048 immediate_quit = 1;
3049 QUIT;
5e570b75 3050 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, trytry);
b5148e85 3051 immediate_quit = 0;
570d7624
JB
3052
3053 if (this <= 0)
3054 {
3055 how_much = this;
3056 break;
3057 }
3058
3059 GPT += this;
3060 GAP_SIZE -= this;
3061 ZV += this;
3062 Z += this;
3063 inserted += this;
3064 }
3065
5e570b75 3066#ifdef DOS_NT
4c3c22f3
RS
3067 /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
3068 /* Determine file type from name and remove LFs from CR-LFs if the file
3069 is deemed to be a text file. */
3070 {
bf162ea8
RS
3071 current_buffer->buffer_file_type
3072 = call1 (Qfind_buffer_file_type, filename);
bf162ea8 3073 if (NILP (current_buffer->buffer_file_type))
4c3c22f3 3074 {
a1d2b64a
RS
3075 int reduced_size
3076 = inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
4c3c22f3
RS
3077 ZV -= reduced_size;
3078 Z -= reduced_size;
3079 GPT -= reduced_size;
3080 GAP_SIZE += reduced_size;
3081 inserted -= reduced_size;
3082 }
3083 }
5e570b75 3084#endif /* DOS_NT */
4c3c22f3 3085
570d7624 3086 if (inserted > 0)
7d8451f1
RS
3087 {
3088 record_insert (point, inserted);
8d4e077b
JA
3089
3090 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
3091 offset_intervals (current_buffer, point, inserted);
7d8451f1
RS
3092 MODIFF++;
3093 }
570d7624
JB
3094
3095 close (fd);
3096
a1d2b64a
RS
3097 /* Discard the unwind protect for closing the file. */
3098 specpdl_ptr--;
570d7624
JB
3099
3100 if (how_much < 0)
3101 error ("IO error reading %s: %s",
ce97267f 3102 XSTRING (filename)->data, strerror (errno));
570d7624
JB
3103
3104 notfound:
32f4334d 3105 handled:
570d7624 3106
265a9e55 3107 if (!NILP (visit))
570d7624 3108 {
cfadd376
RS
3109 if (!EQ (current_buffer->undo_list, Qt))
3110 current_buffer->undo_list = Qnil;
570d7624
JB
3111#ifdef APOLLO
3112 stat (XSTRING (filename)->data, &st);
3113#endif
62bcf009 3114
a7e82472
RS
3115 if (NILP (handler))
3116 {
3117 current_buffer->modtime = st.st_mtime;
3118 current_buffer->filename = filename;
3119 }
62bcf009 3120
95385625 3121 SAVE_MODIFF = MODIFF;
570d7624 3122 current_buffer->auto_save_modified = MODIFF;
2acfd7ae 3123 XSETFASTINT (current_buffer->save_length, Z - BEG);
570d7624 3124#ifdef CLASH_DETECTION
32f4334d
RS
3125 if (NILP (handler))
3126 {
f471f4c2
RS
3127 if (!NILP (current_buffer->file_truename))
3128 unlock_file (current_buffer->file_truename);
32f4334d
RS
3129 unlock_file (filename);
3130 }
570d7624 3131#endif /* CLASH_DETECTION */
330bfe57
RS
3132 if (not_regular)
3133 Fsignal (Qfile_error,
3134 Fcons (build_string ("not a regular file"),
3135 Fcons (filename, Qnil)));
3136
570d7624 3137 /* If visiting nonexistent file, return nil. */
32f4334d 3138 if (current_buffer->modtime == -1)
570d7624
JB
3139 report_file_error ("Opening input file", Fcons (filename, Qnil));
3140 }
3141
0d420e88
BG
3142 /* Decode file format */
3143 if (inserted > 0)
3144 {
3145 insval = call3 (Qformat_decode,
3146 Qnil, make_number (inserted), visit);
3147 CHECK_NUMBER (insval, 0);
3148 inserted = XFASTINT (insval);
3149 }
3150
62bcf009 3151 if (inserted > 0 && NILP (visit) && total > 0)
d2cad97d 3152 signal_after_change (point, 0, inserted);
570d7624 3153
d6a3cc15
RS
3154 if (inserted > 0)
3155 {
3156 p = Vafter_insert_file_functions;
3157 while (!NILP (p))
3158 {
3159 insval = call1 (Fcar (p), make_number (inserted));
3160 if (!NILP (insval))
3161 {
3162 CHECK_NUMBER (insval, 0);
3163 inserted = XFASTINT (insval);
3164 }
3165 QUIT;
3166 p = Fcdr (p);
3167 }
3168 }
3169
a1d2b64a
RS
3170 if (NILP (val))
3171 val = Fcons (filename,
3172 Fcons (make_number (inserted),
3173 Qnil));
3174
3175 RETURN_UNGCPRO (unbind_to (count, val));
570d7624 3176}
7fded690 3177\f
d6a3cc15
RS
3178static Lisp_Object build_annotations ();
3179
6fc6f94b
RS
3180/* If build_annotations switched buffers, switch back to BUF.
3181 Kill the temporary buffer that was selected in the meantime. */
3182
3183static Lisp_Object
3184build_annotations_unwind (buf)
3185 Lisp_Object buf;
3186{
3187 Lisp_Object tembuf;
3188
3189 if (XBUFFER (buf) == current_buffer)
3190 return Qnil;
3191 tembuf = Fcurrent_buffer ();
3192 Fset_buffer (buf);
3193 Fkill_buffer (tembuf);
3194 return Qnil;
3195}
3196
7204a979 3197DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 6,
570d7624
JB
3198 "r\nFWrite region to file: ",
3199 "Write current region into specified file.\n\
3200When called from a program, takes three arguments:\n\
3201START, END and FILENAME. START and END are buffer positions.\n\
3202Optional fourth argument APPEND if non-nil means\n\
3203 append to existing file contents (if any).\n\
3204Optional fifth argument VISIT if t means\n\
3205 set the last-save-file-modtime of buffer to this file's modtime\n\
3206 and mark buffer not modified.\n\
3b7792ed
RS
3207If VISIT is a string, it is a second file name;\n\
3208 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
3209 VISIT is also the file name to lock and unlock for clash detection.\n\
1d386d28
RS
3210If VISIT is neither t nor nil nor a string,\n\
3211 that means do not print the \"Wrote file\" message.\n\
7204a979
RS
3212The optional sixth arg LOCKNAME, if non-nil, specifies the name to\n\
3213 use for locking and unlocking, overriding FILENAME and VISIT.\n\
570d7624
JB
3214Kludgy feature: if START is a string, then that string is written\n\
3215to the file, instead of any buffer contents, and END is ignored.")
7204a979
RS
3216 (start, end, filename, append, visit, lockname)
3217 Lisp_Object start, end, filename, append, visit, lockname;
570d7624
JB
3218{
3219 register int desc;
3220 int failure;
3221 int save_errno;
3222 unsigned char *fn;
3223 struct stat st;
c975dd7a 3224 int tem;
570d7624 3225 int count = specpdl_ptr - specpdl;
6fc6f94b 3226 int count1;
570d7624 3227#ifdef VMS
5e570b75 3228 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
570d7624 3229#endif /* VMS */
3eac9910 3230 Lisp_Object handler;
4ad827c5 3231 Lisp_Object visit_file;
d6a3cc15
RS
3232 Lisp_Object annotations;
3233 int visiting, quietly;
7204a979 3234 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
6fc6f94b 3235 struct buffer *given_buffer;
5e570b75 3236#ifdef DOS_NT
4c3c22f3
RS
3237 int buffer_file_type
3238 = NILP (current_buffer->buffer_file_type) ? O_TEXT : O_BINARY;
5e570b75 3239#endif /* DOS_NT */
570d7624 3240
95385625
RS
3241 if (current_buffer->base_buffer && ! NILP (visit))
3242 error ("Cannot do file visiting in an indirect buffer");
3243
561cb8e1 3244 if (!NILP (start) && !STRINGP (start))
570d7624
JB
3245 validate_region (&start, &end);
3246
7204a979 3247 GCPRO3 (filename, visit, lockname);
570d7624 3248 filename = Fexpand_file_name (filename, Qnil);
561cb8e1 3249 if (STRINGP (visit))
e5176bae 3250 visit_file = Fexpand_file_name (visit, Qnil);
4ad827c5
RS
3251 else
3252 visit_file = filename;
1a04498e 3253 UNGCPRO;
4ad827c5 3254
561cb8e1 3255 visiting = (EQ (visit, Qt) || STRINGP (visit));
d6a3cc15
RS
3256 quietly = !NILP (visit);
3257
3258 annotations = Qnil;
3259
7204a979
RS
3260 if (NILP (lockname))
3261 lockname = visit_file;
3262
3263 GCPRO5 (start, filename, annotations, visit_file, lockname);
570d7624 3264
32f4334d
RS
3265 /* If the file name has special constructs in it,
3266 call the corresponding file handler. */
49307295 3267 handler = Ffind_file_name_handler (filename, Qwrite_region);
b56ad927 3268 /* If FILENAME has no handler, see if VISIT has one. */
93c30b5f 3269 if (NILP (handler) && STRINGP (visit))
49307295 3270 handler = Ffind_file_name_handler (visit, Qwrite_region);
3eac9910 3271
32f4334d
RS
3272 if (!NILP (handler))
3273 {
32f4334d 3274 Lisp_Object val;
51cf6d37
RS
3275 val = call6 (handler, Qwrite_region, start, end,
3276 filename, append, visit);
32f4334d 3277
d6a3cc15 3278 if (visiting)
32f4334d 3279 {
95385625 3280 SAVE_MODIFF = MODIFF;
2acfd7ae 3281 XSETFASTINT (current_buffer->save_length, Z - BEG);
3b7792ed 3282 current_buffer->filename = visit_file;
32f4334d 3283 }
09121adc 3284 UNGCPRO;
32f4334d
RS
3285 return val;
3286 }
3287
561cb8e1
RS
3288 /* Special kludge to simplify auto-saving. */
3289 if (NILP (start))
3290 {
2acfd7ae
KH
3291 XSETFASTINT (start, BEG);
3292 XSETFASTINT (end, Z);
561cb8e1
RS
3293 }
3294
6fc6f94b
RS
3295 record_unwind_protect (build_annotations_unwind, Fcurrent_buffer ());
3296 count1 = specpdl_ptr - specpdl;
3297
3298 given_buffer = current_buffer;
d6a3cc15 3299 annotations = build_annotations (start, end);
6fc6f94b
RS
3300 if (current_buffer != given_buffer)
3301 {
3302 start = BEGV;
3303 end = ZV;
3304 }
d6a3cc15 3305
570d7624
JB
3306#ifdef CLASH_DETECTION
3307 if (!auto_saving)
7204a979 3308 lock_file (lockname);
570d7624
JB
3309#endif /* CLASH_DETECTION */
3310
09121adc 3311 fn = XSTRING (filename)->data;
570d7624 3312 desc = -1;
265a9e55 3313 if (!NILP (append))
5e570b75 3314#ifdef DOS_NT
4c3c22f3 3315 desc = open (fn, O_WRONLY | buffer_file_type);
5e570b75 3316#else /* not DOS_NT */
570d7624 3317 desc = open (fn, O_WRONLY);
5e570b75 3318#endif /* not DOS_NT */
570d7624
JB
3319
3320 if (desc < 0)
3321#ifdef VMS
5e570b75 3322 if (auto_saving) /* Overwrite any previous version of autosave file */
570d7624 3323 {
5e570b75 3324 vms_truncate (fn); /* if fn exists, truncate to zero length */
570d7624
JB
3325 desc = open (fn, O_RDWR);
3326 if (desc < 0)
561cb8e1 3327 desc = creat_copy_attrs (STRINGP (current_buffer->filename)
b72dea2a
JB
3328 ? XSTRING (current_buffer->filename)->data : 0,
3329 fn);
570d7624 3330 }
5e570b75 3331 else /* Write to temporary name and rename if no errors */
570d7624
JB
3332 {
3333 Lisp_Object temp_name;
3334 temp_name = Ffile_name_directory (filename);
3335
265a9e55 3336 if (!NILP (temp_name))
570d7624
JB
3337 {
3338 temp_name = Fmake_temp_name (concat2 (temp_name,
3339 build_string ("$$SAVE$$")));
3340 fname = XSTRING (filename)->data;
3341 fn = XSTRING (temp_name)->data;
3342 desc = creat_copy_attrs (fname, fn);
3343 if (desc < 0)
3344 {
3345 /* If we can't open the temporary file, try creating a new
3346 version of the original file. VMS "creat" creates a
3347 new version rather than truncating an existing file. */
3348 fn = fname;
3349 fname = 0;
3350 desc = creat (fn, 0666);
3351#if 0 /* This can clobber an existing file and fail to replace it,
3352 if the user runs out of space. */
3353 if (desc < 0)
3354 {
3355 /* We can't make a new version;
3356 try to truncate and rewrite existing version if any. */
3357 vms_truncate (fn);
3358 desc = open (fn, O_RDWR);
3359 }
3360#endif
3361 }
3362 }
3363 else
3364 desc = creat (fn, 0666);
3365 }
3366#else /* not VMS */
5e570b75 3367#ifdef DOS_NT
4c3c22f3
RS
3368 desc = open (fn,
3369 O_WRONLY | O_TRUNC | O_CREAT | buffer_file_type,
3370 S_IREAD | S_IWRITE);
5e570b75 3371#else /* not DOS_NT */
570d7624 3372 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
5e570b75 3373#endif /* not DOS_NT */
570d7624
JB
3374#endif /* not VMS */
3375
09121adc
RS
3376 UNGCPRO;
3377
570d7624
JB
3378 if (desc < 0)
3379 {
3380#ifdef CLASH_DETECTION
3381 save_errno = errno;
7204a979 3382 if (!auto_saving) unlock_file (lockname);
570d7624
JB
3383 errno = save_errno;
3384#endif /* CLASH_DETECTION */
3385 report_file_error ("Opening output file", Fcons (filename, Qnil));
3386 }
3387
3388 record_unwind_protect (close_file_unwind, make_number (desc));
3389
265a9e55 3390 if (!NILP (append))
570d7624
JB
3391 if (lseek (desc, 0, 2) < 0)
3392 {
3393#ifdef CLASH_DETECTION
7204a979 3394 if (!auto_saving) unlock_file (lockname);
570d7624
JB
3395#endif /* CLASH_DETECTION */
3396 report_file_error ("Lseek error", Fcons (filename, Qnil));
3397 }
3398
3399#ifdef VMS
3400/*
3401 * Kludge Warning: The VMS C RTL likes to insert carriage returns
3402 * if we do writes that don't end with a carriage return. Furthermore
3403 * it cannot handle writes of more then 16K. The modified
3404 * version of "sys_write" in SYSDEP.C (see comment there) copes with
3405 * this EXCEPT for the last record (iff it doesn't end with a carriage
3406 * return). This implies that if your buffer doesn't end with a carriage
3407 * return, you get one free... tough. However it also means that if
3408 * we make two calls to sys_write (a la the following code) you can
3409 * get one at the gap as well. The easiest way to fix this (honest)
3410 * is to move the gap to the next newline (or the end of the buffer).
3411 * Thus this change.
3412 *
3413 * Yech!
3414 */
3415 if (GPT > BEG && GPT_ADDR[-1] != '\n')
3416 move_gap (find_next_newline (GPT, 1));
3417#endif
3418
3419 failure = 0;
3420 immediate_quit = 1;
3421
561cb8e1 3422 if (STRINGP (start))
570d7624 3423 {
d6a3cc15
RS
3424 failure = 0 > a_write (desc, XSTRING (start)->data,
3425 XSTRING (start)->size, 0, &annotations);
570d7624
JB
3426 save_errno = errno;
3427 }
3428 else if (XINT (start) != XINT (end))
3429 {
c975dd7a 3430 int nwritten = 0;
570d7624
JB
3431 if (XINT (start) < GPT)
3432 {
3433 register int end1 = XINT (end);
3434 tem = XINT (start);
d6a3cc15 3435 failure = 0 > a_write (desc, &FETCH_CHAR (tem),
c975dd7a
RS
3436 min (GPT, end1) - tem, tem, &annotations);
3437 nwritten += min (GPT, end1) - tem;
570d7624
JB
3438 save_errno = errno;
3439 }
3440
3441 if (XINT (end) > GPT && !failure)
3442 {
3443 tem = XINT (start);
3444 tem = max (tem, GPT);
d6a3cc15 3445 failure = 0 > a_write (desc, &FETCH_CHAR (tem), XINT (end) - tem,
c975dd7a
RS
3446 tem, &annotations);
3447 nwritten += XINT (end) - tem;
d6a3cc15
RS
3448 save_errno = errno;
3449 }
69f6e679
RS
3450 }
3451 else
3452 {
3453 /* If file was empty, still need to write the annotations */
3454 failure = 0 > a_write (desc, "", 0, XINT (start), &annotations);
3455 save_errno = errno;
570d7624
JB
3456 }
3457
3458 immediate_quit = 0;
3459
6e23c83e 3460#ifdef HAVE_FSYNC
570d7624
JB
3461 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
3462 Disk full in NFS may be reported here. */
1daffa1c
RS
3463 /* mib says that closing the file will try to write as fast as NFS can do
3464 it, and that means the fsync here is not crucial for autosave files. */
3465 if (!auto_saving && fsync (desc) < 0)
cb33c142
KH
3466 {
3467 /* If fsync fails with EINTR, don't treat that as serious. */
3468 if (errno != EINTR)
3469 failure = 1, save_errno = errno;
3470 }
570d7624
JB
3471#endif
3472
3473 /* Spurious "file has changed on disk" warnings have been
3474 observed on Suns as well.
3475 It seems that `close' can change the modtime, under nfs.
3476
3477 (This has supposedly been fixed in Sunos 4,
3478 but who knows about all the other machines with NFS?) */
3479#if 0
3480
3481 /* On VMS and APOLLO, must do the stat after the close
3482 since closing changes the modtime. */
3483#ifndef VMS
3484#ifndef APOLLO
3485 /* Recall that #if defined does not work on VMS. */
3486#define FOO
3487 fstat (desc, &st);
3488#endif
3489#endif
3490#endif
3491
3492 /* NFS can report a write failure now. */
3493 if (close (desc) < 0)
3494 failure = 1, save_errno = errno;
3495
3496#ifdef VMS
3497 /* If we wrote to a temporary name and had no errors, rename to real name. */
3498 if (fname)
3499 {
3500 if (!failure)
3501 failure = (rename (fn, fname) != 0), save_errno = errno;
3502 fn = fname;
3503 }
3504#endif /* VMS */
3505
3506#ifndef FOO
3507 stat (fn, &st);
3508#endif
6fc6f94b
RS
3509 /* Discard the unwind protect for close_file_unwind. */
3510 specpdl_ptr = specpdl + count1;
3511 /* Restore the original current buffer. */
98295b48 3512 visit_file = unbind_to (count, visit_file);
570d7624
JB
3513
3514#ifdef CLASH_DETECTION
3515 if (!auto_saving)
7204a979 3516 unlock_file (lockname);
570d7624
JB
3517#endif /* CLASH_DETECTION */
3518
3519 /* Do this before reporting IO error
3520 to avoid a "file has changed on disk" warning on
3521 next attempt to save. */
d6a3cc15 3522 if (visiting)
570d7624
JB
3523 current_buffer->modtime = st.st_mtime;
3524
3525 if (failure)
ce97267f 3526 error ("IO error writing %s: %s", fn, strerror (save_errno));
570d7624 3527
d6a3cc15 3528 if (visiting)
570d7624 3529 {
95385625 3530 SAVE_MODIFF = MODIFF;
2acfd7ae 3531 XSETFASTINT (current_buffer->save_length, Z - BEG);
3b7792ed 3532 current_buffer->filename = visit_file;
f4226e89 3533 update_mode_lines++;
570d7624 3534 }
d6a3cc15 3535 else if (quietly)
570d7624
JB
3536 return Qnil;
3537
3538 if (!auto_saving)
3b7792ed 3539 message ("Wrote %s", XSTRING (visit_file)->data);
570d7624
JB
3540
3541 return Qnil;
3542}
3543
d6a3cc15
RS
3544Lisp_Object merge ();
3545
3546DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0,
2ba0ccff 3547 "Return t if (car A) is numerically less than (car B).")
d6a3cc15
RS
3548 (a, b)
3549 Lisp_Object a, b;
3550{
3551 return Flss (Fcar (a), Fcar (b));
3552}
3553
3554/* Build the complete list of annotations appropriate for writing out
3555 the text between START and END, by calling all the functions in
6fc6f94b
RS
3556 write-region-annotate-functions and merging the lists they return.
3557 If one of these functions switches to a different buffer, we assume
3558 that buffer contains altered text. Therefore, the caller must
3559 make sure to restore the current buffer in all cases,
3560 as save-excursion would do. */
d6a3cc15
RS
3561
3562static Lisp_Object
3563build_annotations (start, end)
3564 Lisp_Object start, end;
3565{
3566 Lisp_Object annotations;
3567 Lisp_Object p, res;
3568 struct gcpro gcpro1, gcpro2;
3569
3570 annotations = Qnil;
3571 p = Vwrite_region_annotate_functions;
3572 GCPRO2 (annotations, p);
3573 while (!NILP (p))
3574 {
6fc6f94b
RS
3575 struct buffer *given_buffer = current_buffer;
3576 Vwrite_region_annotations_so_far = annotations;
d6a3cc15 3577 res = call2 (Fcar (p), start, end);
6fc6f94b
RS
3578 /* If the function makes a different buffer current,
3579 assume that means this buffer contains altered text to be output.
3580 Reset START and END from the buffer bounds
3581 and discard all previous annotations because they should have
3582 been dealt with by this function. */
3583 if (current_buffer != given_buffer)
3584 {
6fc6f94b
RS
3585 start = BEGV;
3586 end = ZV;
3587 annotations = Qnil;
3588 }
d6a3cc15
RS
3589 Flength (res); /* Check basic validity of return value */
3590 annotations = merge (annotations, res, Qcar_less_than_car);
3591 p = Fcdr (p);
3592 }
0d420e88
BG
3593
3594 /* Now do the same for annotation functions implied by the file-format */
3595 if (auto_saving && (!EQ (Vauto_save_file_format, Qt)))
3596 p = Vauto_save_file_format;
3597 else
3598 p = current_buffer->file_format;
3599 while (!NILP (p))
3600 {
3601 struct buffer *given_buffer = current_buffer;
3602 Vwrite_region_annotations_so_far = annotations;
3603 res = call3 (Qformat_annotate_function, Fcar (p), start, end);
3604 if (current_buffer != given_buffer)
3605 {
3606 start = BEGV;
3607 end = ZV;
3608 annotations = Qnil;
3609 }
3610 Flength (res);
3611 annotations = merge (annotations, res, Qcar_less_than_car);
3612 p = Fcdr (p);
3613 }
d6a3cc15
RS
3614 UNGCPRO;
3615 return annotations;
3616}
3617
3618/* Write to descriptor DESC the LEN characters starting at ADDR,
3619 assuming they start at position POS in the buffer.
3620 Intersperse with them the annotations from *ANNOT
3621 (those which fall within the range of positions POS to POS + LEN),
3622 each at its appropriate position.
3623
3624 Modify *ANNOT by discarding elements as we output them.
3625 The return value is negative in case of system call failure. */
3626
3627int
3628a_write (desc, addr, len, pos, annot)
3629 int desc;
3630 register char *addr;
3631 register int len;
3632 int pos;
3633 Lisp_Object *annot;
3634{
3635 Lisp_Object tem;
3636 int nextpos;
3637 int lastpos = pos + len;
3638
eb15aa18 3639 while (NILP (*annot) || CONSP (*annot))
d6a3cc15
RS
3640 {
3641 tem = Fcar_safe (Fcar (*annot));
3642 if (INTEGERP (tem) && XINT (tem) >= pos && XFASTINT (tem) <= lastpos)
3643 nextpos = XFASTINT (tem);
3644 else
3645 return e_write (desc, addr, lastpos - pos);
3646 if (nextpos > pos)
3647 {
3648 if (0 > e_write (desc, addr, nextpos - pos))
3649 return -1;
3650 addr += nextpos - pos;
3651 pos = nextpos;
3652 }
3653 tem = Fcdr (Fcar (*annot));
3654 if (STRINGP (tem))
3655 {
3656 if (0 > e_write (desc, XSTRING (tem)->data, XSTRING (tem)->size))
3657 return -1;
3658 }
3659 *annot = Fcdr (*annot);
3660 }
3661}
3662
570d7624
JB
3663int
3664e_write (desc, addr, len)
3665 int desc;
3666 register char *addr;
3667 register int len;
3668{
3669 char buf[16 * 1024];
3670 register char *p, *end;
3671
3672 if (!EQ (current_buffer->selective_display, Qt))
3673 return write (desc, addr, len) - len;
3674 else
3675 {
3676 p = buf;
3677 end = p + sizeof buf;
3678 while (len--)
3679 {
3680 if (p == end)
3681 {
3682 if (write (desc, buf, sizeof buf) != sizeof buf)
3683 return -1;
3684 p = buf;
3685 }
3686 *p = *addr++;
3687 if (*p++ == '\015')
3688 p[-1] = '\n';
3689 }
3690 if (p != buf)
3691 if (write (desc, buf, p - buf) != p - buf)
3692 return -1;
3693 }
3694 return 0;
3695}
3696
3697DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
3698 Sverify_visited_file_modtime, 1, 1, 0,
3699 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
3700This means that the file has not been changed since it was visited or saved.")
3701 (buf)
3702 Lisp_Object buf;
3703{
3704 struct buffer *b;
3705 struct stat st;
32f4334d 3706 Lisp_Object handler;
570d7624
JB
3707
3708 CHECK_BUFFER (buf, 0);
3709 b = XBUFFER (buf);
3710
93c30b5f 3711 if (!STRINGP (b->filename)) return Qt;
570d7624
JB
3712 if (b->modtime == 0) return Qt;
3713
32f4334d
RS
3714 /* If the file name has special constructs in it,
3715 call the corresponding file handler. */
49307295
KH
3716 handler = Ffind_file_name_handler (b->filename,
3717 Qverify_visited_file_modtime);
32f4334d 3718 if (!NILP (handler))
09121adc 3719 return call2 (handler, Qverify_visited_file_modtime, buf);
32f4334d 3720
570d7624
JB
3721 if (stat (XSTRING (b->filename)->data, &st) < 0)
3722 {
3723 /* If the file doesn't exist now and didn't exist before,
3724 we say that it isn't modified, provided the error is a tame one. */
3725 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
3726 st.st_mtime = -1;
3727 else
3728 st.st_mtime = 0;
3729 }
3730 if (st.st_mtime == b->modtime
3731 /* If both are positive, accept them if they are off by one second. */
3732 || (st.st_mtime > 0 && b->modtime > 0
3733 && (st.st_mtime == b->modtime + 1
3734 || st.st_mtime == b->modtime - 1)))
3735 return Qt;
3736 return Qnil;
3737}
3738
3739DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
3740 Sclear_visited_file_modtime, 0, 0, 0,
3741 "Clear out records of last mod time of visited file.\n\
3742Next attempt to save will certainly not complain of a discrepancy.")
3743 ()
3744{
3745 current_buffer->modtime = 0;
3746 return Qnil;
3747}
3748
f5d5eccf
RS
3749DEFUN ("visited-file-modtime", Fvisited_file_modtime,
3750 Svisited_file_modtime, 0, 0, 0,
3751 "Return the current buffer's recorded visited file modification time.\n\
3752The value is a list of the form (HIGH . LOW), like the time values\n\
3753that `file-attributes' returns.")
3754 ()
3755{
b50536bb 3756 return long_to_cons ((unsigned long) current_buffer->modtime);
f5d5eccf
RS
3757}
3758
570d7624 3759DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
f5d5eccf 3760 Sset_visited_file_modtime, 0, 1, 0,
570d7624
JB
3761 "Update buffer's recorded modification time from the visited file's time.\n\
3762Useful if the buffer was not read from the file normally\n\
f5d5eccf
RS
3763or if the file itself has been changed for some known benign reason.\n\
3764An argument specifies the modification time value to use\n\
3765\(instead of that of the visited file), in the form of a list\n\
3766\(HIGH . LOW) or (HIGH LOW).")
3767 (time_list)
3768 Lisp_Object time_list;
570d7624 3769{
f5d5eccf
RS
3770 if (!NILP (time_list))
3771 current_buffer->modtime = cons_to_long (time_list);
3772 else
3773 {
3774 register Lisp_Object filename;
3775 struct stat st;
3776 Lisp_Object handler;
570d7624 3777
f5d5eccf 3778 filename = Fexpand_file_name (current_buffer->filename, Qnil);
32f4334d 3779
f5d5eccf
RS
3780 /* If the file name has special constructs in it,
3781 call the corresponding file handler. */
49307295 3782 handler = Ffind_file_name_handler (filename, Qset_visited_file_modtime);
f5d5eccf 3783 if (!NILP (handler))
caf3c431 3784 /* The handler can find the file name the same way we did. */
76c881b0 3785 return call2 (handler, Qset_visited_file_modtime, Qnil);
f5d5eccf
RS
3786 else if (stat (XSTRING (filename)->data, &st) >= 0)
3787 current_buffer->modtime = st.st_mtime;
3788 }
570d7624
JB
3789
3790 return Qnil;
3791}
3792\f
3793Lisp_Object
3794auto_save_error ()
3795{
570d7624 3796 ring_bell ();
1a04498e 3797 message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3798 Fsleep_for (make_number (1), Qnil);
1a04498e 3799 message ("Autosaving...error!for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3800 Fsleep_for (make_number (1), Qnil);
1a04498e 3801 message ("Autosaving...error for %s", XSTRING (current_buffer->name)->data);
de49a6d3 3802 Fsleep_for (make_number (1), Qnil);
570d7624
JB
3803 return Qnil;
3804}
3805
3806Lisp_Object
3807auto_save_1 ()
3808{
3809 unsigned char *fn;
3810 struct stat st;
3811
3812 /* Get visited file's mode to become the auto save file's mode. */
3813 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
3814 /* But make sure we can overwrite it later! */
3815 auto_save_mode_bits = st.st_mode | 0600;
3816 else
3817 auto_save_mode_bits = 0666;
3818
3819 return
3820 Fwrite_region (Qnil, Qnil,
3821 current_buffer->auto_save_file_name,
7204a979 3822 Qnil, Qlambda, Qnil);
570d7624
JB
3823}
3824
e54d3b5d 3825static Lisp_Object
15fa1468
RS
3826do_auto_save_unwind (desc) /* used as unwind-protect function */
3827 Lisp_Object desc;
e54d3b5d 3828{
3be3c08e 3829 auto_saving = 0;
15fa1468 3830 close (XINT (desc));
e54d3b5d
RS
3831 return Qnil;
3832}
3833
570d7624
JB
3834DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
3835 "Auto-save all buffers that need it.\n\
3836This is all buffers that have auto-saving enabled\n\
3837and are changed since last auto-saved.\n\
3838Auto-saving writes the buffer into a file\n\
3839so that your editing is not lost if the system crashes.\n\
012d4cdc
RS
3840This file is not the file you visited; that changes only when you save.\n\
3841Normally we run the normal hook `auto-save-hook' before saving.\n\n\
570d7624 3842Non-nil first argument means do not print any message if successful.\n\
4746118a 3843Non-nil second argument means save only current buffer.")
17857782
JB
3844 (no_message, current_only)
3845 Lisp_Object no_message, current_only;
570d7624
JB
3846{
3847 struct buffer *old = current_buffer, *b;
3848 Lisp_Object tail, buf;
3849 int auto_saved = 0;
3850 char *omessage = echo_area_glyphs;
f05b275b 3851 int omessage_length = echo_area_glyphs_length;
f14b1c68
JB
3852 extern int minibuf_level;
3853 int do_handled_files;
ff4c9993 3854 Lisp_Object oquit;
e54d3b5d 3855 int listdesc;
e54d3b5d
RS
3856 int count = specpdl_ptr - specpdl;
3857 int *ptr;
ff4c9993
RS
3858
3859 /* Ordinarily don't quit within this function,
3860 but don't make it impossible to quit (in case we get hung in I/O). */
3861 oquit = Vquit_flag;
3862 Vquit_flag = Qnil;
570d7624
JB
3863
3864 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
3865 point to non-strings reached from Vbuffer_alist. */
3866
570d7624 3867 if (minibuf_level)
17857782 3868 no_message = Qt;
570d7624 3869
265a9e55 3870 if (!NILP (Vrun_hooks))
570d7624
JB
3871 call1 (Vrun_hooks, intern ("auto-save-hook"));
3872
e54d3b5d
RS
3873 if (STRINGP (Vauto_save_list_file_name))
3874 {
258fd2cb
RS
3875 Lisp_Object listfile;
3876 listfile = Fexpand_file_name (Vauto_save_list_file_name, Qnil);
5e570b75 3877#ifdef DOS_NT
258fd2cb 3878 listdesc = open (XSTRING (listfile)->data,
e54d3b5d
RS
3879 O_WRONLY | O_TRUNC | O_CREAT | O_TEXT,
3880 S_IREAD | S_IWRITE);
5e570b75 3881#else /* not DOS_NT */
258fd2cb 3882 listdesc = creat (XSTRING (listfile)->data, 0666);
5e570b75 3883#endif /* not DOS_NT */
e54d3b5d
RS
3884 }
3885 else
3886 listdesc = -1;
e54d3b5d 3887
3be3c08e
RS
3888 /* Arrange to close that file whether or not we get an error.
3889 Also reset auto_saving to 0. */
15fa1468
RS
3890 if (listdesc >= 0)
3891 record_unwind_protect (do_auto_save_unwind, make_number (listdesc));
e54d3b5d 3892
3be3c08e
RS
3893 auto_saving = 1;
3894
f14b1c68
JB
3895 /* First, save all files which don't have handlers. If Emacs is
3896 crashing, the handlers may tweak what is causing Emacs to crash
3897 in the first place, and it would be a shame if Emacs failed to
3898 autosave perfectly ordinary files because it couldn't handle some
3899 ange-ftp'd file. */
3900 for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
41d86b13 3901 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
f14b1c68
JB
3902 {
3903 buf = XCONS (XCONS (tail)->car)->cdr;
3904 b = XBUFFER (buf);
e54d3b5d
RS
3905
3906 /* Record all the buffers that have auto save mode
258fd2cb
RS
3907 in the special file that lists them. For each of these buffers,
3908 Record visited name (if any) and auto save name. */
93c30b5f 3909 if (STRINGP (b->auto_save_file_name)
e54d3b5d
RS
3910 && listdesc >= 0 && do_handled_files == 0)
3911 {
258fd2cb
RS
3912 if (!NILP (b->filename))
3913 {
3914 write (listdesc, XSTRING (b->filename)->data,
3915 XSTRING (b->filename)->size);
3916 }
3917 write (listdesc, "\n", 1);
e54d3b5d
RS
3918 write (listdesc, XSTRING (b->auto_save_file_name)->data,
3919 XSTRING (b->auto_save_file_name)->size);
3920 write (listdesc, "\n", 1);
3921 }
17857782 3922
f14b1c68
JB
3923 if (!NILP (current_only)
3924 && b != current_buffer)
3925 continue;
e54d3b5d 3926
95385625
RS
3927 /* Don't auto-save indirect buffers.
3928 The base buffer takes care of it. */
3929 if (b->base_buffer)
3930 continue;
3931
f14b1c68
JB
3932 /* Check for auto save enabled
3933 and file changed since last auto save
3934 and file changed since last real save. */
93c30b5f 3935 if (STRINGP (b->auto_save_file_name)
95385625 3936 && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)
f14b1c68 3937 && b->auto_save_modified < BUF_MODIFF (b)
82c2d839
RS
3938 /* -1 means we've turned off autosaving for a while--see below. */
3939 && XINT (b->save_length) >= 0
f14b1c68 3940 && (do_handled_files
49307295
KH
3941 || NILP (Ffind_file_name_handler (b->auto_save_file_name,
3942 Qwrite_region))))
f14b1c68 3943 {
b60247d9
RS
3944 EMACS_TIME before_time, after_time;
3945
3946 EMACS_GET_TIME (before_time);
3947
3948 /* If we had a failure, don't try again for 20 minutes. */
3949 if (b->auto_save_failure_time >= 0
3950 && EMACS_SECS (before_time) - b->auto_save_failure_time < 1200)
3951 continue;
3952
f14b1c68
JB
3953 if ((XFASTINT (b->save_length) * 10
3954 > (BUF_Z (b) - BUF_BEG (b)) * 13)
3955 /* A short file is likely to change a large fraction;
3956 spare the user annoying messages. */
3957 && XFASTINT (b->save_length) > 5000
3958 /* These messages are frequent and annoying for `*mail*'. */
3959 && !EQ (b->filename, Qnil)
3960 && NILP (no_message))
3961 {
3962 /* It has shrunk too much; turn off auto-saving here. */
3963 message ("Buffer %s has shrunk a lot; auto save turned off there",
3964 XSTRING (b->name)->data);
82c2d839
RS
3965 /* Turn off auto-saving until there's a real save,
3966 and prevent any more warnings. */
46283abe 3967 XSETINT (b->save_length, -1);
f14b1c68
JB
3968 Fsleep_for (make_number (1), Qnil);
3969 continue;
3970 }
3971 set_buffer_internal (b);
3972 if (!auto_saved && NILP (no_message))
3973 message1 ("Auto-saving...");
3974 internal_condition_case (auto_save_1, Qt, auto_save_error);
3975 auto_saved++;
3976 b->auto_save_modified = BUF_MODIFF (b);
2acfd7ae 3977 XSETFASTINT (current_buffer->save_length, Z - BEG);
f14b1c68 3978 set_buffer_internal (old);
b60247d9
RS
3979
3980 EMACS_GET_TIME (after_time);
3981
3982 /* If auto-save took more than 60 seconds,
3983 assume it was an NFS failure that got a timeout. */
3984 if (EMACS_SECS (after_time) - EMACS_SECS (before_time) > 60)
3985 b->auto_save_failure_time = EMACS_SECS (after_time);
f14b1c68
JB
3986 }
3987 }
570d7624 3988
b67f2ca5
RS
3989 /* Prevent another auto save till enough input events come in. */
3990 record_auto_save ();
570d7624 3991
17857782 3992 if (auto_saved && NILP (no_message))
f05b275b
KH
3993 {
3994 if (omessage)
3995 message2 (omessage, omessage_length);
3996 else
3997 message1 ("Auto-saving...done");
3998 }
570d7624 3999
ff4c9993
RS
4000 Vquit_flag = oquit;
4001
e54d3b5d 4002 unbind_to (count, Qnil);
570d7624
JB
4003 return Qnil;
4004}
4005
4006DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
4007 Sset_buffer_auto_saved, 0, 0, 0,
4008 "Mark current buffer as auto-saved with its current text.\n\
4009No auto-save file will be written until the buffer changes again.")
4010 ()
4011{
4012 current_buffer->auto_save_modified = MODIFF;
2acfd7ae 4013 XSETFASTINT (current_buffer->save_length, Z - BEG);
b60247d9
RS
4014 current_buffer->auto_save_failure_time = -1;
4015 return Qnil;
4016}
4017
4018DEFUN ("clear-buffer-auto-save-failure", Fclear_buffer_auto_save_failure,
4019 Sclear_buffer_auto_save_failure, 0, 0, 0,
4020 "Clear any record of a recent auto-save failure in the current buffer.")
4021 ()
4022{
4023 current_buffer->auto_save_failure_time = -1;
570d7624
JB
4024 return Qnil;
4025}
4026
4027DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
4028 0, 0, 0,
4029 "Return t if buffer has been auto-saved since last read in or saved.")
4030 ()
4031{
95385625 4032 return (SAVE_MODIFF < current_buffer->auto_save_modified) ? Qt : Qnil;
570d7624
JB
4033}
4034\f
4035/* Reading and completing file names */
4036extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
4037
6e710ae5
RS
4038/* In the string VAL, change each $ to $$ and return the result. */
4039
4040static Lisp_Object
4041double_dollars (val)
4042 Lisp_Object val;
4043{
4044 register unsigned char *old, *new;
4045 register int n;
4046 int osize, count;
4047
4048 osize = XSTRING (val)->size;
4049 /* Quote "$" as "$$" to get it past substitute-in-file-name */
4050 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
4051 if (*old++ == '$') count++;
4052 if (count > 0)
4053 {
4054 old = XSTRING (val)->data;
4055 val = Fmake_string (make_number (osize + count), make_number (0));
4056 new = XSTRING (val)->data;
4057 for (n = osize; n > 0; n--)
4058 if (*old != '$')
4059 *new++ = *old++;
4060 else
4061 {
4062 *new++ = '$';
4063 *new++ = '$';
4064 old++;
4065 }
4066 }
4067 return val;
4068}
4069
570d7624
JB
4070DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
4071 3, 3, 0,
4072 "Internal subroutine for read-file-name. Do not call this.")
4073 (string, dir, action)
4074 Lisp_Object string, dir, action;
4075 /* action is nil for complete, t for return list of completions,
4076 lambda for verify final value */
4077{
4078 Lisp_Object name, specdir, realdir, val, orig_string;
09121adc 4079 int changed;
8ce069f5 4080 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
09121adc
RS
4081
4082 realdir = dir;
4083 name = string;
4084 orig_string = Qnil;
4085 specdir = Qnil;
4086 changed = 0;
4087 /* No need to protect ACTION--we only compare it with t and nil. */
8ce069f5 4088 GCPRO5 (string, realdir, name, specdir, orig_string);
570d7624
JB
4089
4090 if (XSTRING (string)->size == 0)
4091 {
570d7624 4092 if (EQ (action, Qlambda))
09121adc
RS
4093 {
4094 UNGCPRO;
4095 return Qnil;
4096 }
570d7624
JB
4097 }
4098 else
4099 {
4100 orig_string = string;
4101 string = Fsubstitute_in_file_name (string);
09121adc 4102 changed = NILP (Fstring_equal (string, orig_string));
570d7624 4103 name = Ffile_name_nondirectory (string);
09121adc
RS
4104 val = Ffile_name_directory (string);
4105 if (! NILP (val))
4106 realdir = Fexpand_file_name (val, realdir);
570d7624
JB
4107 }
4108
265a9e55 4109 if (NILP (action))
570d7624
JB
4110 {
4111 specdir = Ffile_name_directory (string);
4112 val = Ffile_name_completion (name, realdir);
09121adc 4113 UNGCPRO;
93c30b5f 4114 if (!STRINGP (val))
570d7624 4115 {
09121adc 4116 if (changed)
dbd04e01 4117 return double_dollars (string);
09121adc 4118 return val;
570d7624
JB
4119 }
4120
265a9e55 4121 if (!NILP (specdir))
570d7624
JB
4122 val = concat2 (specdir, val);
4123#ifndef VMS
6e710ae5
RS
4124 return double_dollars (val);
4125#else /* not VMS */
09121adc 4126 return val;
6e710ae5 4127#endif /* not VMS */
570d7624 4128 }
09121adc 4129 UNGCPRO;
570d7624
JB
4130
4131 if (EQ (action, Qt))
4132 return Ffile_name_all_completions (name, realdir);
4133 /* Only other case actually used is ACTION = lambda */
4134#ifdef VMS
4135 /* Supposedly this helps commands such as `cd' that read directory names,
4136 but can someone explain how it helps them? -- RMS */
4137 if (XSTRING (name)->size == 0)
4138 return Qt;
4139#endif /* VMS */
4140 return Ffile_exists_p (string);
4141}
4142
4143DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
4144 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
4145Value is not expanded---you must call `expand-file-name' yourself.\n\
4146Default name to DEFAULT if user enters a null string.\n\
3beeedfe
RS
4147 (If DEFAULT is omitted, the visited file name is used,\n\
4148 except that if INITIAL is specified, that combined with DIR is used.)\n\
570d7624
JB
4149Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
4150 Non-nil and non-t means also require confirmation after completion.\n\
4151Fifth arg INITIAL specifies text to start with.\n\
4152DIR defaults to current buffer's directory default.")
4153 (prompt, dir, defalt, mustmatch, initial)
4154 Lisp_Object prompt, dir, defalt, mustmatch, initial;
4155{
85b5fe07 4156 Lisp_Object val, insdef, insdef1, tem;
570d7624
JB
4157 struct gcpro gcpro1, gcpro2;
4158 register char *homedir;
4159 int count;
4160
265a9e55 4161 if (NILP (dir))
570d7624 4162 dir = current_buffer->directory;
265a9e55 4163 if (NILP (defalt))
3beeedfe
RS
4164 {
4165 if (! NILP (initial))
4166 defalt = Fexpand_file_name (initial, dir);
4167 else
4168 defalt = current_buffer->filename;
4169 }
570d7624
JB
4170
4171 /* If dir starts with user's homedir, change that to ~. */
4172 homedir = (char *) egetenv ("HOME");
4173 if (homedir != 0
93c30b5f 4174 && STRINGP (dir)
570d7624 4175 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
5e570b75 4176 && IS_DIRECTORY_SEP (XSTRING (dir)->data[strlen (homedir)]))
570d7624
JB
4177 {
4178 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
4179 XSTRING (dir)->size - strlen (homedir) + 1);
4180 XSTRING (dir)->data[0] = '~';
4181 }
4182
4183 if (insert_default_directory)
4184 {
4185 insdef = dir;
265a9e55 4186 if (!NILP (initial))
570d7624 4187 {
15c65264 4188 Lisp_Object args[2], pos;
570d7624
JB
4189
4190 args[0] = insdef;
4191 args[1] = initial;
4192 insdef = Fconcat (2, args);
351bd676 4193 pos = make_number (XSTRING (double_dollars (dir))->size);
6e710ae5 4194 insdef1 = Fcons (double_dollars (insdef), pos);
570d7624 4195 }
6e710ae5
RS
4196 else
4197 insdef1 = double_dollars (insdef);
570d7624 4198 }
351bd676
KH
4199 else if (!NILP (initial))
4200 {
4201 insdef = initial;
4202 insdef1 = Fcons (double_dollars (insdef), 0);
4203 }
570d7624 4204 else
85b5fe07 4205 insdef = Qnil, insdef1 = Qnil;
570d7624
JB
4206
4207#ifdef VMS
4208 count = specpdl_ptr - specpdl;
4209 specbind (intern ("completion-ignore-case"), Qt);
4210#endif
4211
4212 GCPRO2 (insdef, defalt);
4213 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
85b5fe07 4214 dir, mustmatch, insdef1,
15c65264 4215 Qfile_name_history);
570d7624
JB
4216
4217#ifdef VMS
4218 unbind_to (count, Qnil);
4219#endif
4220
4221 UNGCPRO;
265a9e55 4222 if (NILP (val))
570d7624
JB
4223 error ("No file name specified");
4224 tem = Fstring_equal (val, insdef);
265a9e55 4225 if (!NILP (tem) && !NILP (defalt))
570d7624 4226 return defalt;
b320926a 4227 if (XSTRING (val)->size == 0 && NILP (insdef))
d9bc1c99
RS
4228 {
4229 if (!NILP (defalt))
4230 return defalt;
4231 else
4232 error ("No default file name");
4233 }
570d7624
JB
4234 return Fsubstitute_in_file_name (val);
4235}
4236
5e570b75 4237#if 0 /* Old version */
570d7624 4238DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
0de25302
KH
4239 /* Don't confuse make-docfile by having two doc strings for this function.
4240 make-docfile does not pay attention to #if, for good reason! */
4241 0)
570d7624
JB
4242 (prompt, dir, defalt, mustmatch, initial)
4243 Lisp_Object prompt, dir, defalt, mustmatch, initial;
4244{
4245 Lisp_Object val, insdef, tem;
4246 struct gcpro gcpro1, gcpro2;
4247 register char *homedir;
4248 int count;
4249
265a9e55 4250 if (NILP (dir))
570d7624 4251 dir = current_buffer->directory;
265a9e55 4252 if (NILP (defalt))
570d7624
JB
4253 defalt = current_buffer->filename;
4254
4255 /* If dir starts with user's homedir, change that to ~. */
4256 homedir = (char *) egetenv ("HOME");
4257 if (homedir != 0
93c30b5f 4258 && STRINGP (dir)
570d7624
JB
4259 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
4260 && XSTRING (dir)->data[strlen (homedir)] == '/')
4261 {
4262 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
4263 XSTRING (dir)->size - strlen (homedir) + 1);
4264 XSTRING (dir)->data[0] = '~';
4265 }
4266
265a9e55 4267 if (!NILP (initial))
570d7624
JB
4268 insdef = initial;
4269 else if (insert_default_directory)
4270 insdef = dir;
4271 else
4272 insdef = build_string ("");
4273
4274#ifdef VMS
4275 count = specpdl_ptr - specpdl;
4276 specbind (intern ("completion-ignore-case"), Qt);
4277#endif
4278
4279 GCPRO2 (insdef, defalt);
4280 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
4281 dir, mustmatch,
15c65264
RS
4282 insert_default_directory ? insdef : Qnil,
4283 Qfile_name_history);
570d7624
JB
4284
4285#ifdef VMS
4286 unbind_to (count, Qnil);
4287#endif
4288
4289 UNGCPRO;
265a9e55 4290 if (NILP (val))
570d7624
JB
4291 error ("No file name specified");
4292 tem = Fstring_equal (val, insdef);
265a9e55 4293 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
4294 return defalt;
4295 return Fsubstitute_in_file_name (val);
4296}
4297#endif /* Old version */
4298\f
4299syms_of_fileio ()
4300{
0bf2eed2 4301 Qexpand_file_name = intern ("expand-file-name");
273e0829 4302 Qsubstitute_in_file_name = intern ("substitute-in-file-name");
0bf2eed2
RS
4303 Qdirectory_file_name = intern ("directory-file-name");
4304 Qfile_name_directory = intern ("file-name-directory");
4305 Qfile_name_nondirectory = intern ("file-name-nondirectory");
642ef245 4306 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
0bf2eed2 4307 Qfile_name_as_directory = intern ("file-name-as-directory");
32f4334d 4308 Qcopy_file = intern ("copy-file");
a6e6e718 4309 Qmake_directory_internal = intern ("make-directory-internal");
32f4334d
RS
4310 Qdelete_directory = intern ("delete-directory");
4311 Qdelete_file = intern ("delete-file");
4312 Qrename_file = intern ("rename-file");
4313 Qadd_name_to_file = intern ("add-name-to-file");
4314 Qmake_symbolic_link = intern ("make-symbolic-link");
4315 Qfile_exists_p = intern ("file-exists-p");
4316 Qfile_executable_p = intern ("file-executable-p");
4317 Qfile_readable_p = intern ("file-readable-p");
4318 Qfile_symlink_p = intern ("file-symlink-p");
4319 Qfile_writable_p = intern ("file-writable-p");
4320 Qfile_directory_p = intern ("file-directory-p");
adedc71d 4321 Qfile_regular_p = intern ("file-regular-p");
32f4334d
RS
4322 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
4323 Qfile_modes = intern ("file-modes");
4324 Qset_file_modes = intern ("set-file-modes");
4325 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
4326 Qinsert_file_contents = intern ("insert-file-contents");
4327 Qwrite_region = intern ("write-region");
4328 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3ec46acd 4329 Qset_visited_file_modtime = intern ("set-visited-file-modtime");
32f4334d 4330
642ef245 4331 staticpro (&Qexpand_file_name);
273e0829 4332 staticpro (&Qsubstitute_in_file_name);
642ef245
JB
4333 staticpro (&Qdirectory_file_name);
4334 staticpro (&Qfile_name_directory);
4335 staticpro (&Qfile_name_nondirectory);
4336 staticpro (&Qunhandled_file_name_directory);
4337 staticpro (&Qfile_name_as_directory);
15c65264 4338 staticpro (&Qcopy_file);
c34b559d 4339 staticpro (&Qmake_directory_internal);
15c65264
RS
4340 staticpro (&Qdelete_directory);
4341 staticpro (&Qdelete_file);
4342 staticpro (&Qrename_file);
4343 staticpro (&Qadd_name_to_file);
4344 staticpro (&Qmake_symbolic_link);
4345 staticpro (&Qfile_exists_p);
4346 staticpro (&Qfile_executable_p);
4347 staticpro (&Qfile_readable_p);
4348 staticpro (&Qfile_symlink_p);
4349 staticpro (&Qfile_writable_p);
4350 staticpro (&Qfile_directory_p);
adedc71d 4351 staticpro (&Qfile_regular_p);
15c65264
RS
4352 staticpro (&Qfile_accessible_directory_p);
4353 staticpro (&Qfile_modes);
4354 staticpro (&Qset_file_modes);
4355 staticpro (&Qfile_newer_than_file_p);
4356 staticpro (&Qinsert_file_contents);
4357 staticpro (&Qwrite_region);
4358 staticpro (&Qverify_visited_file_modtime);
642ef245
JB
4359
4360 Qfile_name_history = intern ("file-name-history");
4361 Fset (Qfile_name_history, Qnil);
15c65264
RS
4362 staticpro (&Qfile_name_history);
4363
570d7624
JB
4364 Qfile_error = intern ("file-error");
4365 staticpro (&Qfile_error);
4366 Qfile_already_exists = intern("file-already-exists");
4367 staticpro (&Qfile_already_exists);
4368
5e570b75 4369#ifdef DOS_NT
4c3c22f3
RS
4370 Qfind_buffer_file_type = intern ("find-buffer-file-type");
4371 staticpro (&Qfind_buffer_file_type);
5e570b75 4372#endif /* DOS_NT */
4c3c22f3 4373
0d420e88 4374 DEFVAR_LISP ("auto-save-file-format", &Vauto_save_file_format,
824a483f 4375 "*Format in which to write auto-save files.\n\
0d420e88
BG
4376Should be a list of symbols naming formats that are defined in `format-alist'.\n\
4377If it is t, which is the default, auto-save files are written in the\n\
4378same format as a regular save would use.");
4379 Vauto_save_file_format = Qt;
4380
4381 Qformat_decode = intern ("format-decode");
4382 staticpro (&Qformat_decode);
4383 Qformat_annotate_function = intern ("format-annotate-function");
4384 staticpro (&Qformat_annotate_function);
4385
d6a3cc15
RS
4386 Qcar_less_than_car = intern ("car-less-than-car");
4387 staticpro (&Qcar_less_than_car);
4388
570d7624
JB
4389 Fput (Qfile_error, Qerror_conditions,
4390 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
4391 Fput (Qfile_error, Qerror_message,
4392 build_string ("File error"));
4393
4394 Fput (Qfile_already_exists, Qerror_conditions,
4395 Fcons (Qfile_already_exists,
4396 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
4397 Fput (Qfile_already_exists, Qerror_message,
4398 build_string ("File already exists"));
4399
4400 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
4401 "*Non-nil means when reading a filename start with default dir in minibuffer.");
4402 insert_default_directory = 1;
4403
4404 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
4405 "*Non-nil means write new files with record format `stmlf'.\n\
4406nil means use format `var'. This variable is meaningful only on VMS.");
4407 vms_stmlf_recfm = 0;
4408
1d1826db
RS
4409 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
4410 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
4411If a file name matches REGEXP, then all I/O on that file is done by calling\n\
4412HANDLER.\n\
4413\n\
4414The first argument given to HANDLER is the name of the I/O primitive\n\
4415to be handled; the remaining arguments are the arguments that were\n\
4416passed to that primitive. For example, if you do\n\
4417 (file-exists-p FILENAME)\n\
4418and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
642ef245
JB
4419 (funcall HANDLER 'file-exists-p FILENAME)\n\
4420The function `find-file-name-handler' checks this list for a handler\n\
4421for its argument.");
09121adc
RS
4422 Vfile_name_handler_alist = Qnil;
4423
d6a3cc15 4424 DEFVAR_LISP ("after-insert-file-functions", &Vafter_insert_file_functions,
246cfea5
RS
4425 "A list of functions to be called at the end of `insert-file-contents'.\n\
4426Each is passed one argument, the number of bytes inserted. It should return\n\
4427the new byte count, and leave point the same. If `insert-file-contents' is\n\
4428intercepted by a handler from `file-name-handler-alist', that handler is\n\
d6a3cc15
RS
4429responsible for calling the after-insert-file-functions if appropriate.");
4430 Vafter_insert_file_functions = Qnil;
4431
4432 DEFVAR_LISP ("write-region-annotate-functions", &Vwrite_region_annotate_functions,
246cfea5
RS
4433 "A list of functions to be called at the start of `write-region'.\n\
4434Each is passed two arguments, START and END as for `write-region'. It should\n\
4435return a list of pairs (POSITION . STRING) of strings to be effectively\n\
4436inserted at the specified positions of the file being written (1 means to\n\
4437insert before the first byte written). The POSITIONs must be sorted into\n\
4438increasing order. If there are several functions in the list, the several\n\
d6a3cc15
RS
4439lists are merged destructively.");
4440 Vwrite_region_annotate_functions = Qnil;
4441
6fc6f94b
RS
4442 DEFVAR_LISP ("write-region-annotations-so-far",
4443 &Vwrite_region_annotations_so_far,
4444 "When an annotation function is called, this holds the previous annotations.\n\
4445These are the annotations made by other annotation functions\n\
4446that were already called. See also `write-region-annotate-functions'.");
4447 Vwrite_region_annotations_so_far = Qnil;
4448
82c2d839 4449 DEFVAR_LISP ("inhibit-file-name-handlers", &Vinhibit_file_name_handlers,
268466ed 4450 "A list of file name handlers that temporarily should not be used.\n\
e3e86241 4451This applies only to the operation `inhibit-file-name-operation'.");
82c2d839
RS
4452 Vinhibit_file_name_handlers = Qnil;
4453
a65970a0
RS
4454 DEFVAR_LISP ("inhibit-file-name-operation", &Vinhibit_file_name_operation,
4455 "The operation for which `inhibit-file-name-handlers' is applicable.");
4456 Vinhibit_file_name_operation = Qnil;
4457
e54d3b5d 4458 DEFVAR_LISP ("auto-save-list-file-name", &Vauto_save_list_file_name,
51931aca
KH
4459 "File name in which we write a list of all auto save file names.\n\
4460This variable is initialized automatically from `auto-save-list-file-prefix'\n\
4461shortly after Emacs reads your `.emacs' file, if you have not yet given it\n\
4462a non-nil value.");
e54d3b5d
RS
4463 Vauto_save_list_file_name = Qnil;
4464
642ef245 4465 defsubr (&Sfind_file_name_handler);
570d7624
JB
4466 defsubr (&Sfile_name_directory);
4467 defsubr (&Sfile_name_nondirectory);
642ef245 4468 defsubr (&Sunhandled_file_name_directory);
570d7624
JB
4469 defsubr (&Sfile_name_as_directory);
4470 defsubr (&Sdirectory_file_name);
4471 defsubr (&Smake_temp_name);
4472 defsubr (&Sexpand_file_name);
4473 defsubr (&Ssubstitute_in_file_name);
4474 defsubr (&Scopy_file);
9bbe01fb 4475 defsubr (&Smake_directory_internal);
aa734e17 4476 defsubr (&Sdelete_directory);
570d7624
JB
4477 defsubr (&Sdelete_file);
4478 defsubr (&Srename_file);
4479 defsubr (&Sadd_name_to_file);
4480#ifdef S_IFLNK
4481 defsubr (&Smake_symbolic_link);
4482#endif /* S_IFLNK */
4483#ifdef VMS
4484 defsubr (&Sdefine_logical_name);
4485#endif /* VMS */
4486#ifdef HPUX_NET
4487 defsubr (&Ssysnetunam);
4488#endif /* HPUX_NET */
4489 defsubr (&Sfile_name_absolute_p);
4490 defsubr (&Sfile_exists_p);
4491 defsubr (&Sfile_executable_p);
4492 defsubr (&Sfile_readable_p);
4493 defsubr (&Sfile_writable_p);
4494 defsubr (&Sfile_symlink_p);
4495 defsubr (&Sfile_directory_p);
b72dea2a 4496 defsubr (&Sfile_accessible_directory_p);
f793dc6c 4497 defsubr (&Sfile_regular_p);
570d7624
JB
4498 defsubr (&Sfile_modes);
4499 defsubr (&Sset_file_modes);
c24e9a53
RS
4500 defsubr (&Sset_default_file_modes);
4501 defsubr (&Sdefault_file_modes);
570d7624
JB
4502 defsubr (&Sfile_newer_than_file_p);
4503 defsubr (&Sinsert_file_contents);
4504 defsubr (&Swrite_region);
d6a3cc15 4505 defsubr (&Scar_less_than_car);
570d7624
JB
4506 defsubr (&Sverify_visited_file_modtime);
4507 defsubr (&Sclear_visited_file_modtime);
f5d5eccf 4508 defsubr (&Svisited_file_modtime);
570d7624
JB
4509 defsubr (&Sset_visited_file_modtime);
4510 defsubr (&Sdo_auto_save);
4511 defsubr (&Sset_buffer_auto_saved);
b60247d9 4512 defsubr (&Sclear_buffer_auto_save_failure);
570d7624
JB
4513 defsubr (&Srecent_auto_save_p);
4514
4515 defsubr (&Sread_file_name_internal);
4516 defsubr (&Sread_file_name);
85ffea93 4517
483a2e10 4518#ifdef unix
85ffea93 4519 defsubr (&Sunix_sync);
483a2e10 4520#endif
570d7624 4521}