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