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