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