(kill-append): Doc fix.
[bpt/emacs.git] / src / fileio.c
CommitLineData
570d7624 1/* File IO for GNU Emacs.
4746118a 2 Copyright (C) 1985, 1986, 1987, 1988, 1992 Free Software Foundation, Inc.
570d7624
JB
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
4746118a 8the Free Software Foundation; either version 2, or (at your option)
570d7624
JB
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
ffd56f97 20#include "config.h"
570d7624
JB
21
22#include <sys/types.h>
23#include <sys/stat.h>
bfb61299
JB
24
25#ifdef VMS
de5bf5d3 26#include "vms-pwd.h"
bfb61299 27#else
570d7624 28#include <pwd.h>
bfb61299
JB
29#endif
30
570d7624 31#include <ctype.h>
bfb61299
JB
32
33#ifdef VMS
34#include "dir.h"
35#include <perror.h>
36#include <stddef.h>
37#include <string.h>
bfb61299
JB
38#endif
39
570d7624
JB
40#include <errno.h>
41
bfb61299 42#ifndef vax11c
570d7624
JB
43extern int errno;
44extern char *sys_errlist[];
45extern int sys_nerr;
46#endif
47
48#define err_str(a) ((a) < sys_nerr ? sys_errlist[a] : "unknown error")
49
50#ifdef APOLLO
51#include <sys/time.h>
52#endif
53
570d7624 54#include "lisp.h"
8d4e077b 55#include "intervals.h"
570d7624
JB
56#include "buffer.h"
57#include "window.h"
58
59#ifdef VMS
570d7624
JB
60#include <file.h>
61#include <rmsdef.h>
62#include <fab.h>
63#include <nam.h>
64#endif
65
de5bf5d3 66#include "systime.h"
570d7624
JB
67
68#ifdef HPUX
69#include <netio.h>
9b7828a5 70#ifndef HPUX8
570d7624
JB
71#include <errnet.h>
72#endif
9b7828a5 73#endif
570d7624
JB
74
75#ifndef O_WRONLY
76#define O_WRONLY 1
77#endif
78
79#define min(a, b) ((a) < (b) ? (a) : (b))
80#define max(a, b) ((a) > (b) ? (a) : (b))
81
82/* Nonzero during writing of auto-save files */
83int auto_saving;
84
85/* Set by auto_save_1 to mode of original file so Fwrite_region will create
86 a new file with the same mode as the original */
87int auto_save_mode_bits;
88
32f4334d
RS
89/* Alist of elements (REGEXP . HANDLER) for file names
90 whose I/O is done with a special handler. */
91Lisp_Object Vfile_name_handler_alist;
92
570d7624
JB
93/* Nonzero means, when reading a filename in the minibuffer,
94 start out by inserting the default directory into the minibuffer. */
95int insert_default_directory;
96
97/* On VMS, nonzero means write new files with record format stmlf.
98 Zero means use var format. */
99int vms_stmlf_recfm;
100
101Lisp_Object Qfile_error, Qfile_already_exists;
102
15c65264
RS
103Lisp_Object Qfile_name_history;
104
570d7624
JB
105report_file_error (string, data)
106 char *string;
107 Lisp_Object data;
108{
109 Lisp_Object errstring;
110
111 if (errno >= 0 && errno < sys_nerr)
112 errstring = build_string (sys_errlist[errno]);
113 else
114 errstring = build_string ("undocumented error code");
115
116 /* System error messages are capitalized. Downcase the initial
117 unless it is followed by a slash. */
118 if (XSTRING (errstring)->data[1] != '/')
119 XSTRING (errstring)->data[0] = DOWNCASE (XSTRING (errstring)->data[0]);
120
121 while (1)
122 Fsignal (Qfile_error,
123 Fcons (build_string (string), Fcons (errstring, data)));
124}
b5148e85
RS
125
126close_file_unwind (fd)
127 Lisp_Object fd;
128{
129 close (XFASTINT (fd));
130}
570d7624 131\f
0bf2eed2
RS
132Lisp_Object Qexpand_file_name;
133Lisp_Object Qdirectory_file_name;
134Lisp_Object Qfile_name_directory;
135Lisp_Object Qfile_name_nondirectory;
642ef245 136Lisp_Object Qunhandled_file_name_directory;
0bf2eed2 137Lisp_Object Qfile_name_as_directory;
32f4334d
RS
138Lisp_Object Qcopy_file;
139Lisp_Object Qmake_directory;
140Lisp_Object Qdelete_directory;
141Lisp_Object Qdelete_file;
142Lisp_Object Qrename_file;
143Lisp_Object Qadd_name_to_file;
144Lisp_Object Qmake_symbolic_link;
145Lisp_Object Qfile_exists_p;
146Lisp_Object Qfile_executable_p;
147Lisp_Object Qfile_readable_p;
148Lisp_Object Qfile_symlink_p;
149Lisp_Object Qfile_writable_p;
150Lisp_Object Qfile_directory_p;
151Lisp_Object Qfile_accessible_directory_p;
152Lisp_Object Qfile_modes;
153Lisp_Object Qset_file_modes;
154Lisp_Object Qfile_newer_than_file_p;
155Lisp_Object Qinsert_file_contents;
156Lisp_Object Qwrite_region;
157Lisp_Object Qverify_visited_file_modtime;
158
642ef245
JB
159DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 1, 1, 0,
160 "Return FILENAME's handler function, if its syntax is handled specially.\n\
161Otherwise, return nil.\n\
162A file name is handled if one of the regular expressions in\n\
163`file-name-handler-alist' matches it.")
164 (filename)
165 Lisp_Object filename;
32f4334d 166{
642ef245
JB
167 /* This function must not munge the match data. */
168
32f4334d 169 Lisp_Object chain;
3eac9910 170 for (chain = Vfile_name_handler_alist; XTYPE (chain) == Lisp_Cons;
32f4334d
RS
171 chain = XCONS (chain)->cdr)
172 {
173 Lisp_Object elt;
174 elt = XCONS (chain)->car;
175 if (XTYPE (elt) == Lisp_Cons)
176 {
177 Lisp_Object string;
178 string = XCONS (elt)->car;
179 if (XTYPE (string) == Lisp_String
09121adc 180 && fast_string_match (string, filename) >= 0)
32f4334d
RS
181 return XCONS (elt)->cdr;
182 }
642ef245
JB
183
184 QUIT;
32f4334d
RS
185 }
186 return Qnil;
187}
188\f
570d7624
JB
189DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory,
190 1, 1, 0,
191 "Return the directory component in file name NAME.\n\
192Return nil if NAME does not include a directory.\n\
193Otherwise return a directory spec.\n\
194Given a Unix syntax file name, returns a string ending in slash;\n\
195on VMS, perhaps instead a string ending in `:', `]' or `>'.")
196 (file)
197 Lisp_Object file;
198{
199 register unsigned char *beg;
200 register unsigned char *p;
0bf2eed2 201 Lisp_Object handler;
570d7624
JB
202
203 CHECK_STRING (file, 0);
204
0bf2eed2
RS
205 /* If the file name has special constructs in it,
206 call the corresponding file handler. */
642ef245 207 handler = Ffind_file_name_handler (file);
0bf2eed2
RS
208 if (!NILP (handler))
209 return call2 (handler, Qfile_name_directory, file);
210
570d7624
JB
211 beg = XSTRING (file)->data;
212 p = beg + XSTRING (file)->size;
213
214 while (p != beg && p[-1] != '/'
215#ifdef VMS
216 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
217#endif /* VMS */
218 ) p--;
219
220 if (p == beg)
221 return Qnil;
222 return make_string (beg, p - beg);
223}
224
225DEFUN ("file-name-nondirectory", Ffile_name_nondirectory, Sfile_name_nondirectory,
226 1, 1, 0,
227 "Return file name NAME sans its directory.\n\
228For example, in a Unix-syntax file name,\n\
229this is everything after the last slash,\n\
230or the entire name if it contains no slash.")
231 (file)
232 Lisp_Object file;
233{
234 register unsigned char *beg, *p, *end;
0bf2eed2 235 Lisp_Object handler;
570d7624
JB
236
237 CHECK_STRING (file, 0);
238
0bf2eed2
RS
239 /* If the file name has special constructs in it,
240 call the corresponding file handler. */
642ef245 241 handler = Ffind_file_name_handler (file);
0bf2eed2
RS
242 if (!NILP (handler))
243 return call2 (handler, Qfile_name_nondirectory, file);
244
570d7624
JB
245 beg = XSTRING (file)->data;
246 end = p = beg + XSTRING (file)->size;
247
248 while (p != beg && p[-1] != '/'
249#ifdef VMS
250 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
251#endif /* VMS */
252 ) p--;
253
254 return make_string (p, end - p);
255}
642ef245
JB
256
257DEFUN ("unhandled-file-name-directory", Funhandled_file_name_directory, Sunhandled_file_name_directory, 1, 1, 0,
258 "Return a directly usable directory name somehow associated with FILENAME.\n\
259A `directly usable' directory name is one that may be used without the\n\
260intervention of any file handler.\n\
261If FILENAME is a directly usable file itself, return\n\
262(file-name-directory FILENAME).\n\
263The `call-process' and `start-process' functions use this function to\n\
264get a current directory to run processes in.")
265 (filename)
266 Lisp_Object filename;
267{
268 Lisp_Object handler;
269
270 /* If the file name has special constructs in it,
271 call the corresponding file handler. */
272 handler = Ffind_file_name_handler (filename);
273 if (!NILP (handler))
274 return call2 (handler, Qunhandled_file_name_directory, filename);
275
276 return Ffile_name_directory (filename);
277}
278
570d7624
JB
279\f
280char *
281file_name_as_directory (out, in)
282 char *out, *in;
283{
284 int size = strlen (in) - 1;
285
286 strcpy (out, in);
287
288#ifdef VMS
289 /* Is it already a directory string? */
290 if (in[size] == ':' || in[size] == ']' || in[size] == '>')
291 return out;
292 /* Is it a VMS directory file name? If so, hack VMS syntax. */
293 else if (! index (in, '/')
294 && ((size > 3 && ! strcmp (&in[size - 3], ".DIR"))
295 || (size > 3 && ! strcmp (&in[size - 3], ".dir"))
296 || (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4)
297 || ! strncmp (&in[size - 5], ".dir", 4))
298 && (in[size - 1] == '.' || in[size - 1] == ';')
299 && in[size] == '1')))
300 {
301 register char *p, *dot;
302 char brack;
303
304 /* x.dir -> [.x]
305 dir:x.dir --> dir:[x]
306 dir:[x]y.dir --> dir:[x.y] */
307 p = in + size;
308 while (p != in && *p != ':' && *p != '>' && *p != ']') p--;
309 if (p != in)
310 {
311 strncpy (out, in, p - in);
312 out[p - in] = '\0';
313 if (*p == ':')
314 {
315 brack = ']';
316 strcat (out, ":[");
317 }
318 else
319 {
320 brack = *p;
321 strcat (out, ".");
322 }
323 p++;
324 }
325 else
326 {
327 brack = ']';
328 strcpy (out, "[.");
329 }
bfb61299
JB
330 dot = index (p, '.');
331 if (dot)
570d7624
JB
332 {
333 /* blindly remove any extension */
334 size = strlen (out) + (dot - p);
335 strncat (out, p, dot - p);
336 }
337 else
338 {
339 strcat (out, p);
340 size = strlen (out);
341 }
342 out[size++] = brack;
343 out[size] = '\0';
344 }
345#else /* not VMS */
346 /* For Unix syntax, Append a slash if necessary */
347 if (out[size] != '/')
348 strcat (out, "/");
349#endif /* not VMS */
350 return out;
351}
352
353DEFUN ("file-name-as-directory", Ffile_name_as_directory,
354 Sfile_name_as_directory, 1, 1, 0,
355 "Return a string representing file FILENAME interpreted as a directory.\n\
356This operation exists because a directory is also a file, but its name as\n\
357a directory is different from its name as a file.\n\
358The result can be used as the value of `default-directory'\n\
359or passed as second argument to `expand-file-name'.\n\
360For a Unix-syntax file name, just appends a slash.\n\
361On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
362 (file)
363 Lisp_Object file;
364{
365 char *buf;
0bf2eed2 366 Lisp_Object handler;
570d7624
JB
367
368 CHECK_STRING (file, 0);
265a9e55 369 if (NILP (file))
570d7624 370 return Qnil;
0bf2eed2
RS
371
372 /* If the file name has special constructs in it,
373 call the corresponding file handler. */
642ef245 374 handler = Ffind_file_name_handler (file);
0bf2eed2
RS
375 if (!NILP (handler))
376 return call2 (handler, Qfile_name_as_directory, file);
377
570d7624
JB
378 buf = (char *) alloca (XSTRING (file)->size + 10);
379 return build_string (file_name_as_directory (buf, XSTRING (file)->data));
380}
381\f
382/*
383 * Convert from directory name to filename.
384 * On VMS:
385 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
386 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
387 * On UNIX, it's simple: just make sure there is a terminating /
388
389 * Value is nonzero if the string output is different from the input.
390 */
391
392directory_file_name (src, dst)
393 char *src, *dst;
394{
395 long slen;
396#ifdef VMS
397 long rlen;
398 char * ptr, * rptr;
399 char bracket;
400 struct FAB fab = cc$rms_fab;
401 struct NAM nam = cc$rms_nam;
402 char esa[NAM$C_MAXRSS];
403#endif /* VMS */
404
405 slen = strlen (src);
406#ifdef VMS
407 if (! index (src, '/')
408 && (src[slen - 1] == ']'
409 || src[slen - 1] == ':'
410 || src[slen - 1] == '>'))
411 {
412 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
413 fab.fab$l_fna = src;
414 fab.fab$b_fns = slen;
415 fab.fab$l_nam = &nam;
416 fab.fab$l_fop = FAB$M_NAM;
417
418 nam.nam$l_esa = esa;
419 nam.nam$b_ess = sizeof esa;
420 nam.nam$b_nop |= NAM$M_SYNCHK;
421
422 /* We call SYS$PARSE to handle such things as [--] for us. */
423 if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
424 {
425 slen = nam.nam$b_esl;
426 if (esa[slen - 1] == ';' && esa[slen - 2] == '.')
427 slen -= 2;
428 esa[slen] = '\0';
429 src = esa;
430 }
431 if (src[slen - 1] != ']' && src[slen - 1] != '>')
432 {
433 /* what about when we have logical_name:???? */
434 if (src[slen - 1] == ':')
435 { /* Xlate logical name and see what we get */
436 ptr = strcpy (dst, src); /* upper case for getenv */
437 while (*ptr)
438 {
439 if ('a' <= *ptr && *ptr <= 'z')
440 *ptr -= 040;
441 ptr++;
442 }
443 dst[slen - 1] = 0; /* remove colon */
444 if (!(src = egetenv (dst)))
445 return 0;
446 /* should we jump to the beginning of this procedure?
447 Good points: allows us to use logical names that xlate
448 to Unix names,
449 Bad points: can be a problem if we just translated to a device
450 name...
451 For now, I'll punt and always expect VMS names, and hope for
452 the best! */
453 slen = strlen (src);
454 if (src[slen - 1] != ']' && src[slen - 1] != '>')
455 { /* no recursion here! */
456 strcpy (dst, src);
457 return 0;
458 }
459 }
460 else
461 { /* not a directory spec */
462 strcpy (dst, src);
463 return 0;
464 }
465 }
466 bracket = src[slen - 1];
467
468 /* If bracket is ']' or '>', bracket - 2 is the corresponding
469 opening bracket. */
bfb61299
JB
470 ptr = index (src, bracket - 2);
471 if (ptr == 0)
570d7624
JB
472 { /* no opening bracket */
473 strcpy (dst, src);
474 return 0;
475 }
476 if (!(rptr = rindex (src, '.')))
477 rptr = ptr;
478 slen = rptr - src;
479 strncpy (dst, src, slen);
480 dst[slen] = '\0';
481 if (*rptr == '.')
482 {
483 dst[slen++] = bracket;
484 dst[slen] = '\0';
485 }
486 else
487 {
488 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
489 then translate the device and recurse. */
490 if (dst[slen - 1] == ':'
491 && dst[slen - 2] != ':' /* skip decnet nodes */
492 && strcmp(src + slen, "[000000]") == 0)
493 {
494 dst[slen - 1] = '\0';
495 if ((ptr = egetenv (dst))
496 && (rlen = strlen (ptr) - 1) > 0
497 && (ptr[rlen] == ']' || ptr[rlen] == '>')
498 && ptr[rlen - 1] == '.')
499 {
72b21817
RS
500 char * buf = (char *) alloca (strlen (ptr) + 1);
501 strcpy (buf, ptr);
502 buf[rlen - 1] = ']';
503 buf[rlen] = '\0';
504 return directory_file_name (buf, dst);
570d7624
JB
505 }
506 else
507 dst[slen - 1] = ':';
508 }
509 strcat (dst, "[000000]");
510 slen += 8;
511 }
512 rptr++;
513 rlen = strlen (rptr) - 1;
514 strncat (dst, rptr, rlen);
515 dst[slen + rlen] = '\0';
516 strcat (dst, ".DIR.1");
517 return 1;
518 }
519#endif /* VMS */
520 /* Process as Unix format: just remove any final slash.
521 But leave "/" unchanged; do not change it to "". */
522 strcpy (dst, src);
4746118a 523 if (slen > 1 && dst[slen - 1] == '/')
570d7624
JB
524 dst[slen - 1] = 0;
525 return 1;
526}
527
528DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name,
529 1, 1, 0,
530 "Returns the file name of the directory named DIR.\n\
531This is the name of the file that holds the data for the directory DIR.\n\
532This operation exists because a directory is also a file, but its name as\n\
533a directory is different from its name as a file.\n\
534In Unix-syntax, this function just removes the final slash.\n\
535On VMS, given a VMS-syntax directory name such as \"[X.Y]\",\n\
536it returns a file name such as \"[X]Y.DIR.1\".")
537 (directory)
538 Lisp_Object directory;
539{
540 char *buf;
0bf2eed2 541 Lisp_Object handler;
570d7624
JB
542
543 CHECK_STRING (directory, 0);
544
265a9e55 545 if (NILP (directory))
570d7624 546 return Qnil;
0bf2eed2
RS
547
548 /* If the file name has special constructs in it,
549 call the corresponding file handler. */
642ef245 550 handler = Ffind_file_name_handler (directory);
0bf2eed2
RS
551 if (!NILP (handler))
552 return call2 (handler, Qdirectory_file_name, directory);
553
570d7624
JB
554#ifdef VMS
555 /* 20 extra chars is insufficient for VMS, since we might perform a
556 logical name translation. an equivalence string can be up to 255
557 chars long, so grab that much extra space... - sss */
558 buf = (char *) alloca (XSTRING (directory)->size + 20 + 255);
559#else
560 buf = (char *) alloca (XSTRING (directory)->size + 20);
561#endif
562 directory_file_name (XSTRING (directory)->data, buf);
563 return build_string (buf);
564}
565
566DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0,
567 "Generate temporary file name (string) starting with PREFIX (a string).\n\
568The Emacs process number forms part of the result,\n\
569so there is no danger of generating a name being used by another process.")
570 (prefix)
571 Lisp_Object prefix;
572{
573 Lisp_Object val;
574 val = concat2 (prefix, build_string ("XXXXXX"));
575 mktemp (XSTRING (val)->data);
576 return val;
577}
578\f
579DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
580 "Convert FILENAME to absolute, and canonicalize it.\n\
581Second arg DEFAULT is directory to start with if FILENAME is relative\n\
582 (does not start with slash); if DEFAULT is nil or missing,\n\
583the current buffer's value of default-directory is used.\n\
b72dea2a
JB
584Path components that are `.' are removed, and \n\
585path components followed by `..' are removed, along with the `..' itself;\n\
586note that these simplifications are done without checking the resulting\n\
587paths in the file system.\n\
588An initial `~/' expands to your home directory.\n\
589An initial `~USER/' expands to USER's home directory.\n\
570d7624
JB
590See also the function `substitute-in-file-name'.")
591 (name, defalt)
592 Lisp_Object name, defalt;
593{
594 unsigned char *nm;
595
596 register unsigned char *newdir, *p, *o;
597 int tlen;
598 unsigned char *target;
599 struct passwd *pw;
600 int lose;
601#ifdef VMS
602 unsigned char * colon = 0;
603 unsigned char * close = 0;
604 unsigned char * slash = 0;
605 unsigned char * brack = 0;
606 int lbrack = 0, rbrack = 0;
607 int dots = 0;
608#endif /* VMS */
0bf2eed2 609 Lisp_Object handler;
570d7624
JB
610
611 CHECK_STRING (name, 0);
612
0bf2eed2
RS
613 /* If the file name has special constructs in it,
614 call the corresponding file handler. */
642ef245 615 handler = Ffind_file_name_handler (name);
0bf2eed2 616 if (!NILP (handler))
09121adc 617 return call3 (handler, Qexpand_file_name, name, defalt);
0bf2eed2 618
570d7624
JB
619#ifdef VMS
620 /* Filenames on VMS are always upper case. */
621 name = Fupcase (name);
622#endif
623
624 nm = XSTRING (name)->data;
625
626 /* If nm is absolute, flush ...// and detect /./ and /../.
627 If no /./ or /../ we can return right away. */
628 if (
629 nm[0] == '/'
630#ifdef VMS
631 || index (nm, ':')
632#endif /* VMS */
633 )
634 {
635 p = nm;
636 lose = 0;
637 while (*p)
638 {
c77d647e
JB
639 /* Since we know the path is absolute, we can assume that each
640 element starts with a "/". */
641
642 /* "//" anywhere isn't necessarily hairy; we just start afresh
643 with the second slash. */
570d7624
JB
644 if (p[0] == '/' && p[1] == '/'
645#ifdef APOLLO
646 /* // at start of filename is meaningful on Apollo system */
647 && nm != p
648#endif /* APOLLO */
649 )
650 nm = p + 1;
c77d647e
JB
651
652 /* "~" is hairy as the start of any path element. */
570d7624
JB
653 if (p[0] == '/' && p[1] == '~')
654 nm = p + 1, lose = 1;
c77d647e
JB
655
656 /* "." and ".." are hairy. */
657 if (p[0] == '/'
658 && p[1] == '.'
659 && (p[2] == '/'
660 || p[2] == 0
661 || (p[2] == '.' && (p[3] == '/'
662 || p[3] == 0))))
570d7624
JB
663 lose = 1;
664#ifdef VMS
665 if (p[0] == '\\')
666 lose = 1;
667 if (p[0] == '/') {
668 /* if dev:[dir]/, move nm to / */
669 if (!slash && p > nm && (brack || colon)) {
670 nm = (brack ? brack + 1 : colon + 1);
671 lbrack = rbrack = 0;
672 brack = 0;
673 colon = 0;
674 }
675 slash = p;
676 }
677 if (p[0] == '-')
678#ifndef VMS4_4
679 /* VMS pre V4.4,convert '-'s in filenames. */
680 if (lbrack == rbrack)
681 {
682 if (dots < 2) /* this is to allow negative version numbers */
683 p[0] = '_';
684 }
685 else
686#endif /* VMS4_4 */
687 if (lbrack > rbrack &&
688 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
689 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
690 lose = 1;
691#ifndef VMS4_4
692 else
693 p[0] = '_';
694#endif /* VMS4_4 */
695 /* count open brackets, reset close bracket pointer */
696 if (p[0] == '[' || p[0] == '<')
697 lbrack++, brack = 0;
698 /* count close brackets, set close bracket pointer */
699 if (p[0] == ']' || p[0] == '>')
700 rbrack++, brack = p;
701 /* detect ][ or >< */
702 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
703 lose = 1;
704 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
705 nm = p + 1, lose = 1;
706 if (p[0] == ':' && (colon || slash))
707 /* if dev1:[dir]dev2:, move nm to dev2: */
708 if (brack)
709 {
710 nm = brack + 1;
711 brack = 0;
712 }
713 /* if /pathname/dev:, move nm to dev: */
714 else if (slash)
715 nm = slash + 1;
716 /* if node::dev:, move colon following dev */
717 else if (colon && colon[-1] == ':')
718 colon = p;
719 /* if dev1:dev2:, move nm to dev2: */
720 else if (colon && colon[-1] != ':')
721 {
722 nm = colon + 1;
723 colon = 0;
724 }
725 if (p[0] == ':' && !colon)
726 {
727 if (p[1] == ':')
728 p++;
729 colon = p;
730 }
731 if (lbrack == rbrack)
732 if (p[0] == ';')
733 dots = 2;
734 else if (p[0] == '.')
735 dots++;
736#endif /* VMS */
737 p++;
738 }
739 if (!lose)
740 {
741#ifdef VMS
742 if (index (nm, '/'))
743 return build_string (sys_translate_unix (nm));
744#endif /* VMS */
745 if (nm == XSTRING (name)->data)
746 return name;
747 return build_string (nm);
748 }
749 }
750
751 /* Now determine directory to start with and put it in newdir */
752
753 newdir = 0;
754
755 if (nm[0] == '~') /* prefix ~ */
c77d647e
JB
756 {
757 if (nm[1] == '/'
570d7624 758#ifdef VMS
c77d647e
JB
759 || nm[1] == ':'
760#endif /* VMS */
761 || nm[1] == 0) /* ~ by itself */
762 {
763 if (!(newdir = (unsigned char *) egetenv ("HOME")))
764 newdir = (unsigned char *) "";
765 nm++;
570d7624 766#ifdef VMS
c77d647e
JB
767 nm++; /* Don't leave the slash in nm. */
768#endif /* VMS */
769 }
770 else /* ~user/filename */
771 {
772 for (p = nm; *p && (*p != '/'
570d7624 773#ifdef VMS
c77d647e
JB
774 && *p != ':'
775#endif /* VMS */
776 ); p++);
777 o = (unsigned char *) alloca (p - nm + 1);
778 bcopy ((char *) nm, o, p - nm);
779 o [p - nm] = 0;
780
781 pw = (struct passwd *) getpwnam (o + 1);
782 if (pw)
783 {
784 newdir = (unsigned char *) pw -> pw_dir;
570d7624 785#ifdef VMS
c77d647e 786 nm = p + 1; /* skip the terminator */
570d7624 787#else
c77d647e
JB
788 nm = p;
789#endif /* VMS */
790 }
e5d77022 791
c77d647e
JB
792 /* If we don't find a user of that name, leave the name
793 unchanged; don't move nm forward to p. */
794 }
795 }
570d7624
JB
796
797 if (nm[0] != '/'
798#ifdef VMS
799 && !index (nm, ':')
800#endif /* not VMS */
801 && !newdir)
802 {
265a9e55 803 if (NILP (defalt))
570d7624
JB
804 defalt = current_buffer->directory;
805 CHECK_STRING (defalt, 1);
806 newdir = XSTRING (defalt)->data;
807 }
808
bfb61299
JB
809 if (newdir != 0)
810 {
811 /* Get rid of any slash at the end of newdir. */
812 int length = strlen (newdir);
813 if (newdir[length - 1] == '/')
814 {
815 unsigned char *temp = (unsigned char *) alloca (length);
816 bcopy (newdir, temp, length - 1);
817 temp[length - 1] = 0;
818 newdir = temp;
819 }
820 tlen = length + 1;
821 }
822 else
823 tlen = 0;
570d7624 824
bfb61299
JB
825 /* Now concatenate the directory and name to new space in the stack frame */
826 tlen += strlen (nm) + 1;
570d7624
JB
827 target = (unsigned char *) alloca (tlen);
828 *target = 0;
829
830 if (newdir)
831 {
832#ifndef VMS
833 if (nm[0] == 0 || nm[0] == '/')
834 strcpy (target, newdir);
835 else
836#endif
c77d647e 837 file_name_as_directory (target, newdir);
570d7624
JB
838 }
839
840 strcat (target, nm);
841#ifdef VMS
842 if (index (target, '/'))
843 strcpy (target, sys_translate_unix (target));
844#endif /* VMS */
845
c77d647e 846 /* Now canonicalize by removing /. and /foo/.. if they appear. */
570d7624
JB
847
848 p = target;
849 o = target;
850
851 while (*p)
852 {
853#ifdef VMS
854 if (*p != ']' && *p != '>' && *p != '-')
855 {
856 if (*p == '\\')
857 p++;
858 *o++ = *p++;
859 }
860 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
861 /* brackets are offset from each other by 2 */
862 {
863 p += 2;
864 if (*p != '.' && *p != '-' && o[-1] != '.')
865 /* convert [foo][bar] to [bar] */
866 while (o[-1] != '[' && o[-1] != '<')
867 o--;
868 else if (*p == '-' && *o != '.')
869 *--p = '.';
870 }
871 else if (p[0] == '-' && o[-1] == '.' &&
872 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
873 /* flush .foo.- ; leave - if stopped by '[' or '<' */
874 {
875 do
876 o--;
877 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
878 if (p[1] == '.') /* foo.-.bar ==> bar*/
879 p += 2;
880 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
881 p++, o--;
882 /* else [foo.-] ==> [-] */
883 }
884 else
885 {
886#ifndef VMS4_4
887 if (*p == '-' &&
888 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
889 p[1] != ']' && p[1] != '>' && p[1] != '.')
890 *p = '_';
891#endif /* VMS4_4 */
892 *o++ = *p++;
893 }
894#else /* not VMS */
895 if (*p != '/')
896 {
897 *o++ = *p++;
898 }
899 else if (!strncmp (p, "//", 2)
900#ifdef APOLLO
901 /* // at start of filename is meaningful in Apollo system */
902 && o != target
903#endif /* APOLLO */
904 )
905 {
906 o = target;
907 p++;
908 }
c77d647e
JB
909 else if (p[0] == '/'
910 && p[1] == '.'
911 && (p[2] == '/'
912 || p[2] == 0))
913 {
914 /* If "/." is the entire filename, keep the "/". Otherwise,
915 just delete the whole "/.". */
916 if (o == target && p[2] == '\0')
917 *o++ = *p;
918 p += 2;
919 }
570d7624
JB
920 else if (!strncmp (p, "/..", 3)
921 /* `/../' is the "superroot" on certain file systems. */
922 && o != target
923 && (p[3] == '/' || p[3] == 0))
924 {
925 while (o != target && *--o != '/')
926 ;
927#ifdef APOLLO
928 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
929 ++o;
930 else
931#endif /* APOLLO */
932 if (o == target && *o == '/')
933 ++o;
934 p += 3;
935 }
936 else
937 {
938 *o++ = *p++;
939 }
940#endif /* not VMS */
941 }
942
943 return make_string (target, o - target);
944}
945#if 0
e5d77022
JB
946/* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'.
947DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
570d7624
JB
948 "Convert FILENAME to absolute, and canonicalize it.\n\
949Second arg DEFAULT is directory to start with if FILENAME is relative\n\
950 (does not start with slash); if DEFAULT is nil or missing,\n\
951the current buffer's value of default-directory is used.\n\
952Filenames containing `.' or `..' as components are simplified;\n\
953initial `~/' expands to your home directory.\n\
954See also the function `substitute-in-file-name'.")
955 (name, defalt)
956 Lisp_Object name, defalt;
957{
958 unsigned char *nm;
959
960 register unsigned char *newdir, *p, *o;
961 int tlen;
962 unsigned char *target;
963 struct passwd *pw;
964 int lose;
965#ifdef VMS
966 unsigned char * colon = 0;
967 unsigned char * close = 0;
968 unsigned char * slash = 0;
969 unsigned char * brack = 0;
970 int lbrack = 0, rbrack = 0;
971 int dots = 0;
972#endif /* VMS */
973
974 CHECK_STRING (name, 0);
975
976#ifdef VMS
977 /* Filenames on VMS are always upper case. */
978 name = Fupcase (name);
979#endif
980
981 nm = XSTRING (name)->data;
982
983 /* If nm is absolute, flush ...// and detect /./ and /../.
984 If no /./ or /../ we can return right away. */
985 if (
986 nm[0] == '/'
987#ifdef VMS
988 || index (nm, ':')
989#endif /* VMS */
990 )
991 {
992 p = nm;
993 lose = 0;
994 while (*p)
995 {
996 if (p[0] == '/' && p[1] == '/'
997#ifdef APOLLO
998 /* // at start of filename is meaningful on Apollo system */
999 && nm != p
1000#endif /* APOLLO */
1001 )
1002 nm = p + 1;
1003 if (p[0] == '/' && p[1] == '~')
1004 nm = p + 1, lose = 1;
1005 if (p[0] == '/' && p[1] == '.'
1006 && (p[2] == '/' || p[2] == 0
1007 || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
1008 lose = 1;
1009#ifdef VMS
1010 if (p[0] == '\\')
1011 lose = 1;
1012 if (p[0] == '/') {
1013 /* if dev:[dir]/, move nm to / */
1014 if (!slash && p > nm && (brack || colon)) {
1015 nm = (brack ? brack + 1 : colon + 1);
1016 lbrack = rbrack = 0;
1017 brack = 0;
1018 colon = 0;
1019 }
1020 slash = p;
1021 }
1022 if (p[0] == '-')
1023#ifndef VMS4_4
1024 /* VMS pre V4.4,convert '-'s in filenames. */
1025 if (lbrack == rbrack)
1026 {
1027 if (dots < 2) /* this is to allow negative version numbers */
1028 p[0] = '_';
1029 }
1030 else
1031#endif /* VMS4_4 */
1032 if (lbrack > rbrack &&
1033 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
1034 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
1035 lose = 1;
1036#ifndef VMS4_4
1037 else
1038 p[0] = '_';
1039#endif /* VMS4_4 */
1040 /* count open brackets, reset close bracket pointer */
1041 if (p[0] == '[' || p[0] == '<')
1042 lbrack++, brack = 0;
1043 /* count close brackets, set close bracket pointer */
1044 if (p[0] == ']' || p[0] == '>')
1045 rbrack++, brack = p;
1046 /* detect ][ or >< */
1047 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
1048 lose = 1;
1049 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
1050 nm = p + 1, lose = 1;
1051 if (p[0] == ':' && (colon || slash))
1052 /* if dev1:[dir]dev2:, move nm to dev2: */
1053 if (brack)
1054 {
1055 nm = brack + 1;
1056 brack = 0;
1057 }
1058 /* if /pathname/dev:, move nm to dev: */
1059 else if (slash)
1060 nm = slash + 1;
1061 /* if node::dev:, move colon following dev */
1062 else if (colon && colon[-1] == ':')
1063 colon = p;
1064 /* if dev1:dev2:, move nm to dev2: */
1065 else if (colon && colon[-1] != ':')
1066 {
1067 nm = colon + 1;
1068 colon = 0;
1069 }
1070 if (p[0] == ':' && !colon)
1071 {
1072 if (p[1] == ':')
1073 p++;
1074 colon = p;
1075 }
1076 if (lbrack == rbrack)
1077 if (p[0] == ';')
1078 dots = 2;
1079 else if (p[0] == '.')
1080 dots++;
1081#endif /* VMS */
1082 p++;
1083 }
1084 if (!lose)
1085 {
1086#ifdef VMS
1087 if (index (nm, '/'))
1088 return build_string (sys_translate_unix (nm));
1089#endif /* VMS */
1090 if (nm == XSTRING (name)->data)
1091 return name;
1092 return build_string (nm);
1093 }
1094 }
1095
1096 /* Now determine directory to start with and put it in NEWDIR */
1097
1098 newdir = 0;
1099
1100 if (nm[0] == '~') /* prefix ~ */
1101 if (nm[1] == '/'
1102#ifdef VMS
1103 || nm[1] == ':'
1104#endif /* VMS */
1105 || nm[1] == 0)/* ~/filename */
1106 {
1107 if (!(newdir = (unsigned char *) egetenv ("HOME")))
1108 newdir = (unsigned char *) "";
1109 nm++;
1110#ifdef VMS
1111 nm++; /* Don't leave the slash in nm. */
1112#endif /* VMS */
1113 }
1114 else /* ~user/filename */
1115 {
1116 /* Get past ~ to user */
1117 unsigned char *user = nm + 1;
1118 /* Find end of name. */
1119 unsigned char *ptr = (unsigned char *) index (user, '/');
1120 int len = ptr ? ptr - user : strlen (user);
1121#ifdef VMS
1122 unsigned char *ptr1 = index (user, ':');
1123 if (ptr1 != 0 && ptr1 - user < len)
1124 len = ptr1 - user;
1125#endif /* VMS */
1126 /* Copy the user name into temp storage. */
1127 o = (unsigned char *) alloca (len + 1);
1128 bcopy ((char *) user, o, len);
1129 o[len] = 0;
1130
1131 /* Look up the user name. */
1132 pw = (struct passwd *) getpwnam (o + 1);
1133 if (!pw)
1134 error ("\"%s\" isn't a registered user", o + 1);
1135
1136 newdir = (unsigned char *) pw->pw_dir;
1137
1138 /* Discard the user name from NM. */
1139 nm += len;
1140 }
1141
1142 if (nm[0] != '/'
1143#ifdef VMS
1144 && !index (nm, ':')
1145#endif /* not VMS */
1146 && !newdir)
1147 {
265a9e55 1148 if (NILP (defalt))
570d7624
JB
1149 defalt = current_buffer->directory;
1150 CHECK_STRING (defalt, 1);
1151 newdir = XSTRING (defalt)->data;
1152 }
1153
1154 /* Now concatenate the directory and name to new space in the stack frame */
1155
1156 tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1;
1157 target = (unsigned char *) alloca (tlen);
1158 *target = 0;
1159
1160 if (newdir)
1161 {
1162#ifndef VMS
1163 if (nm[0] == 0 || nm[0] == '/')
1164 strcpy (target, newdir);
1165 else
1166#endif
1167 file_name_as_directory (target, newdir);
1168 }
1169
1170 strcat (target, nm);
1171#ifdef VMS
1172 if (index (target, '/'))
1173 strcpy (target, sys_translate_unix (target));
1174#endif /* VMS */
1175
1176 /* Now canonicalize by removing /. and /foo/.. if they appear */
1177
1178 p = target;
1179 o = target;
1180
1181 while (*p)
1182 {
1183#ifdef VMS
1184 if (*p != ']' && *p != '>' && *p != '-')
1185 {
1186 if (*p == '\\')
1187 p++;
1188 *o++ = *p++;
1189 }
1190 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
1191 /* brackets are offset from each other by 2 */
1192 {
1193 p += 2;
1194 if (*p != '.' && *p != '-' && o[-1] != '.')
1195 /* convert [foo][bar] to [bar] */
1196 while (o[-1] != '[' && o[-1] != '<')
1197 o--;
1198 else if (*p == '-' && *o != '.')
1199 *--p = '.';
1200 }
1201 else if (p[0] == '-' && o[-1] == '.' &&
1202 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1203 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1204 {
1205 do
1206 o--;
1207 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1208 if (p[1] == '.') /* foo.-.bar ==> bar*/
1209 p += 2;
1210 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1211 p++, o--;
1212 /* else [foo.-] ==> [-] */
1213 }
1214 else
1215 {
1216#ifndef VMS4_4
1217 if (*p == '-' &&
1218 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
1219 p[1] != ']' && p[1] != '>' && p[1] != '.')
1220 *p = '_';
1221#endif /* VMS4_4 */
1222 *o++ = *p++;
1223 }
1224#else /* not VMS */
1225 if (*p != '/')
1226 {
1227 *o++ = *p++;
1228 }
1229 else if (!strncmp (p, "//", 2)
1230#ifdef APOLLO
1231 /* // at start of filename is meaningful in Apollo system */
1232 && o != target
1233#endif /* APOLLO */
1234 )
1235 {
1236 o = target;
1237 p++;
1238 }
1239 else if (p[0] == '/' && p[1] == '.' &&
1240 (p[2] == '/' || p[2] == 0))
1241 p += 2;
1242 else if (!strncmp (p, "/..", 3)
1243 /* `/../' is the "superroot" on certain file systems. */
1244 && o != target
1245 && (p[3] == '/' || p[3] == 0))
1246 {
1247 while (o != target && *--o != '/')
1248 ;
1249#ifdef APOLLO
1250 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
1251 ++o;
1252 else
1253#endif /* APOLLO */
1254 if (o == target && *o == '/')
1255 ++o;
1256 p += 3;
1257 }
1258 else
1259 {
1260 *o++ = *p++;
1261 }
1262#endif /* not VMS */
1263 }
1264
1265 return make_string (target, o - target);
1266}
1267#endif
1268\f
1269DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name,
1270 Ssubstitute_in_file_name, 1, 1, 0,
1271 "Substitute environment variables referred to in FILENAME.\n\
1272`$FOO' where FOO is an environment variable name means to substitute\n\
1273the value of that variable. The variable name should be terminated\n\
1274with a character not a letter, digit or underscore; otherwise, enclose\n\
1275the entire variable name in braces.\n\
1276If `/~' appears, all of FILENAME through that `/' is discarded.\n\n\
1277On VMS, `$' substitution is not done; this function does little and only\n\
1278duplicates what `expand-file-name' does.")
1279 (string)
1280 Lisp_Object string;
1281{
1282 unsigned char *nm;
1283
1284 register unsigned char *s, *p, *o, *x, *endp;
1285 unsigned char *target;
1286 int total = 0;
1287 int substituted = 0;
1288 unsigned char *xnm;
1289
1290 CHECK_STRING (string, 0);
1291
1292 nm = XSTRING (string)->data;
1293 endp = nm + XSTRING (string)->size;
1294
1295 /* If /~ or // appears, discard everything through first slash. */
1296
1297 for (p = nm; p != endp; p++)
1298 {
1299 if ((p[0] == '~' ||
1300#ifdef APOLLO
1301 /* // at start of file name is meaningful in Apollo system */
1302 (p[0] == '/' && p - 1 != nm)
1303#else /* not APOLLO */
1304 p[0] == '/'
1305#endif /* not APOLLO */
1306 )
1307 && p != nm &&
1308#ifdef VMS
1309 (p[-1] == ':' || p[-1] == ']' || p[-1] == '>' ||
1310#endif /* VMS */
1311 p[-1] == '/')
1312#ifdef VMS
1313 )
1314#endif /* VMS */
1315 {
1316 nm = p;
1317 substituted = 1;
1318 }
1319 }
1320
1321#ifdef VMS
1322 return build_string (nm);
1323#else
1324
1325 /* See if any variables are substituted into the string
1326 and find the total length of their values in `total' */
1327
1328 for (p = nm; p != endp;)
1329 if (*p != '$')
1330 p++;
1331 else
1332 {
1333 p++;
1334 if (p == endp)
1335 goto badsubst;
1336 else if (*p == '$')
1337 {
1338 /* "$$" means a single "$" */
1339 p++;
1340 total -= 1;
1341 substituted = 1;
1342 continue;
1343 }
1344 else if (*p == '{')
1345 {
1346 o = ++p;
1347 while (p != endp && *p != '}') p++;
1348 if (*p != '}') goto missingclose;
1349 s = p;
1350 }
1351 else
1352 {
1353 o = p;
1354 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1355 s = p;
1356 }
1357
1358 /* Copy out the variable name */
1359 target = (unsigned char *) alloca (s - o + 1);
1360 strncpy (target, o, s - o);
1361 target[s - o] = 0;
1362
1363 /* Get variable value */
1364 o = (unsigned char *) egetenv (target);
1365/* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
1366#if 0
1367#ifdef USG
1368 if (!o && !strcmp (target, "USER"))
1369 o = egetenv ("LOGNAME");
1370#endif /* USG */
1371#endif /* 0 */
1372 if (!o) goto badvar;
1373 total += strlen (o);
1374 substituted = 1;
1375 }
1376
1377 if (!substituted)
1378 return string;
1379
1380 /* If substitution required, recopy the string and do it */
1381 /* Make space in stack frame for the new copy */
1382 xnm = (unsigned char *) alloca (XSTRING (string)->size + total + 1);
1383 x = xnm;
1384
1385 /* Copy the rest of the name through, replacing $ constructs with values */
1386 for (p = nm; *p;)
1387 if (*p != '$')
1388 *x++ = *p++;
1389 else
1390 {
1391 p++;
1392 if (p == endp)
1393 goto badsubst;
1394 else if (*p == '$')
1395 {
1396 *x++ = *p++;
1397 continue;
1398 }
1399 else if (*p == '{')
1400 {
1401 o = ++p;
1402 while (p != endp && *p != '}') p++;
1403 if (*p != '}') goto missingclose;
1404 s = p++;
1405 }
1406 else
1407 {
1408 o = p;
1409 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1410 s = p;
1411 }
1412
1413 /* Copy out the variable name */
1414 target = (unsigned char *) alloca (s - o + 1);
1415 strncpy (target, o, s - o);
1416 target[s - o] = 0;
1417
1418 /* Get variable value */
1419 o = (unsigned char *) egetenv (target);
1420/* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
1421#if 0
1422#ifdef USG
1423 if (!o && !strcmp (target, "USER"))
1424 o = egetenv ("LOGNAME");
1425#endif /* USG */
1426#endif /* 0 */
1427 if (!o)
1428 goto badvar;
1429
1430 strcpy (x, o);
1431 x += strlen (o);
1432 }
1433
1434 *x = 0;
1435
1436 /* If /~ or // appears, discard everything through first slash. */
1437
1438 for (p = xnm; p != x; p++)
1439 if ((p[0] == '~' ||
1440#ifdef APOLLO
1441 /* // at start of file name is meaningful in Apollo system */
1442 (p[0] == '/' && p - 1 != xnm)
1443#else /* not APOLLO */
1444 p[0] == '/'
1445#endif /* not APOLLO */
1446 )
1447 && p != nm && p[-1] == '/')
1448 xnm = p;
1449
1450 return make_string (xnm, x - xnm);
1451
1452 badsubst:
1453 error ("Bad format environment-variable substitution");
1454 missingclose:
1455 error ("Missing \"}\" in environment-variable substitution");
1456 badvar:
1457 error ("Substituting nonexistent environment variable \"%s\"", target);
1458
1459 /* NOTREACHED */
1460#endif /* not VMS */
1461}
1462\f
067ffa38
JB
1463/* A slightly faster and more convenient way to get
1464 (directory-file-name (expand-file-name FOO)). The return value may
1465 have had its last character zapped with a '\0' character, meaning
1466 that it is acceptable to system calls, but not to other lisp
1467 functions. Callers should make sure that the return value doesn't
1468 escape. */
1469
570d7624
JB
1470Lisp_Object
1471expand_and_dir_to_file (filename, defdir)
1472 Lisp_Object filename, defdir;
1473{
1474 register Lisp_Object abspath;
1475
1476 abspath = Fexpand_file_name (filename, defdir);
1477#ifdef VMS
1478 {
1479 register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1];
1480 if (c == ':' || c == ']' || c == '>')
1481 abspath = Fdirectory_file_name (abspath);
1482 }
1483#else
1484 /* Remove final slash, if any (unless path is root).
1485 stat behaves differently depending! */
1486 if (XSTRING (abspath)->size > 1
1487 && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/')
1488 {
1489 if (EQ (abspath, filename))
1490 abspath = Fcopy_sequence (abspath);
1491 XSTRING (abspath)->data[XSTRING (abspath)->size - 1] = 0;
1492 }
1493#endif
1494 return abspath;
1495}
1496\f
1497barf_or_query_if_file_exists (absname, querystring, interactive)
1498 Lisp_Object absname;
1499 unsigned char *querystring;
1500 int interactive;
1501{
1502 register Lisp_Object tem;
1503 struct gcpro gcpro1;
1504
1505 if (access (XSTRING (absname)->data, 4) >= 0)
1506 {
1507 if (! interactive)
1508 Fsignal (Qfile_already_exists,
1509 Fcons (build_string ("File already exists"),
1510 Fcons (absname, Qnil)));
1511 GCPRO1 (absname);
1512 tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
1513 XSTRING (absname)->data, querystring));
1514 UNGCPRO;
265a9e55 1515 if (NILP (tem))
570d7624
JB
1516 Fsignal (Qfile_already_exists,
1517 Fcons (build_string ("File already exists"),
1518 Fcons (absname, Qnil)));
1519 }
1520 return;
1521}
1522
1523DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4,
349a7710 1524 "fCopy file: \nFCopy %s to file: \np\nP",
570d7624
JB
1525 "Copy FILE to NEWNAME. Both args must be strings.\n\
1526Signals a `file-already-exists' error if file NEWNAME already exists,\n\
1527unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\
1528A number as third arg means request confirmation if NEWNAME already exists.\n\
1529This is what happens in interactive use with M-x.\n\
349a7710
JB
1530Fourth arg KEEP-TIME non-nil means give the new file the same\n\
1531last-modified time as the old one. (This works on only some systems.)\n\
1532A prefix arg makes KEEP-TIME non-nil.")
570d7624
JB
1533 (filename, newname, ok_if_already_exists, keep_date)
1534 Lisp_Object filename, newname, ok_if_already_exists, keep_date;
1535{
1536 int ifd, ofd, n;
1537 char buf[16 * 1024];
1538 struct stat st;
32f4334d 1539 Lisp_Object handler;
570d7624 1540 struct gcpro gcpro1, gcpro2;
b5148e85 1541 int count = specpdl_ptr - specpdl;
570d7624
JB
1542
1543 GCPRO2 (filename, newname);
1544 CHECK_STRING (filename, 0);
1545 CHECK_STRING (newname, 1);
1546 filename = Fexpand_file_name (filename, Qnil);
1547 newname = Fexpand_file_name (newname, Qnil);
32f4334d 1548
0bf2eed2 1549 /* If the input file name has special constructs in it,
32f4334d 1550 call the corresponding file handler. */
642ef245 1551 handler = Ffind_file_name_handler (filename);
0bf2eed2
RS
1552 if (!NILP (handler))
1553 return call3 (handler, Qcopy_file, filename, newname);
1554 /* Likewise for output file name. */
642ef245 1555 handler = Ffind_file_name_handler (newname);
32f4334d
RS
1556 if (!NILP (handler))
1557 return call3 (handler, Qcopy_file, filename, newname);
1558
265a9e55 1559 if (NILP (ok_if_already_exists)
570d7624
JB
1560 || XTYPE (ok_if_already_exists) == Lisp_Int)
1561 barf_or_query_if_file_exists (newname, "copy to it",
1562 XTYPE (ok_if_already_exists) == Lisp_Int);
1563
1564 ifd = open (XSTRING (filename)->data, 0);
1565 if (ifd < 0)
1566 report_file_error ("Opening input file", Fcons (filename, Qnil));
1567
b5148e85
RS
1568 record_unwind_protect (close_file_unwind, make_number (ifd));
1569
570d7624
JB
1570#ifdef VMS
1571 /* Create the copy file with the same record format as the input file */
1572 ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
1573#else
1574 ofd = creat (XSTRING (newname)->data, 0666);
1575#endif /* VMS */
1576 if (ofd < 0)
66331187 1577 report_file_error ("Opening output file", Fcons (newname, Qnil));
b5148e85
RS
1578
1579 record_unwind_protect (close_file_unwind, make_number (ofd));
570d7624 1580
b5148e85
RS
1581 immediate_quit = 1;
1582 QUIT;
570d7624
JB
1583 while ((n = read (ifd, buf, sizeof buf)) > 0)
1584 if (write (ofd, buf, n) != n)
66331187 1585 report_file_error ("I/O error", Fcons (newname, Qnil));
b5148e85 1586 immediate_quit = 0;
570d7624
JB
1587
1588 if (fstat (ifd, &st) >= 0)
1589 {
265a9e55 1590 if (!NILP (keep_date))
570d7624 1591 {
de5bf5d3
JB
1592 EMACS_TIME atime, mtime;
1593 EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
1594 EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
1595 EMACS_SET_UTIMES (XSTRING (newname)->data, atime, mtime);
570d7624 1596 }
570d7624
JB
1597#ifdef APOLLO
1598 if (!egetenv ("USE_DOMAIN_ACLS"))
1599#endif
de5bf5d3 1600 chmod (XSTRING (newname)->data, st.st_mode & 07777);
570d7624
JB
1601 }
1602
b5148e85
RS
1603 /* Discard the unwind protects. */
1604 specpdl_ptr = specpdl + count;
1605
570d7624
JB
1606 close (ifd);
1607 if (close (ofd) < 0)
1608 report_file_error ("I/O error", Fcons (newname, Qnil));
1609
1610 UNGCPRO;
1611 return Qnil;
1612}
1613
9bbe01fb 1614DEFUN ("make-directory-internal", Fmake_directory_internal,
353cfc19 1615 Smake_directory_internal, 1, 1, 0,
570d7624
JB
1616 "Create a directory. One argument, a file name string.")
1617 (dirname)
1618 Lisp_Object dirname;
1619{
1620 unsigned char *dir;
32f4334d 1621 Lisp_Object handler;
570d7624
JB
1622
1623 CHECK_STRING (dirname, 0);
1624 dirname = Fexpand_file_name (dirname, Qnil);
32f4334d 1625
642ef245 1626 handler = Ffind_file_name_handler (dirname);
32f4334d 1627 if (!NILP (handler))
9bbe01fb
RS
1628 return call3 (handler, Qmake_directory, dirname, Qnil);
1629
570d7624
JB
1630 dir = XSTRING (dirname)->data;
1631
1632 if (mkdir (dir, 0777) != 0)
1633 report_file_error ("Creating directory", Flist (1, &dirname));
1634
32f4334d 1635 return Qnil;
570d7624
JB
1636}
1637
aa734e17
RS
1638DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
1639 "Delete a directory. One argument, a file name string.")
570d7624
JB
1640 (dirname)
1641 Lisp_Object dirname;
1642{
1643 unsigned char *dir;
32f4334d 1644 Lisp_Object handler;
570d7624
JB
1645
1646 CHECK_STRING (dirname, 0);
1647 dirname = Fexpand_file_name (dirname, Qnil);
1648 dir = XSTRING (dirname)->data;
1649
642ef245 1650 handler = Ffind_file_name_handler (dirname);
32f4334d
RS
1651 if (!NILP (handler))
1652 return call2 (handler, Qdelete_directory, dirname);
1653
570d7624
JB
1654 if (rmdir (dir) != 0)
1655 report_file_error ("Removing directory", Flist (1, &dirname));
1656
1657 return Qnil;
1658}
1659
1660DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
1661 "Delete specified file. One argument, a file name string.\n\
1662If file has multiple names, it continues to exist with the other names.")
1663 (filename)
1664 Lisp_Object filename;
1665{
32f4334d 1666 Lisp_Object handler;
570d7624
JB
1667 CHECK_STRING (filename, 0);
1668 filename = Fexpand_file_name (filename, Qnil);
32f4334d 1669
642ef245 1670 handler = Ffind_file_name_handler (filename);
32f4334d
RS
1671 if (!NILP (handler))
1672 return call2 (handler, Qdelete_file, filename);
1673
570d7624
JB
1674 if (0 > unlink (XSTRING (filename)->data))
1675 report_file_error ("Removing old name", Flist (1, &filename));
1676 return Qnil;
1677}
1678
1679DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
1680 "fRename file: \nFRename %s to file: \np",
1681 "Rename FILE as NEWNAME. Both args strings.\n\
1682If file has names other than FILE, it continues to have those names.\n\
1683Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1684unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1685A number as third arg means request confirmation if NEWNAME already exists.\n\
1686This is what happens in interactive use with M-x.")
1687 (filename, newname, ok_if_already_exists)
1688 Lisp_Object filename, newname, ok_if_already_exists;
1689{
1690#ifdef NO_ARG_ARRAY
1691 Lisp_Object args[2];
1692#endif
32f4334d 1693 Lisp_Object handler;
570d7624
JB
1694 struct gcpro gcpro1, gcpro2;
1695
1696 GCPRO2 (filename, newname);
1697 CHECK_STRING (filename, 0);
1698 CHECK_STRING (newname, 1);
1699 filename = Fexpand_file_name (filename, Qnil);
1700 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1701
1702 /* If the file name has special constructs in it,
1703 call the corresponding file handler. */
642ef245 1704 handler = Ffind_file_name_handler (filename);
32f4334d
RS
1705 if (!NILP (handler))
1706 return call3 (handler, Qrename_file, filename, newname);
1707
265a9e55 1708 if (NILP (ok_if_already_exists)
570d7624
JB
1709 || XTYPE (ok_if_already_exists) == Lisp_Int)
1710 barf_or_query_if_file_exists (newname, "rename to it",
1711 XTYPE (ok_if_already_exists) == Lisp_Int);
1712#ifndef BSD4_1
1713 if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
1714#else
1715 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data)
1716 || 0 > unlink (XSTRING (filename)->data))
1717#endif
1718 {
1719 if (errno == EXDEV)
1720 {
1721 Fcopy_file (filename, newname, ok_if_already_exists, Qt);
1722 Fdelete_file (filename);
1723 }
1724 else
1725#ifdef NO_ARG_ARRAY
1726 {
1727 args[0] = filename;
1728 args[1] = newname;
1729 report_file_error ("Renaming", Flist (2, args));
1730 }
1731#else
1732 report_file_error ("Renaming", Flist (2, &filename));
1733#endif
1734 }
1735 UNGCPRO;
1736 return Qnil;
1737}
1738
1739DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3,
1740 "fAdd name to file: \nFName to add to %s: \np",
1741 "Give FILE additional name NEWNAME. Both args strings.\n\
1742Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1743unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1744A number as third arg means request confirmation if NEWNAME already exists.\n\
1745This is what happens in interactive use with M-x.")
1746 (filename, newname, ok_if_already_exists)
1747 Lisp_Object filename, newname, ok_if_already_exists;
1748{
1749#ifdef NO_ARG_ARRAY
1750 Lisp_Object args[2];
1751#endif
32f4334d 1752 Lisp_Object handler;
570d7624
JB
1753 struct gcpro gcpro1, gcpro2;
1754
1755 GCPRO2 (filename, newname);
1756 CHECK_STRING (filename, 0);
1757 CHECK_STRING (newname, 1);
1758 filename = Fexpand_file_name (filename, Qnil);
1759 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1760
1761 /* If the file name has special constructs in it,
1762 call the corresponding file handler. */
642ef245 1763 handler = Ffind_file_name_handler (filename);
32f4334d
RS
1764 if (!NILP (handler))
1765 return call3 (handler, Qadd_name_to_file, filename, newname);
1766
265a9e55 1767 if (NILP (ok_if_already_exists)
570d7624
JB
1768 || XTYPE (ok_if_already_exists) == Lisp_Int)
1769 barf_or_query_if_file_exists (newname, "make it a new name",
1770 XTYPE (ok_if_already_exists) == Lisp_Int);
1771 unlink (XSTRING (newname)->data);
1772 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data))
1773 {
1774#ifdef NO_ARG_ARRAY
1775 args[0] = filename;
1776 args[1] = newname;
1777 report_file_error ("Adding new name", Flist (2, args));
1778#else
1779 report_file_error ("Adding new name", Flist (2, &filename));
1780#endif
1781 }
1782
1783 UNGCPRO;
1784 return Qnil;
1785}
1786
1787#ifdef S_IFLNK
1788DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
1789 "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",
1790 "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\
1791Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1792unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1793A number as third arg means request confirmation if NEWNAME already exists.\n\
1794This happens for interactive use with M-x.")
e5d77022
JB
1795 (filename, linkname, ok_if_already_exists)
1796 Lisp_Object filename, linkname, ok_if_already_exists;
570d7624
JB
1797{
1798#ifdef NO_ARG_ARRAY
1799 Lisp_Object args[2];
1800#endif
32f4334d 1801 Lisp_Object handler;
570d7624
JB
1802 struct gcpro gcpro1, gcpro2;
1803
e5d77022 1804 GCPRO2 (filename, linkname);
570d7624 1805 CHECK_STRING (filename, 0);
e5d77022 1806 CHECK_STRING (linkname, 1);
570d7624
JB
1807#if 0 /* This made it impossible to make a link to a relative name. */
1808 filename = Fexpand_file_name (filename, Qnil);
1809#endif
e5d77022 1810 linkname = Fexpand_file_name (linkname, Qnil);
32f4334d
RS
1811
1812 /* If the file name has special constructs in it,
1813 call the corresponding file handler. */
642ef245 1814 handler = Ffind_file_name_handler (filename);
32f4334d 1815 if (!NILP (handler))
3eac9910 1816 return call3 (handler, Qmake_symbolic_link, filename, linkname);
32f4334d 1817
265a9e55 1818 if (NILP (ok_if_already_exists)
570d7624 1819 || XTYPE (ok_if_already_exists) == Lisp_Int)
e5d77022 1820 barf_or_query_if_file_exists (linkname, "make it a link",
570d7624 1821 XTYPE (ok_if_already_exists) == Lisp_Int);
e5d77022 1822 if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
1823 {
1824 /* If we didn't complain already, silently delete existing file. */
1825 if (errno == EEXIST)
1826 {
1827 unlink (XSTRING (filename)->data);
e5d77022 1828 if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
1829 return Qnil;
1830 }
1831
1832#ifdef NO_ARG_ARRAY
1833 args[0] = filename;
e5d77022 1834 args[1] = linkname;
570d7624
JB
1835 report_file_error ("Making symbolic link", Flist (2, args));
1836#else
1837 report_file_error ("Making symbolic link", Flist (2, &filename));
1838#endif
1839 }
1840 UNGCPRO;
1841 return Qnil;
1842}
1843#endif /* S_IFLNK */
1844
1845#ifdef VMS
1846
1847DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
1848 2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
1849 "Define the job-wide logical name NAME to have the value STRING.\n\
1850If STRING is nil or a null string, the logical name NAME is deleted.")
1851 (varname, string)
1852 Lisp_Object varname;
1853 Lisp_Object string;
1854{
1855 CHECK_STRING (varname, 0);
265a9e55 1856 if (NILP (string))
570d7624
JB
1857 delete_logical_name (XSTRING (varname)->data);
1858 else
1859 {
1860 CHECK_STRING (string, 1);
1861
1862 if (XSTRING (string)->size == 0)
1863 delete_logical_name (XSTRING (varname)->data);
1864 else
1865 define_logical_name (XSTRING (varname)->data, XSTRING (string)->data);
1866 }
1867
1868 return string;
1869}
1870#endif /* VMS */
1871
1872#ifdef HPUX_NET
1873
1874DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
1875 "Open a network connection to PATH using LOGIN as the login string.")
1876 (path, login)
1877 Lisp_Object path, login;
1878{
1879 int netresult;
1880
1881 CHECK_STRING (path, 0);
1882 CHECK_STRING (login, 0);
1883
1884 netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
1885
1886 if (netresult == -1)
1887 return Qnil;
1888 else
1889 return Qt;
1890}
1891#endif /* HPUX_NET */
1892\f
1893DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
1894 1, 1, 0,
1895 "Return t if file FILENAME specifies an absolute path name.\n\
1896On Unix, this is a name starting with a `/' or a `~'.")
1897 (filename)
1898 Lisp_Object filename;
1899{
1900 unsigned char *ptr;
1901
1902 CHECK_STRING (filename, 0);
1903 ptr = XSTRING (filename)->data;
1904 if (*ptr == '/' || *ptr == '~'
1905#ifdef VMS
1906/* ??? This criterion is probably wrong for '<'. */
1907 || index (ptr, ':') || index (ptr, '<')
1908 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
1909 && ptr[1] != '.')
1910#endif /* VMS */
1911 )
1912 return Qt;
1913 else
1914 return Qnil;
1915}
1916
1917DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
1918 "Return t if file FILENAME exists. (This does not mean you can read it.)\n\
1919See also `file-readable-p' and `file-attributes'.")
1920 (filename)
1921 Lisp_Object filename;
1922{
1923 Lisp_Object abspath;
32f4334d 1924 Lisp_Object handler;
570d7624
JB
1925
1926 CHECK_STRING (filename, 0);
1927 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1928
1929 /* If the file name has special constructs in it,
1930 call the corresponding file handler. */
642ef245 1931 handler = Ffind_file_name_handler (abspath);
32f4334d 1932 if (!NILP (handler))
09121adc 1933 return call2 (handler, Qfile_exists_p, abspath);
32f4334d 1934
570d7624
JB
1935 return (access (XSTRING (abspath)->data, 0) >= 0) ? Qt : Qnil;
1936}
1937
1938DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
1939 "Return t if FILENAME can be executed by you.\n\
1940For directories this means you can change to that directory.")
1941 (filename)
1942 Lisp_Object filename;
1943
1944{
1945 Lisp_Object abspath;
32f4334d 1946 Lisp_Object handler;
570d7624
JB
1947
1948 CHECK_STRING (filename, 0);
1949 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1950
1951 /* If the file name has special constructs in it,
1952 call the corresponding file handler. */
642ef245 1953 handler = Ffind_file_name_handler (abspath);
32f4334d 1954 if (!NILP (handler))
09121adc 1955 return call2 (handler, Qfile_executable_p, abspath);
32f4334d 1956
570d7624
JB
1957 return (access (XSTRING (abspath)->data, 1) >= 0) ? Qt : Qnil;
1958}
1959
1960DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
1961 "Return t if file FILENAME exists and you can read it.\n\
1962See also `file-exists-p' and `file-attributes'.")
1963 (filename)
1964 Lisp_Object filename;
1965{
1966 Lisp_Object abspath;
32f4334d 1967 Lisp_Object handler;
570d7624
JB
1968
1969 CHECK_STRING (filename, 0);
1970 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1971
1972 /* If the file name has special constructs in it,
1973 call the corresponding file handler. */
642ef245 1974 handler = Ffind_file_name_handler (abspath);
32f4334d 1975 if (!NILP (handler))
09121adc 1976 return call2 (handler, Qfile_readable_p, abspath);
32f4334d 1977
570d7624
JB
1978 return (access (XSTRING (abspath)->data, 4) >= 0) ? Qt : Qnil;
1979}
1980
1981DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
1982 "If file FILENAME is the name of a symbolic link\n\
1983returns the name of the file to which it is linked.\n\
1984Otherwise returns NIL.")
1985 (filename)
1986 Lisp_Object filename;
1987{
1988#ifdef S_IFLNK
1989 char *buf;
1990 int bufsize;
1991 int valsize;
1992 Lisp_Object val;
32f4334d 1993 Lisp_Object handler;
570d7624
JB
1994
1995 CHECK_STRING (filename, 0);
1996 filename = Fexpand_file_name (filename, Qnil);
1997
32f4334d
RS
1998 /* If the file name has special constructs in it,
1999 call the corresponding file handler. */
642ef245 2000 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2001 if (!NILP (handler))
2002 return call2 (handler, Qfile_symlink_p, filename);
2003
570d7624
JB
2004 bufsize = 100;
2005 while (1)
2006 {
2007 buf = (char *) xmalloc (bufsize);
2008 bzero (buf, bufsize);
2009 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
2010 if (valsize < bufsize) break;
2011 /* Buffer was not long enough */
2012 free (buf);
2013 bufsize *= 2;
2014 }
2015 if (valsize == -1)
2016 {
2017 free (buf);
2018 return Qnil;
2019 }
2020 val = make_string (buf, valsize);
2021 free (buf);
2022 return val;
2023#else /* not S_IFLNK */
2024 return Qnil;
2025#endif /* not S_IFLNK */
2026}
2027
2028/* Having this before file-symlink-p mysteriously caused it to be forgotten
2029 on the RT/PC. */
2030DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
2031 "Return t if file FILENAME can be written or created by you.")
2032 (filename)
2033 Lisp_Object filename;
2034{
2035 Lisp_Object abspath, dir;
32f4334d 2036 Lisp_Object handler;
570d7624
JB
2037
2038 CHECK_STRING (filename, 0);
2039 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2040
2041 /* If the file name has special constructs in it,
2042 call the corresponding file handler. */
642ef245 2043 handler = Ffind_file_name_handler (abspath);
32f4334d 2044 if (!NILP (handler))
09121adc 2045 return call2 (handler, Qfile_writable_p, abspath);
32f4334d 2046
570d7624
JB
2047 if (access (XSTRING (abspath)->data, 0) >= 0)
2048 return (access (XSTRING (abspath)->data, 2) >= 0) ? Qt : Qnil;
2049 dir = Ffile_name_directory (abspath);
2050#ifdef VMS
265a9e55 2051 if (!NILP (dir))
570d7624
JB
2052 dir = Fdirectory_file_name (dir);
2053#endif /* VMS */
265a9e55 2054 return (access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
570d7624
JB
2055 ? Qt : Qnil);
2056}
2057
2058DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
2059 "Return t if file FILENAME is the name of a directory as a file.\n\
2060A directory name spec may be given instead; then the value is t\n\
2061if the directory so specified exists and really is a directory.")
2062 (filename)
2063 Lisp_Object filename;
2064{
2065 register Lisp_Object abspath;
2066 struct stat st;
32f4334d 2067 Lisp_Object handler;
570d7624
JB
2068
2069 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2070
32f4334d
RS
2071 /* If the file name has special constructs in it,
2072 call the corresponding file handler. */
642ef245 2073 handler = Ffind_file_name_handler (abspath);
32f4334d 2074 if (!NILP (handler))
09121adc 2075 return call2 (handler, Qfile_directory_p, abspath);
32f4334d 2076
570d7624
JB
2077 if (stat (XSTRING (abspath)->data, &st) < 0)
2078 return Qnil;
2079 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2080}
2081
b72dea2a
JB
2082DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
2083 "Return t if file FILENAME is the name of a directory as a file,\n\
2084and files in that directory can be opened by you. In order to use a\n\
2085directory as a buffer's current directory, this predicate must return true.\n\
2086A directory name spec may be given instead; then the value is t\n\
2087if the directory so specified exists and really is a readable and\n\
2088searchable directory.")
2089 (filename)
2090 Lisp_Object filename;
2091{
32f4334d
RS
2092 Lisp_Object handler;
2093
2094 /* If the file name has special constructs in it,
2095 call the corresponding file handler. */
642ef245 2096 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2097 if (!NILP (handler))
2098 return call2 (handler, Qfile_accessible_directory_p, filename);
2099
b72dea2a
JB
2100 if (NILP (Ffile_directory_p (filename))
2101 || NILP (Ffile_executable_p (filename)))
2102 return Qnil;
2103 else
2104 return Qt;
2105}
2106
570d7624
JB
2107DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2108 "Return mode bits of FILE, as an integer.")
2109 (filename)
2110 Lisp_Object filename;
2111{
2112 Lisp_Object abspath;
2113 struct stat st;
32f4334d 2114 Lisp_Object handler;
570d7624
JB
2115
2116 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2117
32f4334d
RS
2118 /* If the file name has special constructs in it,
2119 call the corresponding file handler. */
642ef245 2120 handler = Ffind_file_name_handler (abspath);
32f4334d 2121 if (!NILP (handler))
09121adc 2122 return call2 (handler, Qfile_modes, abspath);
32f4334d 2123
570d7624
JB
2124 if (stat (XSTRING (abspath)->data, &st) < 0)
2125 return Qnil;
2126 return make_number (st.st_mode & 07777);
2127}
2128
2129DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2130 "Set mode bits of FILE to MODE (an integer).\n\
2131Only the 12 low bits of MODE are used.")
2132 (filename, mode)
2133 Lisp_Object filename, mode;
2134{
2135 Lisp_Object abspath;
32f4334d 2136 Lisp_Object handler;
570d7624
JB
2137
2138 abspath = Fexpand_file_name (filename, current_buffer->directory);
2139 CHECK_NUMBER (mode, 1);
2140
32f4334d
RS
2141 /* If the file name has special constructs in it,
2142 call the corresponding file handler. */
642ef245 2143 handler = Ffind_file_name_handler (abspath);
32f4334d 2144 if (!NILP (handler))
09121adc 2145 return call3 (handler, Qset_file_modes, abspath, mode);
32f4334d 2146
570d7624
JB
2147#ifndef APOLLO
2148 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2149 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2150#else /* APOLLO */
2151 if (!egetenv ("USE_DOMAIN_ACLS"))
2152 {
2153 struct stat st;
2154 struct timeval tvp[2];
2155
2156 /* chmod on apollo also change the file's modtime; need to save the
2157 modtime and then restore it. */
2158 if (stat (XSTRING (abspath)->data, &st) < 0)
2159 {
2160 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2161 return (Qnil);
2162 }
2163
2164 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2165 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2166
2167 /* reset the old accessed and modified times. */
2168 tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
2169 tvp[0].tv_usec = 0;
2170 tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
2171 tvp[1].tv_usec = 0;
2172
2173 if (utimes (XSTRING (abspath)->data, tvp) < 0)
2174 report_file_error ("Doing utimes", Fcons (abspath, Qnil));
2175 }
2176#endif /* APOLLO */
2177
2178 return Qnil;
2179}
2180
36a8c287
JB
2181DEFUN ("set-umask", Fset_umask, Sset_umask, 1, 1, 0,
2182 "Select which permission bits to disable in newly created files.\n\
2183MASK should be an integer; if a permission's bit in MASK is 1,\n\
2184subsequently created files will not have that permission enabled.\n\
2185Only the low 9 bits are used.\n\
2186This setting is inherited by subprocesses.")
2187 (mask)
2188 Lisp_Object mask;
2189{
2190 CHECK_NUMBER (mask, 0);
2191
2192 umask (XINT (mask) & 0777);
2193
2194 return Qnil;
2195}
2196
2197DEFUN ("umask", Fumask, Sumask, 0, 0, 0,
2198 "Return the current umask value.\n\
2199The umask value determines which permissions are enabled in newly\n\
2200created files. If a permission's bit in the umask is 1, subsequently\n\
2201created files will not have that permission enabled.")
2202 ()
2203{
2204 Lisp_Object mask;
2205
2206 XSET (mask, Lisp_Int, umask (0));
2207 umask (XINT (mask));
2208
2209 return mask;
2210}
2211
85ffea93
RS
2212#ifdef unix
2213
2214DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2215 "Tell Unix to finish all pending disk updates.")
2216 ()
2217{
2218 sync ();
2219 return Qnil;
2220}
2221
2222#endif /* unix */
2223
570d7624
JB
2224DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2225 "Return t if file FILE1 is newer than file FILE2.\n\
2226If FILE1 does not exist, the answer is nil;\n\
2227otherwise, if FILE2 does not exist, the answer is t.")
2228 (file1, file2)
2229 Lisp_Object file1, file2;
2230{
32f4334d 2231 Lisp_Object abspath1, abspath2;
570d7624
JB
2232 struct stat st;
2233 int mtime1;
32f4334d 2234 Lisp_Object handler;
09121adc 2235 struct gcpro gcpro1, gcpro2;
570d7624
JB
2236
2237 CHECK_STRING (file1, 0);
2238 CHECK_STRING (file2, 0);
2239
09121adc
RS
2240 abspath1 = Qnil;
2241 GCPRO2 (abspath1, file2);
32f4334d
RS
2242 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2243 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
09121adc 2244 UNGCPRO;
570d7624 2245
32f4334d
RS
2246 /* If the file name has special constructs in it,
2247 call the corresponding file handler. */
642ef245 2248 handler = Ffind_file_name_handler (abspath1);
32f4334d
RS
2249 if (!NILP (handler))
2250 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2251
2252 if (stat (XSTRING (abspath1)->data, &st) < 0)
570d7624
JB
2253 return Qnil;
2254
2255 mtime1 = st.st_mtime;
2256
32f4334d 2257 if (stat (XSTRING (abspath2)->data, &st) < 0)
570d7624
JB
2258 return Qt;
2259
2260 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2261}
2262\f
570d7624
JB
2263DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
2264 1, 2, 0,
2265 "Insert contents of file FILENAME after point.\n\
2266Returns list of absolute pathname and length of data inserted.\n\
2267If second argument VISIT is non-nil, the buffer's visited filename\n\
2268and last save file modtime are set, and it is marked unmodified.\n\
2269If visiting and the file does not exist, visiting is completed\n\
2270before the error is signaled.")
2271 (filename, visit)
2272 Lisp_Object filename, visit;
2273{
2274 struct stat st;
2275 register int fd;
2276 register int inserted = 0;
2277 register int how_much;
2278 int count = specpdl_ptr - specpdl;
2279 struct gcpro gcpro1;
32f4334d
RS
2280 Lisp_Object handler, val;
2281
2282 val = Qnil;
2283
570d7624 2284 GCPRO1 (filename);
265a9e55 2285 if (!NILP (current_buffer->read_only))
570d7624
JB
2286 Fbarf_if_buffer_read_only();
2287
2288 CHECK_STRING (filename, 0);
2289 filename = Fexpand_file_name (filename, Qnil);
2290
32f4334d
RS
2291 /* If the file name has special constructs in it,
2292 call the corresponding file handler. */
642ef245 2293 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2294 if (!NILP (handler))
2295 {
2296 val = call3 (handler, Qinsert_file_contents, filename, visit);
2297 st.st_mtime = 0;
2298 goto handled;
2299 }
2300
570d7624
JB
2301 fd = -1;
2302
2303#ifndef APOLLO
2304 if (stat (XSTRING (filename)->data, &st) < 0
349a7710 2305 || (fd = open (XSTRING (filename)->data, 0)) < 0)
570d7624
JB
2306#else
2307 if ((fd = open (XSTRING (filename)->data, 0)) < 0
2308 || fstat (fd, &st) < 0)
2309#endif /* not APOLLO */
2310 {
2311 if (fd >= 0) close (fd);
265a9e55 2312 if (NILP (visit))
570d7624
JB
2313 report_file_error ("Opening input file", Fcons (filename, Qnil));
2314 st.st_mtime = -1;
2315 how_much = 0;
2316 goto notfound;
2317 }
2318
2319 record_unwind_protect (close_file_unwind, make_number (fd));
2320
be53b411
JB
2321#ifdef S_IFSOCK
2322 /* This code will need to be changed in order to work on named
2323 pipes, and it's probably just not worth it. So we should at
2324 least signal an error. */
2325 if ((st.st_mode & S_IFMT) == S_IFSOCK)
2326 Fsignal (Qfile_error,
2327 Fcons (build_string ("reading from named pipe"),
2328 Fcons (filename, Qnil)));
2329#endif
2330
570d7624
JB
2331 /* Supposedly happens on VMS. */
2332 if (st.st_size < 0)
2333 error ("File size is negative");
be53b411 2334
570d7624
JB
2335 {
2336 register Lisp_Object temp;
2337
2338 /* Make sure point-max won't overflow after this insertion. */
2339 XSET (temp, Lisp_Int, st.st_size + Z);
2340 if (st.st_size + Z != XINT (temp))
2341 error ("maximum buffer size exceeded");
2342 }
2343
265a9e55 2344 if (NILP (visit))
570d7624
JB
2345 prepare_to_modify_buffer (point, point);
2346
2347 move_gap (point);
2348 if (GAP_SIZE < st.st_size)
2349 make_gap (st.st_size - GAP_SIZE);
2350
2351 while (1)
2352 {
2353 int try = min (st.st_size - inserted, 64 << 10);
b5148e85
RS
2354 int this;
2355
2356 /* Allow quitting out of the actual I/O. */
2357 immediate_quit = 1;
2358 QUIT;
2359 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2360 immediate_quit = 0;
570d7624
JB
2361
2362 if (this <= 0)
2363 {
2364 how_much = this;
2365 break;
2366 }
2367
2368 GPT += this;
2369 GAP_SIZE -= this;
2370 ZV += this;
2371 Z += this;
2372 inserted += this;
2373 }
2374
2375 if (inserted > 0)
7d8451f1
RS
2376 {
2377 record_insert (point, inserted);
8d4e077b
JA
2378
2379 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2380 offset_intervals (current_buffer, point, inserted);
7d8451f1
RS
2381 MODIFF++;
2382 }
570d7624
JB
2383
2384 close (fd);
2385
2386 /* Discard the unwind protect */
2387 specpdl_ptr = specpdl + count;
2388
2389 if (how_much < 0)
2390 error ("IO error reading %s: %s",
2391 XSTRING (filename)->data, err_str (errno));
2392
2393 notfound:
32f4334d 2394 handled:
570d7624 2395
265a9e55 2396 if (!NILP (visit))
570d7624
JB
2397 {
2398 current_buffer->undo_list = Qnil;
2399#ifdef APOLLO
2400 stat (XSTRING (filename)->data, &st);
2401#endif
2402 current_buffer->modtime = st.st_mtime;
2403 current_buffer->save_modified = MODIFF;
2404 current_buffer->auto_save_modified = MODIFF;
2405 XFASTINT (current_buffer->save_length) = Z - BEG;
2406#ifdef CLASH_DETECTION
32f4334d
RS
2407 if (NILP (handler))
2408 {
2409 if (!NILP (current_buffer->filename))
2410 unlock_file (current_buffer->filename);
2411 unlock_file (filename);
2412 }
570d7624
JB
2413#endif /* CLASH_DETECTION */
2414 current_buffer->filename = filename;
2415 /* If visiting nonexistent file, return nil. */
32f4334d 2416 if (current_buffer->modtime == -1)
570d7624
JB
2417 report_file_error ("Opening input file", Fcons (filename, Qnil));
2418 }
2419
2420 signal_after_change (point, 0, inserted);
2421
32f4334d
RS
2422 if (!NILP (val))
2423 RETURN_UNGCPRO (val);
9b7828a5
JB
2424 RETURN_UNGCPRO (Fcons (filename,
2425 Fcons (make_number (inserted),
2426 Qnil)));
570d7624
JB
2427}
2428
2429DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2430 "r\nFWrite region to file: ",
2431 "Write current region into specified file.\n\
2432When called from a program, takes three arguments:\n\
2433START, END and FILENAME. START and END are buffer positions.\n\
2434Optional fourth argument APPEND if non-nil means\n\
2435 append to existing file contents (if any).\n\
2436Optional fifth argument VISIT if t means\n\
2437 set the last-save-file-modtime of buffer to this file's modtime\n\
2438 and mark buffer not modified.\n\
2439If VISIT is neither t nor nil, it means do not print\n\
2440 the \"Wrote file\" message.\n\
3b7792ed
RS
2441If VISIT is a string, it is a second file name;\n\
2442 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
2443 VISIT is also the file name to lock and unlock for clash detection.\n\
570d7624
JB
2444Kludgy feature: if START is a string, then that string is written\n\
2445to the file, instead of any buffer contents, and END is ignored.")
2446 (start, end, filename, append, visit)
2447 Lisp_Object start, end, filename, append, visit;
2448{
2449 register int desc;
2450 int failure;
2451 int save_errno;
2452 unsigned char *fn;
2453 struct stat st;
2454 int tem;
2455 int count = specpdl_ptr - specpdl;
2456#ifdef VMS
2457 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
2458#endif /* VMS */
3eac9910 2459 Lisp_Object handler;
3b7792ed
RS
2460 Lisp_Object visit_file = XTYPE (visit) == Lisp_String ? visit : filename;
2461 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
570d7624
JB
2462
2463 /* Special kludge to simplify auto-saving */
265a9e55 2464 if (NILP (start))
570d7624
JB
2465 {
2466 XFASTINT (start) = BEG;
2467 XFASTINT (end) = Z;
2468 }
2469 else if (XTYPE (start) != Lisp_String)
2470 validate_region (&start, &end);
2471
3b7792ed 2472 GCPRO4 (start, filename, visit, visit_file);
570d7624 2473 filename = Fexpand_file_name (filename, Qnil);
570d7624 2474
32f4334d
RS
2475 /* If the file name has special constructs in it,
2476 call the corresponding file handler. */
642ef245 2477 handler = Ffind_file_name_handler (filename);
3eac9910 2478
32f4334d
RS
2479 if (!NILP (handler))
2480 {
2481 Lisp_Object args[7];
2482 Lisp_Object val;
2483 args[0] = handler;
2484 args[1] = Qwrite_region;
2485 args[2] = start;
2486 args[3] = end;
2487 args[4] = filename;
2488 args[5] = append;
2489 args[6] = visit;
2490 val = Ffuncall (7, args);
2491
2492 /* Do this before reporting IO error
2493 to avoid a "file has changed on disk" warning on
2494 next attempt to save. */
3b7792ed 2495 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
32f4334d
RS
2496 {
2497 current_buffer->modtime = 0;
2498 current_buffer->save_modified = MODIFF;
2499 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 2500 current_buffer->filename = visit_file;
32f4334d 2501 }
09121adc 2502 UNGCPRO;
32f4334d
RS
2503 return val;
2504 }
2505
570d7624
JB
2506#ifdef CLASH_DETECTION
2507 if (!auto_saving)
3b7792ed 2508 lock_file (visit_file);
570d7624
JB
2509#endif /* CLASH_DETECTION */
2510
09121adc 2511 fn = XSTRING (filename)->data;
570d7624 2512 desc = -1;
265a9e55 2513 if (!NILP (append))
570d7624
JB
2514 desc = open (fn, O_WRONLY);
2515
2516 if (desc < 0)
2517#ifdef VMS
2518 if (auto_saving) /* Overwrite any previous version of autosave file */
2519 {
2520 vms_truncate (fn); /* if fn exists, truncate to zero length */
2521 desc = open (fn, O_RDWR);
2522 if (desc < 0)
2523 desc = creat_copy_attrs (XTYPE (current_buffer->filename) == Lisp_String
b72dea2a
JB
2524 ? XSTRING (current_buffer->filename)->data : 0,
2525 fn);
570d7624
JB
2526 }
2527 else /* Write to temporary name and rename if no errors */
2528 {
2529 Lisp_Object temp_name;
2530 temp_name = Ffile_name_directory (filename);
2531
265a9e55 2532 if (!NILP (temp_name))
570d7624
JB
2533 {
2534 temp_name = Fmake_temp_name (concat2 (temp_name,
2535 build_string ("$$SAVE$$")));
2536 fname = XSTRING (filename)->data;
2537 fn = XSTRING (temp_name)->data;
2538 desc = creat_copy_attrs (fname, fn);
2539 if (desc < 0)
2540 {
2541 /* If we can't open the temporary file, try creating a new
2542 version of the original file. VMS "creat" creates a
2543 new version rather than truncating an existing file. */
2544 fn = fname;
2545 fname = 0;
2546 desc = creat (fn, 0666);
2547#if 0 /* This can clobber an existing file and fail to replace it,
2548 if the user runs out of space. */
2549 if (desc < 0)
2550 {
2551 /* We can't make a new version;
2552 try to truncate and rewrite existing version if any. */
2553 vms_truncate (fn);
2554 desc = open (fn, O_RDWR);
2555 }
2556#endif
2557 }
2558 }
2559 else
2560 desc = creat (fn, 0666);
2561 }
2562#else /* not VMS */
2563 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
2564#endif /* not VMS */
2565
09121adc
RS
2566 UNGCPRO;
2567
570d7624
JB
2568 if (desc < 0)
2569 {
2570#ifdef CLASH_DETECTION
2571 save_errno = errno;
3b7792ed 2572 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
2573 errno = save_errno;
2574#endif /* CLASH_DETECTION */
2575 report_file_error ("Opening output file", Fcons (filename, Qnil));
2576 }
2577
2578 record_unwind_protect (close_file_unwind, make_number (desc));
2579
265a9e55 2580 if (!NILP (append))
570d7624
JB
2581 if (lseek (desc, 0, 2) < 0)
2582 {
2583#ifdef CLASH_DETECTION
3b7792ed 2584 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
2585#endif /* CLASH_DETECTION */
2586 report_file_error ("Lseek error", Fcons (filename, Qnil));
2587 }
2588
2589#ifdef VMS
2590/*
2591 * Kludge Warning: The VMS C RTL likes to insert carriage returns
2592 * if we do writes that don't end with a carriage return. Furthermore
2593 * it cannot handle writes of more then 16K. The modified
2594 * version of "sys_write" in SYSDEP.C (see comment there) copes with
2595 * this EXCEPT for the last record (iff it doesn't end with a carriage
2596 * return). This implies that if your buffer doesn't end with a carriage
2597 * return, you get one free... tough. However it also means that if
2598 * we make two calls to sys_write (a la the following code) you can
2599 * get one at the gap as well. The easiest way to fix this (honest)
2600 * is to move the gap to the next newline (or the end of the buffer).
2601 * Thus this change.
2602 *
2603 * Yech!
2604 */
2605 if (GPT > BEG && GPT_ADDR[-1] != '\n')
2606 move_gap (find_next_newline (GPT, 1));
2607#endif
2608
2609 failure = 0;
2610 immediate_quit = 1;
2611
2612 if (XTYPE (start) == Lisp_String)
2613 {
2614 failure = 0 > e_write (desc, XSTRING (start)->data,
2615 XSTRING (start)->size);
2616 save_errno = errno;
2617 }
2618 else if (XINT (start) != XINT (end))
2619 {
2620 if (XINT (start) < GPT)
2621 {
2622 register int end1 = XINT (end);
2623 tem = XINT (start);
2624 failure = 0 > e_write (desc, &FETCH_CHAR (tem),
2625 min (GPT, end1) - tem);
2626 save_errno = errno;
2627 }
2628
2629 if (XINT (end) > GPT && !failure)
2630 {
2631 tem = XINT (start);
2632 tem = max (tem, GPT);
2633 failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem);
2634 save_errno = errno;
2635 }
2636 }
2637
2638 immediate_quit = 0;
2639
2640#ifndef USG
2641#ifndef VMS
2642#ifndef BSD4_1
570d7624
JB
2643 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
2644 Disk full in NFS may be reported here. */
2645 if (fsync (desc) < 0)
2646 failure = 1, save_errno = errno;
2647#endif
2648#endif
570d7624
JB
2649#endif
2650
2651 /* Spurious "file has changed on disk" warnings have been
2652 observed on Suns as well.
2653 It seems that `close' can change the modtime, under nfs.
2654
2655 (This has supposedly been fixed in Sunos 4,
2656 but who knows about all the other machines with NFS?) */
2657#if 0
2658
2659 /* On VMS and APOLLO, must do the stat after the close
2660 since closing changes the modtime. */
2661#ifndef VMS
2662#ifndef APOLLO
2663 /* Recall that #if defined does not work on VMS. */
2664#define FOO
2665 fstat (desc, &st);
2666#endif
2667#endif
2668#endif
2669
2670 /* NFS can report a write failure now. */
2671 if (close (desc) < 0)
2672 failure = 1, save_errno = errno;
2673
2674#ifdef VMS
2675 /* If we wrote to a temporary name and had no errors, rename to real name. */
2676 if (fname)
2677 {
2678 if (!failure)
2679 failure = (rename (fn, fname) != 0), save_errno = errno;
2680 fn = fname;
2681 }
2682#endif /* VMS */
2683
2684#ifndef FOO
2685 stat (fn, &st);
2686#endif
2687 /* Discard the unwind protect */
2688 specpdl_ptr = specpdl + count;
2689
2690#ifdef CLASH_DETECTION
2691 if (!auto_saving)
3b7792ed 2692 unlock_file (visit_file);
570d7624
JB
2693#endif /* CLASH_DETECTION */
2694
2695 /* Do this before reporting IO error
2696 to avoid a "file has changed on disk" warning on
2697 next attempt to save. */
3b7792ed 2698 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
570d7624
JB
2699 current_buffer->modtime = st.st_mtime;
2700
2701 if (failure)
2702 error ("IO error writing %s: %s", fn, err_str (save_errno));
2703
3b7792ed 2704 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
570d7624
JB
2705 {
2706 current_buffer->save_modified = MODIFF;
2707 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 2708 current_buffer->filename = visit_file;
570d7624 2709 }
265a9e55 2710 else if (!NILP (visit))
570d7624
JB
2711 return Qnil;
2712
2713 if (!auto_saving)
3b7792ed 2714 message ("Wrote %s", XSTRING (visit_file)->data);
570d7624
JB
2715
2716 return Qnil;
2717}
2718
2719int
2720e_write (desc, addr, len)
2721 int desc;
2722 register char *addr;
2723 register int len;
2724{
2725 char buf[16 * 1024];
2726 register char *p, *end;
2727
2728 if (!EQ (current_buffer->selective_display, Qt))
2729 return write (desc, addr, len) - len;
2730 else
2731 {
2732 p = buf;
2733 end = p + sizeof buf;
2734 while (len--)
2735 {
2736 if (p == end)
2737 {
2738 if (write (desc, buf, sizeof buf) != sizeof buf)
2739 return -1;
2740 p = buf;
2741 }
2742 *p = *addr++;
2743 if (*p++ == '\015')
2744 p[-1] = '\n';
2745 }
2746 if (p != buf)
2747 if (write (desc, buf, p - buf) != p - buf)
2748 return -1;
2749 }
2750 return 0;
2751}
2752
2753DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
2754 Sverify_visited_file_modtime, 1, 1, 0,
2755 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
2756This means that the file has not been changed since it was visited or saved.")
2757 (buf)
2758 Lisp_Object buf;
2759{
2760 struct buffer *b;
2761 struct stat st;
32f4334d 2762 Lisp_Object handler;
570d7624
JB
2763
2764 CHECK_BUFFER (buf, 0);
2765 b = XBUFFER (buf);
2766
2767 if (XTYPE (b->filename) != Lisp_String) return Qt;
2768 if (b->modtime == 0) return Qt;
2769
32f4334d
RS
2770 /* If the file name has special constructs in it,
2771 call the corresponding file handler. */
642ef245 2772 handler = Ffind_file_name_handler (b->filename);
32f4334d 2773 if (!NILP (handler))
09121adc 2774 return call2 (handler, Qverify_visited_file_modtime, buf);
32f4334d 2775
570d7624
JB
2776 if (stat (XSTRING (b->filename)->data, &st) < 0)
2777 {
2778 /* If the file doesn't exist now and didn't exist before,
2779 we say that it isn't modified, provided the error is a tame one. */
2780 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
2781 st.st_mtime = -1;
2782 else
2783 st.st_mtime = 0;
2784 }
2785 if (st.st_mtime == b->modtime
2786 /* If both are positive, accept them if they are off by one second. */
2787 || (st.st_mtime > 0 && b->modtime > 0
2788 && (st.st_mtime == b->modtime + 1
2789 || st.st_mtime == b->modtime - 1)))
2790 return Qt;
2791 return Qnil;
2792}
2793
2794DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
2795 Sclear_visited_file_modtime, 0, 0, 0,
2796 "Clear out records of last mod time of visited file.\n\
2797Next attempt to save will certainly not complain of a discrepancy.")
2798 ()
2799{
2800 current_buffer->modtime = 0;
2801 return Qnil;
2802}
2803
2804DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
2805 Sset_visited_file_modtime, 0, 0, 0,
2806 "Update buffer's recorded modification time from the visited file's time.\n\
2807Useful if the buffer was not read from the file normally\n\
2808or if the file itself has been changed for some known benign reason.")
2809 ()
2810{
2811 register Lisp_Object filename;
2812 struct stat st;
3eac9910 2813 Lisp_Object handler;
570d7624
JB
2814
2815 filename = Fexpand_file_name (current_buffer->filename, Qnil);
32f4334d
RS
2816
2817 /* If the file name has special constructs in it,
2818 call the corresponding file handler. */
642ef245 2819 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2820 if (!NILP (handler))
2821 current_buffer->modtime = 0;
570d7624 2822
32f4334d 2823 else if (stat (XSTRING (filename)->data, &st) >= 0)
570d7624
JB
2824 current_buffer->modtime = st.st_mtime;
2825
2826 return Qnil;
2827}
2828\f
2829Lisp_Object
2830auto_save_error ()
2831{
2832 unsigned char *name = XSTRING (current_buffer->name)->data;
2833
2834 ring_bell ();
2835 message ("Autosaving...error for %s", name);
de49a6d3 2836 Fsleep_for (make_number (1), Qnil);
570d7624 2837 message ("Autosaving...error!for %s", name);
de49a6d3 2838 Fsleep_for (make_number (1), Qnil);
570d7624 2839 message ("Autosaving...error for %s", name);
de49a6d3 2840 Fsleep_for (make_number (1), Qnil);
570d7624
JB
2841 return Qnil;
2842}
2843
2844Lisp_Object
2845auto_save_1 ()
2846{
2847 unsigned char *fn;
2848 struct stat st;
2849
2850 /* Get visited file's mode to become the auto save file's mode. */
2851 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
2852 /* But make sure we can overwrite it later! */
2853 auto_save_mode_bits = st.st_mode | 0600;
2854 else
2855 auto_save_mode_bits = 0666;
2856
2857 return
2858 Fwrite_region (Qnil, Qnil,
2859 current_buffer->auto_save_file_name,
2860 Qnil, Qlambda);
2861}
2862
2863DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
2864 "Auto-save all buffers that need it.\n\
2865This is all buffers that have auto-saving enabled\n\
2866and are changed since last auto-saved.\n\
2867Auto-saving writes the buffer into a file\n\
2868so that your editing is not lost if the system crashes.\n\
2869This file is not the file you visited; that changes only when you save.\n\n\
2870Non-nil first argument means do not print any message if successful.\n\
4746118a 2871Non-nil second argument means save only current buffer.")
570d7624
JB
2872 (nomsg)
2873 Lisp_Object nomsg;
2874{
2875 struct buffer *old = current_buffer, *b;
2876 Lisp_Object tail, buf;
2877 int auto_saved = 0;
2878 char *omessage = echo_area_glyphs;
2879 extern minibuf_level;
2880
2881 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
2882 point to non-strings reached from Vbuffer_alist. */
2883
2884 auto_saving = 1;
2885 if (minibuf_level)
2886 nomsg = Qt;
2887
2888 /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
2889 eventually call do-auto-save, so don't err here in that case. */
265a9e55 2890 if (!NILP (Vrun_hooks))
570d7624
JB
2891 call1 (Vrun_hooks, intern ("auto-save-hook"));
2892
2893 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
2894 tail = XCONS (tail)->cdr)
2895 {
2896 buf = XCONS (XCONS (tail)->car)->cdr;
2897 b = XBUFFER (buf);
2898 /* Check for auto save enabled
2899 and file changed since last auto save
2900 and file changed since last real save. */
2901 if (XTYPE (b->auto_save_file_name) == Lisp_String
2902 && b->save_modified < BUF_MODIFF (b)
2903 && b->auto_save_modified < BUF_MODIFF (b))
2904 {
2905 if ((XFASTINT (b->save_length) * 10
2906 > (BUF_Z (b) - BUF_BEG (b)) * 13)
2907 /* A short file is likely to change a large fraction;
2908 spare the user annoying messages. */
2909 && XFASTINT (b->save_length) > 5000
2910 /* These messages are frequent and annoying for `*mail*'. */
2911 && !EQ (b->filename, Qnil))
2912 {
2913 /* It has shrunk too much; turn off auto-saving here. */
2914 message ("Buffer %s has shrunk a lot; auto save turned off there",
2915 XSTRING (b->name)->data);
2916 /* User can reenable saving with M-x auto-save. */
2917 b->auto_save_file_name = Qnil;
2918 /* Prevent warning from repeating if user does so. */
2919 XFASTINT (b->save_length) = 0;
2fd3c56b 2920 Fsleep_for (make_number (1), Qnil);
570d7624
JB
2921 continue;
2922 }
2923 set_buffer_internal (b);
265a9e55 2924 if (!auto_saved && NILP (nomsg))
570d7624
JB
2925 message1 ("Auto-saving...");
2926 internal_condition_case (auto_save_1, Qt, auto_save_error);
2927 auto_saved++;
2928 b->auto_save_modified = BUF_MODIFF (b);
2929 XFASTINT (current_buffer->save_length) = Z - BEG;
2930 set_buffer_internal (old);
2931 }
2932 }
2933
b67f2ca5
RS
2934 /* Prevent another auto save till enough input events come in. */
2935 record_auto_save ();
570d7624 2936
265a9e55 2937 if (auto_saved && NILP (nomsg))
570d7624
JB
2938 message1 (omessage ? omessage : "Auto-saving...done");
2939
2940 auto_saving = 0;
2941 return Qnil;
2942}
2943
2944DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
2945 Sset_buffer_auto_saved, 0, 0, 0,
2946 "Mark current buffer as auto-saved with its current text.\n\
2947No auto-save file will be written until the buffer changes again.")
2948 ()
2949{
2950 current_buffer->auto_save_modified = MODIFF;
2951 XFASTINT (current_buffer->save_length) = Z - BEG;
2952 return Qnil;
2953}
2954
2955DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
2956 0, 0, 0,
2957 "Return t if buffer has been auto-saved since last read in or saved.")
2958 ()
2959{
2960 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
2961}
2962\f
2963/* Reading and completing file names */
2964extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
2965
2966DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
2967 3, 3, 0,
2968 "Internal subroutine for read-file-name. Do not call this.")
2969 (string, dir, action)
2970 Lisp_Object string, dir, action;
2971 /* action is nil for complete, t for return list of completions,
2972 lambda for verify final value */
2973{
2974 Lisp_Object name, specdir, realdir, val, orig_string;
09121adc
RS
2975 int changed;
2976 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2977
2978 realdir = dir;
2979 name = string;
2980 orig_string = Qnil;
2981 specdir = Qnil;
2982 changed = 0;
2983 /* No need to protect ACTION--we only compare it with t and nil. */
2984 GCPRO4 (string, realdir, name, specdir);
570d7624
JB
2985
2986 if (XSTRING (string)->size == 0)
2987 {
570d7624 2988 if (EQ (action, Qlambda))
09121adc
RS
2989 {
2990 UNGCPRO;
2991 return Qnil;
2992 }
570d7624
JB
2993 }
2994 else
2995 {
2996 orig_string = string;
2997 string = Fsubstitute_in_file_name (string);
09121adc 2998 changed = NILP (Fstring_equal (string, orig_string));
570d7624 2999 name = Ffile_name_nondirectory (string);
09121adc
RS
3000 val = Ffile_name_directory (string);
3001 if (! NILP (val))
3002 realdir = Fexpand_file_name (val, realdir);
570d7624
JB
3003 }
3004
265a9e55 3005 if (NILP (action))
570d7624
JB
3006 {
3007 specdir = Ffile_name_directory (string);
3008 val = Ffile_name_completion (name, realdir);
09121adc 3009 UNGCPRO;
570d7624
JB
3010 if (XTYPE (val) != Lisp_String)
3011 {
09121adc 3012 if (changed)
570d7624 3013 return string;
09121adc 3014 return val;
570d7624
JB
3015 }
3016
265a9e55 3017 if (!NILP (specdir))
570d7624
JB
3018 val = concat2 (specdir, val);
3019#ifndef VMS
3020 {
3021 register unsigned char *old, *new;
3022 register int n;
3023 int osize, count;
3024
3025 osize = XSTRING (val)->size;
3026 /* Quote "$" as "$$" to get it past substitute-in-file-name */
3027 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
3028 if (*old++ == '$') count++;
3029 if (count > 0)
3030 {
3031 old = XSTRING (val)->data;
3032 val = Fmake_string (make_number (osize + count), make_number (0));
3033 new = XSTRING (val)->data;
3034 for (n = osize; n > 0; n--)
3035 if (*old != '$')
3036 *new++ = *old++;
3037 else
3038 {
3039 *new++ = '$';
3040 *new++ = '$';
3041 old++;
3042 }
3043 }
3044 }
3045#endif /* Not VMS */
09121adc 3046 return val;
570d7624 3047 }
09121adc 3048 UNGCPRO;
570d7624
JB
3049
3050 if (EQ (action, Qt))
3051 return Ffile_name_all_completions (name, realdir);
3052 /* Only other case actually used is ACTION = lambda */
3053#ifdef VMS
3054 /* Supposedly this helps commands such as `cd' that read directory names,
3055 but can someone explain how it helps them? -- RMS */
3056 if (XSTRING (name)->size == 0)
3057 return Qt;
3058#endif /* VMS */
3059 return Ffile_exists_p (string);
3060}
3061
3062DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3063 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3064Value is not expanded---you must call `expand-file-name' yourself.\n\
3065Default name to DEFAULT if user enters a null string.\n\
3066 (If DEFAULT is omitted, the visited file name is used.)\n\
3067Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3068 Non-nil and non-t means also require confirmation after completion.\n\
3069Fifth arg INITIAL specifies text to start with.\n\
3070DIR defaults to current buffer's directory default.")
3071 (prompt, dir, defalt, mustmatch, initial)
3072 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3073{
85b5fe07 3074 Lisp_Object val, insdef, insdef1, tem;
570d7624
JB
3075 struct gcpro gcpro1, gcpro2;
3076 register char *homedir;
3077 int count;
3078
265a9e55 3079 if (NILP (dir))
570d7624 3080 dir = current_buffer->directory;
265a9e55 3081 if (NILP (defalt))
570d7624
JB
3082 defalt = current_buffer->filename;
3083
3084 /* If dir starts with user's homedir, change that to ~. */
3085 homedir = (char *) egetenv ("HOME");
3086 if (homedir != 0
3087 && XTYPE (dir) == Lisp_String
3088 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3089 && XSTRING (dir)->data[strlen (homedir)] == '/')
3090 {
3091 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3092 XSTRING (dir)->size - strlen (homedir) + 1);
3093 XSTRING (dir)->data[0] = '~';
3094 }
3095
3096 if (insert_default_directory)
3097 {
3098 insdef = dir;
85b5fe07 3099 insdef1 = dir;
265a9e55 3100 if (!NILP (initial))
570d7624 3101 {
15c65264 3102 Lisp_Object args[2], pos;
570d7624
JB
3103
3104 args[0] = insdef;
3105 args[1] = initial;
3106 insdef = Fconcat (2, args);
509b05ed 3107 pos = make_number (XSTRING (dir)->size);
85b5fe07 3108 insdef1 = Fcons (insdef, pos);
570d7624 3109 }
570d7624
JB
3110 }
3111 else
85b5fe07 3112 insdef = Qnil, insdef1 = Qnil;
570d7624
JB
3113
3114#ifdef VMS
3115 count = specpdl_ptr - specpdl;
3116 specbind (intern ("completion-ignore-case"), Qt);
3117#endif
3118
3119 GCPRO2 (insdef, defalt);
3120 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
85b5fe07 3121 dir, mustmatch, insdef1,
15c65264 3122 Qfile_name_history);
570d7624
JB
3123
3124#ifdef VMS
3125 unbind_to (count, Qnil);
3126#endif
3127
3128 UNGCPRO;
265a9e55 3129 if (NILP (val))
570d7624
JB
3130 error ("No file name specified");
3131 tem = Fstring_equal (val, insdef);
265a9e55 3132 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
3133 return defalt;
3134 return Fsubstitute_in_file_name (val);
3135}
3136
3137#if 0 /* Old version */
3138DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3139 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3140Value is not expanded---you must call `expand-file-name' yourself.\n\
3141Default name to DEFAULT if user enters a null string.\n\
3142 (If DEFAULT is omitted, the visited file name is used.)\n\
3143Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3144 Non-nil and non-t means also require confirmation after completion.\n\
3145Fifth arg INITIAL specifies text to start with.\n\
3146DIR defaults to current buffer's directory default.")
3147 (prompt, dir, defalt, mustmatch, initial)
3148 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3149{
3150 Lisp_Object val, insdef, tem;
3151 struct gcpro gcpro1, gcpro2;
3152 register char *homedir;
3153 int count;
3154
265a9e55 3155 if (NILP (dir))
570d7624 3156 dir = current_buffer->directory;
265a9e55 3157 if (NILP (defalt))
570d7624
JB
3158 defalt = current_buffer->filename;
3159
3160 /* If dir starts with user's homedir, change that to ~. */
3161 homedir = (char *) egetenv ("HOME");
3162 if (homedir != 0
3163 && XTYPE (dir) == Lisp_String
3164 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3165 && XSTRING (dir)->data[strlen (homedir)] == '/')
3166 {
3167 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3168 XSTRING (dir)->size - strlen (homedir) + 1);
3169 XSTRING (dir)->data[0] = '~';
3170 }
3171
265a9e55 3172 if (!NILP (initial))
570d7624
JB
3173 insdef = initial;
3174 else if (insert_default_directory)
3175 insdef = dir;
3176 else
3177 insdef = build_string ("");
3178
3179#ifdef VMS
3180 count = specpdl_ptr - specpdl;
3181 specbind (intern ("completion-ignore-case"), Qt);
3182#endif
3183
3184 GCPRO2 (insdef, defalt);
3185 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3186 dir, mustmatch,
15c65264
RS
3187 insert_default_directory ? insdef : Qnil,
3188 Qfile_name_history);
570d7624
JB
3189
3190#ifdef VMS
3191 unbind_to (count, Qnil);
3192#endif
3193
3194 UNGCPRO;
265a9e55 3195 if (NILP (val))
570d7624
JB
3196 error ("No file name specified");
3197 tem = Fstring_equal (val, insdef);
265a9e55 3198 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
3199 return defalt;
3200 return Fsubstitute_in_file_name (val);
3201}
3202#endif /* Old version */
3203\f
3204syms_of_fileio ()
3205{
0bf2eed2
RS
3206 Qexpand_file_name = intern ("expand-file-name");
3207 Qdirectory_file_name = intern ("directory-file-name");
3208 Qfile_name_directory = intern ("file-name-directory");
3209 Qfile_name_nondirectory = intern ("file-name-nondirectory");
642ef245 3210 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
0bf2eed2 3211 Qfile_name_as_directory = intern ("file-name-as-directory");
32f4334d
RS
3212 Qcopy_file = intern ("copy-file");
3213 Qmake_directory = intern ("make-directory");
3214 Qdelete_directory = intern ("delete-directory");
3215 Qdelete_file = intern ("delete-file");
3216 Qrename_file = intern ("rename-file");
3217 Qadd_name_to_file = intern ("add-name-to-file");
3218 Qmake_symbolic_link = intern ("make-symbolic-link");
3219 Qfile_exists_p = intern ("file-exists-p");
3220 Qfile_executable_p = intern ("file-executable-p");
3221 Qfile_readable_p = intern ("file-readable-p");
3222 Qfile_symlink_p = intern ("file-symlink-p");
3223 Qfile_writable_p = intern ("file-writable-p");
3224 Qfile_directory_p = intern ("file-directory-p");
3225 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
3226 Qfile_modes = intern ("file-modes");
3227 Qset_file_modes = intern ("set-file-modes");
3228 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
3229 Qinsert_file_contents = intern ("insert-file-contents");
3230 Qwrite_region = intern ("write-region");
3231 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3232
642ef245
JB
3233 staticpro (&Qexpand_file_name);
3234 staticpro (&Qdirectory_file_name);
3235 staticpro (&Qfile_name_directory);
3236 staticpro (&Qfile_name_nondirectory);
3237 staticpro (&Qunhandled_file_name_directory);
3238 staticpro (&Qfile_name_as_directory);
15c65264
RS
3239 staticpro (&Qcopy_file);
3240 staticpro (&Qmake_directory);
3241 staticpro (&Qdelete_directory);
3242 staticpro (&Qdelete_file);
3243 staticpro (&Qrename_file);
3244 staticpro (&Qadd_name_to_file);
3245 staticpro (&Qmake_symbolic_link);
3246 staticpro (&Qfile_exists_p);
3247 staticpro (&Qfile_executable_p);
3248 staticpro (&Qfile_readable_p);
3249 staticpro (&Qfile_symlink_p);
3250 staticpro (&Qfile_writable_p);
3251 staticpro (&Qfile_directory_p);
3252 staticpro (&Qfile_accessible_directory_p);
3253 staticpro (&Qfile_modes);
3254 staticpro (&Qset_file_modes);
3255 staticpro (&Qfile_newer_than_file_p);
3256 staticpro (&Qinsert_file_contents);
3257 staticpro (&Qwrite_region);
3258 staticpro (&Qverify_visited_file_modtime);
642ef245
JB
3259
3260 Qfile_name_history = intern ("file-name-history");
3261 Fset (Qfile_name_history, Qnil);
15c65264
RS
3262 staticpro (&Qfile_name_history);
3263
570d7624
JB
3264 Qfile_error = intern ("file-error");
3265 staticpro (&Qfile_error);
3266 Qfile_already_exists = intern("file-already-exists");
3267 staticpro (&Qfile_already_exists);
3268
3269 Fput (Qfile_error, Qerror_conditions,
3270 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
3271 Fput (Qfile_error, Qerror_message,
3272 build_string ("File error"));
3273
3274 Fput (Qfile_already_exists, Qerror_conditions,
3275 Fcons (Qfile_already_exists,
3276 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
3277 Fput (Qfile_already_exists, Qerror_message,
3278 build_string ("File already exists"));
3279
3280 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
3281 "*Non-nil means when reading a filename start with default dir in minibuffer.");
3282 insert_default_directory = 1;
3283
3284 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
3285 "*Non-nil means write new files with record format `stmlf'.\n\
3286nil means use format `var'. This variable is meaningful only on VMS.");
3287 vms_stmlf_recfm = 0;
3288
1d1826db
RS
3289 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
3290 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
3291If a file name matches REGEXP, then all I/O on that file is done by calling\n\
3292HANDLER.\n\
3293\n\
3294The first argument given to HANDLER is the name of the I/O primitive\n\
3295to be handled; the remaining arguments are the arguments that were\n\
3296passed to that primitive. For example, if you do\n\
3297 (file-exists-p FILENAME)\n\
3298and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
642ef245
JB
3299 (funcall HANDLER 'file-exists-p FILENAME)\n\
3300The function `find-file-name-handler' checks this list for a handler\n\
3301for its argument.");
09121adc
RS
3302 Vfile_name_handler_alist = Qnil;
3303
642ef245 3304 defsubr (&Sfind_file_name_handler);
570d7624
JB
3305 defsubr (&Sfile_name_directory);
3306 defsubr (&Sfile_name_nondirectory);
642ef245 3307 defsubr (&Sunhandled_file_name_directory);
570d7624
JB
3308 defsubr (&Sfile_name_as_directory);
3309 defsubr (&Sdirectory_file_name);
3310 defsubr (&Smake_temp_name);
3311 defsubr (&Sexpand_file_name);
3312 defsubr (&Ssubstitute_in_file_name);
3313 defsubr (&Scopy_file);
9bbe01fb 3314 defsubr (&Smake_directory_internal);
aa734e17 3315 defsubr (&Sdelete_directory);
570d7624
JB
3316 defsubr (&Sdelete_file);
3317 defsubr (&Srename_file);
3318 defsubr (&Sadd_name_to_file);
3319#ifdef S_IFLNK
3320 defsubr (&Smake_symbolic_link);
3321#endif /* S_IFLNK */
3322#ifdef VMS
3323 defsubr (&Sdefine_logical_name);
3324#endif /* VMS */
3325#ifdef HPUX_NET
3326 defsubr (&Ssysnetunam);
3327#endif /* HPUX_NET */
3328 defsubr (&Sfile_name_absolute_p);
3329 defsubr (&Sfile_exists_p);
3330 defsubr (&Sfile_executable_p);
3331 defsubr (&Sfile_readable_p);
3332 defsubr (&Sfile_writable_p);
3333 defsubr (&Sfile_symlink_p);
3334 defsubr (&Sfile_directory_p);
b72dea2a 3335 defsubr (&Sfile_accessible_directory_p);
570d7624
JB
3336 defsubr (&Sfile_modes);
3337 defsubr (&Sset_file_modes);
36a8c287
JB
3338 defsubr (&Sset_umask);
3339 defsubr (&Sumask);
570d7624
JB
3340 defsubr (&Sfile_newer_than_file_p);
3341 defsubr (&Sinsert_file_contents);
3342 defsubr (&Swrite_region);
3343 defsubr (&Sverify_visited_file_modtime);
3344 defsubr (&Sclear_visited_file_modtime);
3345 defsubr (&Sset_visited_file_modtime);
3346 defsubr (&Sdo_auto_save);
3347 defsubr (&Sset_buffer_auto_saved);
3348 defsubr (&Srecent_auto_save_p);
3349
3350 defsubr (&Sread_file_name_internal);
3351 defsubr (&Sread_file_name);
85ffea93 3352
483a2e10 3353#ifdef unix
85ffea93 3354 defsubr (&Sunix_sync);
483a2e10 3355#endif
570d7624 3356}