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