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