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