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