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