* process.c (wait_reading_process_input): Undo change of April
[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);
eabf01d4
RS
850 /* Adding `length > 1 &&' makes ~ expand into / when homedir
851 is the root dir. People disagree about whether that is right.
852 Anyway, we can't take the risk of this change now. */
853 if (newdir[length - 1] == '/')
bfb61299
JB
854 {
855 unsigned char *temp = (unsigned char *) alloca (length);
856 bcopy (newdir, temp, length - 1);
857 temp[length - 1] = 0;
858 newdir = temp;
859 }
860 tlen = length + 1;
861 }
862 else
863 tlen = 0;
570d7624 864
bfb61299
JB
865 /* Now concatenate the directory and name to new space in the stack frame */
866 tlen += strlen (nm) + 1;
570d7624
JB
867 target = (unsigned char *) alloca (tlen);
868 *target = 0;
869
870 if (newdir)
871 {
872#ifndef VMS
873 if (nm[0] == 0 || nm[0] == '/')
874 strcpy (target, newdir);
875 else
876#endif
c77d647e 877 file_name_as_directory (target, newdir);
570d7624
JB
878 }
879
880 strcat (target, nm);
881#ifdef VMS
882 if (index (target, '/'))
883 strcpy (target, sys_translate_unix (target));
884#endif /* VMS */
885
c77d647e 886 /* Now canonicalize by removing /. and /foo/.. if they appear. */
570d7624
JB
887
888 p = target;
889 o = target;
890
891 while (*p)
892 {
893#ifdef VMS
894 if (*p != ']' && *p != '>' && *p != '-')
895 {
896 if (*p == '\\')
897 p++;
898 *o++ = *p++;
899 }
900 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
901 /* brackets are offset from each other by 2 */
902 {
903 p += 2;
904 if (*p != '.' && *p != '-' && o[-1] != '.')
905 /* convert [foo][bar] to [bar] */
906 while (o[-1] != '[' && o[-1] != '<')
907 o--;
908 else if (*p == '-' && *o != '.')
909 *--p = '.';
910 }
911 else if (p[0] == '-' && o[-1] == '.' &&
912 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
913 /* flush .foo.- ; leave - if stopped by '[' or '<' */
914 {
915 do
916 o--;
917 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
918 if (p[1] == '.') /* foo.-.bar ==> bar*/
919 p += 2;
920 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
921 p++, o--;
922 /* else [foo.-] ==> [-] */
923 }
924 else
925 {
926#ifndef VMS4_4
927 if (*p == '-' &&
928 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
929 p[1] != ']' && p[1] != '>' && p[1] != '.')
930 *p = '_';
931#endif /* VMS4_4 */
932 *o++ = *p++;
933 }
934#else /* not VMS */
935 if (*p != '/')
936 {
937 *o++ = *p++;
938 }
939 else if (!strncmp (p, "//", 2)
940#ifdef APOLLO
941 /* // at start of filename is meaningful in Apollo system */
942 && o != target
943#endif /* APOLLO */
944 )
945 {
946 o = target;
947 p++;
948 }
c77d647e
JB
949 else if (p[0] == '/'
950 && p[1] == '.'
951 && (p[2] == '/'
952 || p[2] == 0))
953 {
954 /* If "/." is the entire filename, keep the "/". Otherwise,
955 just delete the whole "/.". */
956 if (o == target && p[2] == '\0')
957 *o++ = *p;
958 p += 2;
959 }
570d7624
JB
960 else if (!strncmp (p, "/..", 3)
961 /* `/../' is the "superroot" on certain file systems. */
962 && o != target
963 && (p[3] == '/' || p[3] == 0))
964 {
965 while (o != target && *--o != '/')
966 ;
967#ifdef APOLLO
968 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
969 ++o;
970 else
971#endif /* APOLLO */
972 if (o == target && *o == '/')
973 ++o;
974 p += 3;
975 }
976 else
977 {
978 *o++ = *p++;
979 }
980#endif /* not VMS */
981 }
982
983 return make_string (target, o - target);
984}
985#if 0
e5d77022
JB
986/* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'.
987DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
570d7624
JB
988 "Convert FILENAME to absolute, and canonicalize it.\n\
989Second arg DEFAULT is directory to start with if FILENAME is relative\n\
990 (does not start with slash); if DEFAULT is nil or missing,\n\
991the current buffer's value of default-directory is used.\n\
992Filenames containing `.' or `..' as components are simplified;\n\
993initial `~/' expands to your home directory.\n\
994See also the function `substitute-in-file-name'.")
995 (name, defalt)
996 Lisp_Object name, defalt;
997{
998 unsigned char *nm;
999
1000 register unsigned char *newdir, *p, *o;
1001 int tlen;
1002 unsigned char *target;
1003 struct passwd *pw;
1004 int lose;
1005#ifdef VMS
1006 unsigned char * colon = 0;
1007 unsigned char * close = 0;
1008 unsigned char * slash = 0;
1009 unsigned char * brack = 0;
1010 int lbrack = 0, rbrack = 0;
1011 int dots = 0;
1012#endif /* VMS */
1013
1014 CHECK_STRING (name, 0);
1015
1016#ifdef VMS
1017 /* Filenames on VMS are always upper case. */
1018 name = Fupcase (name);
1019#endif
1020
1021 nm = XSTRING (name)->data;
1022
1023 /* If nm is absolute, flush ...// and detect /./ and /../.
1024 If no /./ or /../ we can return right away. */
1025 if (
1026 nm[0] == '/'
1027#ifdef VMS
1028 || index (nm, ':')
1029#endif /* VMS */
1030 )
1031 {
1032 p = nm;
1033 lose = 0;
1034 while (*p)
1035 {
1036 if (p[0] == '/' && p[1] == '/'
1037#ifdef APOLLO
1038 /* // at start of filename is meaningful on Apollo system */
1039 && nm != p
1040#endif /* APOLLO */
1041 )
1042 nm = p + 1;
1043 if (p[0] == '/' && p[1] == '~')
1044 nm = p + 1, lose = 1;
1045 if (p[0] == '/' && p[1] == '.'
1046 && (p[2] == '/' || p[2] == 0
1047 || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
1048 lose = 1;
1049#ifdef VMS
1050 if (p[0] == '\\')
1051 lose = 1;
1052 if (p[0] == '/') {
1053 /* if dev:[dir]/, move nm to / */
1054 if (!slash && p > nm && (brack || colon)) {
1055 nm = (brack ? brack + 1 : colon + 1);
1056 lbrack = rbrack = 0;
1057 brack = 0;
1058 colon = 0;
1059 }
1060 slash = p;
1061 }
1062 if (p[0] == '-')
1063#ifndef VMS4_4
1064 /* VMS pre V4.4,convert '-'s in filenames. */
1065 if (lbrack == rbrack)
1066 {
1067 if (dots < 2) /* this is to allow negative version numbers */
1068 p[0] = '_';
1069 }
1070 else
1071#endif /* VMS4_4 */
1072 if (lbrack > rbrack &&
1073 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
1074 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
1075 lose = 1;
1076#ifndef VMS4_4
1077 else
1078 p[0] = '_';
1079#endif /* VMS4_4 */
1080 /* count open brackets, reset close bracket pointer */
1081 if (p[0] == '[' || p[0] == '<')
1082 lbrack++, brack = 0;
1083 /* count close brackets, set close bracket pointer */
1084 if (p[0] == ']' || p[0] == '>')
1085 rbrack++, brack = p;
1086 /* detect ][ or >< */
1087 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
1088 lose = 1;
1089 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
1090 nm = p + 1, lose = 1;
1091 if (p[0] == ':' && (colon || slash))
1092 /* if dev1:[dir]dev2:, move nm to dev2: */
1093 if (brack)
1094 {
1095 nm = brack + 1;
1096 brack = 0;
1097 }
1098 /* if /pathname/dev:, move nm to dev: */
1099 else if (slash)
1100 nm = slash + 1;
1101 /* if node::dev:, move colon following dev */
1102 else if (colon && colon[-1] == ':')
1103 colon = p;
1104 /* if dev1:dev2:, move nm to dev2: */
1105 else if (colon && colon[-1] != ':')
1106 {
1107 nm = colon + 1;
1108 colon = 0;
1109 }
1110 if (p[0] == ':' && !colon)
1111 {
1112 if (p[1] == ':')
1113 p++;
1114 colon = p;
1115 }
1116 if (lbrack == rbrack)
1117 if (p[0] == ';')
1118 dots = 2;
1119 else if (p[0] == '.')
1120 dots++;
1121#endif /* VMS */
1122 p++;
1123 }
1124 if (!lose)
1125 {
1126#ifdef VMS
1127 if (index (nm, '/'))
1128 return build_string (sys_translate_unix (nm));
1129#endif /* VMS */
1130 if (nm == XSTRING (name)->data)
1131 return name;
1132 return build_string (nm);
1133 }
1134 }
1135
1136 /* Now determine directory to start with and put it in NEWDIR */
1137
1138 newdir = 0;
1139
1140 if (nm[0] == '~') /* prefix ~ */
1141 if (nm[1] == '/'
1142#ifdef VMS
1143 || nm[1] == ':'
1144#endif /* VMS */
1145 || nm[1] == 0)/* ~/filename */
1146 {
1147 if (!(newdir = (unsigned char *) egetenv ("HOME")))
1148 newdir = (unsigned char *) "";
1149 nm++;
1150#ifdef VMS
1151 nm++; /* Don't leave the slash in nm. */
1152#endif /* VMS */
1153 }
1154 else /* ~user/filename */
1155 {
1156 /* Get past ~ to user */
1157 unsigned char *user = nm + 1;
1158 /* Find end of name. */
1159 unsigned char *ptr = (unsigned char *) index (user, '/');
1160 int len = ptr ? ptr - user : strlen (user);
1161#ifdef VMS
1162 unsigned char *ptr1 = index (user, ':');
1163 if (ptr1 != 0 && ptr1 - user < len)
1164 len = ptr1 - user;
1165#endif /* VMS */
1166 /* Copy the user name into temp storage. */
1167 o = (unsigned char *) alloca (len + 1);
1168 bcopy ((char *) user, o, len);
1169 o[len] = 0;
1170
1171 /* Look up the user name. */
1172 pw = (struct passwd *) getpwnam (o + 1);
1173 if (!pw)
1174 error ("\"%s\" isn't a registered user", o + 1);
1175
1176 newdir = (unsigned char *) pw->pw_dir;
1177
1178 /* Discard the user name from NM. */
1179 nm += len;
1180 }
1181
1182 if (nm[0] != '/'
1183#ifdef VMS
1184 && !index (nm, ':')
1185#endif /* not VMS */
1186 && !newdir)
1187 {
265a9e55 1188 if (NILP (defalt))
570d7624
JB
1189 defalt = current_buffer->directory;
1190 CHECK_STRING (defalt, 1);
1191 newdir = XSTRING (defalt)->data;
1192 }
1193
1194 /* Now concatenate the directory and name to new space in the stack frame */
1195
1196 tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1;
1197 target = (unsigned char *) alloca (tlen);
1198 *target = 0;
1199
1200 if (newdir)
1201 {
1202#ifndef VMS
1203 if (nm[0] == 0 || nm[0] == '/')
1204 strcpy (target, newdir);
1205 else
1206#endif
1207 file_name_as_directory (target, newdir);
1208 }
1209
1210 strcat (target, nm);
1211#ifdef VMS
1212 if (index (target, '/'))
1213 strcpy (target, sys_translate_unix (target));
1214#endif /* VMS */
1215
1216 /* Now canonicalize by removing /. and /foo/.. if they appear */
1217
1218 p = target;
1219 o = target;
1220
1221 while (*p)
1222 {
1223#ifdef VMS
1224 if (*p != ']' && *p != '>' && *p != '-')
1225 {
1226 if (*p == '\\')
1227 p++;
1228 *o++ = *p++;
1229 }
1230 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
1231 /* brackets are offset from each other by 2 */
1232 {
1233 p += 2;
1234 if (*p != '.' && *p != '-' && o[-1] != '.')
1235 /* convert [foo][bar] to [bar] */
1236 while (o[-1] != '[' && o[-1] != '<')
1237 o--;
1238 else if (*p == '-' && *o != '.')
1239 *--p = '.';
1240 }
1241 else if (p[0] == '-' && o[-1] == '.' &&
1242 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1243 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1244 {
1245 do
1246 o--;
1247 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1248 if (p[1] == '.') /* foo.-.bar ==> bar*/
1249 p += 2;
1250 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1251 p++, o--;
1252 /* else [foo.-] ==> [-] */
1253 }
1254 else
1255 {
1256#ifndef VMS4_4
1257 if (*p == '-' &&
1258 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
1259 p[1] != ']' && p[1] != '>' && p[1] != '.')
1260 *p = '_';
1261#endif /* VMS4_4 */
1262 *o++ = *p++;
1263 }
1264#else /* not VMS */
1265 if (*p != '/')
1266 {
1267 *o++ = *p++;
1268 }
1269 else if (!strncmp (p, "//", 2)
1270#ifdef APOLLO
1271 /* // at start of filename is meaningful in Apollo system */
1272 && o != target
1273#endif /* APOLLO */
1274 )
1275 {
1276 o = target;
1277 p++;
1278 }
1279 else if (p[0] == '/' && p[1] == '.' &&
1280 (p[2] == '/' || p[2] == 0))
1281 p += 2;
1282 else if (!strncmp (p, "/..", 3)
1283 /* `/../' is the "superroot" on certain file systems. */
1284 && o != target
1285 && (p[3] == '/' || p[3] == 0))
1286 {
1287 while (o != target && *--o != '/')
1288 ;
1289#ifdef APOLLO
1290 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
1291 ++o;
1292 else
1293#endif /* APOLLO */
1294 if (o == target && *o == '/')
1295 ++o;
1296 p += 3;
1297 }
1298 else
1299 {
1300 *o++ = *p++;
1301 }
1302#endif /* not VMS */
1303 }
1304
1305 return make_string (target, o - target);
1306}
1307#endif
1308\f
1309DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name,
1310 Ssubstitute_in_file_name, 1, 1, 0,
1311 "Substitute environment variables referred to in FILENAME.\n\
1312`$FOO' where FOO is an environment variable name means to substitute\n\
1313the value of that variable. The variable name should be terminated\n\
1314with a character not a letter, digit or underscore; otherwise, enclose\n\
1315the entire variable name in braces.\n\
1316If `/~' appears, all of FILENAME through that `/' is discarded.\n\n\
1317On VMS, `$' substitution is not done; this function does little and only\n\
1318duplicates what `expand-file-name' does.")
1319 (string)
1320 Lisp_Object string;
1321{
1322 unsigned char *nm;
1323
1324 register unsigned char *s, *p, *o, *x, *endp;
1325 unsigned char *target;
1326 int total = 0;
1327 int substituted = 0;
1328 unsigned char *xnm;
1329
1330 CHECK_STRING (string, 0);
1331
1332 nm = XSTRING (string)->data;
1333 endp = nm + XSTRING (string)->size;
1334
1335 /* If /~ or // appears, discard everything through first slash. */
1336
1337 for (p = nm; p != endp; p++)
1338 {
1339 if ((p[0] == '~' ||
1340#ifdef APOLLO
1341 /* // at start of file name is meaningful in Apollo system */
1342 (p[0] == '/' && p - 1 != nm)
1343#else /* not APOLLO */
1344 p[0] == '/'
1345#endif /* not APOLLO */
1346 )
1347 && p != nm &&
1348#ifdef VMS
1349 (p[-1] == ':' || p[-1] == ']' || p[-1] == '>' ||
1350#endif /* VMS */
1351 p[-1] == '/')
1352#ifdef VMS
1353 )
1354#endif /* VMS */
1355 {
1356 nm = p;
1357 substituted = 1;
1358 }
1359 }
1360
1361#ifdef VMS
1362 return build_string (nm);
1363#else
1364
1365 /* See if any variables are substituted into the string
1366 and find the total length of their values in `total' */
1367
1368 for (p = nm; p != endp;)
1369 if (*p != '$')
1370 p++;
1371 else
1372 {
1373 p++;
1374 if (p == endp)
1375 goto badsubst;
1376 else if (*p == '$')
1377 {
1378 /* "$$" means a single "$" */
1379 p++;
1380 total -= 1;
1381 substituted = 1;
1382 continue;
1383 }
1384 else if (*p == '{')
1385 {
1386 o = ++p;
1387 while (p != endp && *p != '}') p++;
1388 if (*p != '}') goto missingclose;
1389 s = p;
1390 }
1391 else
1392 {
1393 o = p;
1394 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1395 s = p;
1396 }
1397
1398 /* Copy out the variable name */
1399 target = (unsigned char *) alloca (s - o + 1);
1400 strncpy (target, o, s - o);
1401 target[s - o] = 0;
1402
1403 /* Get variable value */
1404 o = (unsigned char *) egetenv (target);
1405/* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
1406#if 0
1407#ifdef USG
1408 if (!o && !strcmp (target, "USER"))
1409 o = egetenv ("LOGNAME");
1410#endif /* USG */
1411#endif /* 0 */
1412 if (!o) goto badvar;
1413 total += strlen (o);
1414 substituted = 1;
1415 }
1416
1417 if (!substituted)
1418 return string;
1419
1420 /* If substitution required, recopy the string and do it */
1421 /* Make space in stack frame for the new copy */
1422 xnm = (unsigned char *) alloca (XSTRING (string)->size + total + 1);
1423 x = xnm;
1424
1425 /* Copy the rest of the name through, replacing $ constructs with values */
1426 for (p = nm; *p;)
1427 if (*p != '$')
1428 *x++ = *p++;
1429 else
1430 {
1431 p++;
1432 if (p == endp)
1433 goto badsubst;
1434 else if (*p == '$')
1435 {
1436 *x++ = *p++;
1437 continue;
1438 }
1439 else if (*p == '{')
1440 {
1441 o = ++p;
1442 while (p != endp && *p != '}') p++;
1443 if (*p != '}') goto missingclose;
1444 s = p++;
1445 }
1446 else
1447 {
1448 o = p;
1449 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1450 s = p;
1451 }
1452
1453 /* Copy out the variable name */
1454 target = (unsigned char *) alloca (s - o + 1);
1455 strncpy (target, o, s - o);
1456 target[s - o] = 0;
1457
1458 /* Get variable value */
1459 o = (unsigned char *) egetenv (target);
1460/* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
1461#if 0
1462#ifdef USG
1463 if (!o && !strcmp (target, "USER"))
1464 o = egetenv ("LOGNAME");
1465#endif /* USG */
1466#endif /* 0 */
1467 if (!o)
1468 goto badvar;
1469
1470 strcpy (x, o);
1471 x += strlen (o);
1472 }
1473
1474 *x = 0;
1475
1476 /* If /~ or // appears, discard everything through first slash. */
1477
1478 for (p = xnm; p != x; p++)
1479 if ((p[0] == '~' ||
1480#ifdef APOLLO
1481 /* // at start of file name is meaningful in Apollo system */
1482 (p[0] == '/' && p - 1 != xnm)
1483#else /* not APOLLO */
1484 p[0] == '/'
1485#endif /* not APOLLO */
1486 )
1487 && p != nm && p[-1] == '/')
1488 xnm = p;
1489
1490 return make_string (xnm, x - xnm);
1491
1492 badsubst:
1493 error ("Bad format environment-variable substitution");
1494 missingclose:
1495 error ("Missing \"}\" in environment-variable substitution");
1496 badvar:
1497 error ("Substituting nonexistent environment variable \"%s\"", target);
1498
1499 /* NOTREACHED */
1500#endif /* not VMS */
1501}
1502\f
067ffa38
JB
1503/* A slightly faster and more convenient way to get
1504 (directory-file-name (expand-file-name FOO)). The return value may
1505 have had its last character zapped with a '\0' character, meaning
1506 that it is acceptable to system calls, but not to other lisp
1507 functions. Callers should make sure that the return value doesn't
1508 escape. */
1509
570d7624
JB
1510Lisp_Object
1511expand_and_dir_to_file (filename, defdir)
1512 Lisp_Object filename, defdir;
1513{
1514 register Lisp_Object abspath;
1515
1516 abspath = Fexpand_file_name (filename, defdir);
1517#ifdef VMS
1518 {
1519 register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1];
1520 if (c == ':' || c == ']' || c == '>')
1521 abspath = Fdirectory_file_name (abspath);
1522 }
1523#else
1524 /* Remove final slash, if any (unless path is root).
1525 stat behaves differently depending! */
1526 if (XSTRING (abspath)->size > 1
1527 && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/')
1528 {
1529 if (EQ (abspath, filename))
1530 abspath = Fcopy_sequence (abspath);
1531 XSTRING (abspath)->data[XSTRING (abspath)->size - 1] = 0;
1532 }
1533#endif
1534 return abspath;
1535}
1536\f
1537barf_or_query_if_file_exists (absname, querystring, interactive)
1538 Lisp_Object absname;
1539 unsigned char *querystring;
1540 int interactive;
1541{
1542 register Lisp_Object tem;
1543 struct gcpro gcpro1;
1544
1545 if (access (XSTRING (absname)->data, 4) >= 0)
1546 {
1547 if (! interactive)
1548 Fsignal (Qfile_already_exists,
1549 Fcons (build_string ("File already exists"),
1550 Fcons (absname, Qnil)));
1551 GCPRO1 (absname);
1552 tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
1553 XSTRING (absname)->data, querystring));
1554 UNGCPRO;
265a9e55 1555 if (NILP (tem))
570d7624
JB
1556 Fsignal (Qfile_already_exists,
1557 Fcons (build_string ("File already exists"),
1558 Fcons (absname, Qnil)));
1559 }
1560 return;
1561}
1562
1563DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4,
349a7710 1564 "fCopy file: \nFCopy %s to file: \np\nP",
570d7624
JB
1565 "Copy FILE to NEWNAME. Both args must be strings.\n\
1566Signals a `file-already-exists' error if file NEWNAME already exists,\n\
1567unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\
1568A number as third arg means request confirmation if NEWNAME already exists.\n\
1569This is what happens in interactive use with M-x.\n\
349a7710
JB
1570Fourth arg KEEP-TIME non-nil means give the new file the same\n\
1571last-modified time as the old one. (This works on only some systems.)\n\
1572A prefix arg makes KEEP-TIME non-nil.")
570d7624
JB
1573 (filename, newname, ok_if_already_exists, keep_date)
1574 Lisp_Object filename, newname, ok_if_already_exists, keep_date;
1575{
1576 int ifd, ofd, n;
1577 char buf[16 * 1024];
1578 struct stat st;
32f4334d 1579 Lisp_Object handler;
570d7624 1580 struct gcpro gcpro1, gcpro2;
b5148e85 1581 int count = specpdl_ptr - specpdl;
570d7624
JB
1582
1583 GCPRO2 (filename, newname);
1584 CHECK_STRING (filename, 0);
1585 CHECK_STRING (newname, 1);
1586 filename = Fexpand_file_name (filename, Qnil);
1587 newname = Fexpand_file_name (newname, Qnil);
32f4334d 1588
0bf2eed2 1589 /* If the input file name has special constructs in it,
32f4334d 1590 call the corresponding file handler. */
642ef245 1591 handler = Ffind_file_name_handler (filename);
0bf2eed2
RS
1592 if (!NILP (handler))
1593 return call3 (handler, Qcopy_file, filename, newname);
1594 /* Likewise for output file name. */
642ef245 1595 handler = Ffind_file_name_handler (newname);
32f4334d
RS
1596 if (!NILP (handler))
1597 return call3 (handler, Qcopy_file, filename, newname);
1598
265a9e55 1599 if (NILP (ok_if_already_exists)
570d7624
JB
1600 || XTYPE (ok_if_already_exists) == Lisp_Int)
1601 barf_or_query_if_file_exists (newname, "copy to it",
1602 XTYPE (ok_if_already_exists) == Lisp_Int);
1603
1604 ifd = open (XSTRING (filename)->data, 0);
1605 if (ifd < 0)
1606 report_file_error ("Opening input file", Fcons (filename, Qnil));
1607
b5148e85
RS
1608 record_unwind_protect (close_file_unwind, make_number (ifd));
1609
570d7624
JB
1610#ifdef VMS
1611 /* Create the copy file with the same record format as the input file */
1612 ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
1613#else
1614 ofd = creat (XSTRING (newname)->data, 0666);
1615#endif /* VMS */
1616 if (ofd < 0)
66331187 1617 report_file_error ("Opening output file", Fcons (newname, Qnil));
b5148e85
RS
1618
1619 record_unwind_protect (close_file_unwind, make_number (ofd));
570d7624 1620
b5148e85
RS
1621 immediate_quit = 1;
1622 QUIT;
570d7624
JB
1623 while ((n = read (ifd, buf, sizeof buf)) > 0)
1624 if (write (ofd, buf, n) != n)
66331187 1625 report_file_error ("I/O error", Fcons (newname, Qnil));
b5148e85 1626 immediate_quit = 0;
570d7624
JB
1627
1628 if (fstat (ifd, &st) >= 0)
1629 {
265a9e55 1630 if (!NILP (keep_date))
570d7624 1631 {
de5bf5d3
JB
1632 EMACS_TIME atime, mtime;
1633 EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
1634 EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
1635 EMACS_SET_UTIMES (XSTRING (newname)->data, atime, mtime);
570d7624 1636 }
570d7624
JB
1637#ifdef APOLLO
1638 if (!egetenv ("USE_DOMAIN_ACLS"))
1639#endif
de5bf5d3 1640 chmod (XSTRING (newname)->data, st.st_mode & 07777);
570d7624
JB
1641 }
1642
b5148e85
RS
1643 /* Discard the unwind protects. */
1644 specpdl_ptr = specpdl + count;
1645
570d7624
JB
1646 close (ifd);
1647 if (close (ofd) < 0)
1648 report_file_error ("I/O error", Fcons (newname, Qnil));
1649
1650 UNGCPRO;
1651 return Qnil;
1652}
1653
9bbe01fb 1654DEFUN ("make-directory-internal", Fmake_directory_internal,
353cfc19 1655 Smake_directory_internal, 1, 1, 0,
570d7624
JB
1656 "Create a directory. One argument, a file name string.")
1657 (dirname)
1658 Lisp_Object dirname;
1659{
1660 unsigned char *dir;
32f4334d 1661 Lisp_Object handler;
570d7624
JB
1662
1663 CHECK_STRING (dirname, 0);
1664 dirname = Fexpand_file_name (dirname, Qnil);
32f4334d 1665
642ef245 1666 handler = Ffind_file_name_handler (dirname);
32f4334d 1667 if (!NILP (handler))
9bbe01fb
RS
1668 return call3 (handler, Qmake_directory, dirname, Qnil);
1669
570d7624
JB
1670 dir = XSTRING (dirname)->data;
1671
1672 if (mkdir (dir, 0777) != 0)
1673 report_file_error ("Creating directory", Flist (1, &dirname));
1674
32f4334d 1675 return Qnil;
570d7624
JB
1676}
1677
aa734e17
RS
1678DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
1679 "Delete a directory. One argument, a file name string.")
570d7624
JB
1680 (dirname)
1681 Lisp_Object dirname;
1682{
1683 unsigned char *dir;
32f4334d 1684 Lisp_Object handler;
570d7624
JB
1685
1686 CHECK_STRING (dirname, 0);
1687 dirname = Fexpand_file_name (dirname, Qnil);
1688 dir = XSTRING (dirname)->data;
1689
642ef245 1690 handler = Ffind_file_name_handler (dirname);
32f4334d
RS
1691 if (!NILP (handler))
1692 return call2 (handler, Qdelete_directory, dirname);
1693
570d7624
JB
1694 if (rmdir (dir) != 0)
1695 report_file_error ("Removing directory", Flist (1, &dirname));
1696
1697 return Qnil;
1698}
1699
1700DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
1701 "Delete specified file. One argument, a file name string.\n\
1702If file has multiple names, it continues to exist with the other names.")
1703 (filename)
1704 Lisp_Object filename;
1705{
32f4334d 1706 Lisp_Object handler;
570d7624
JB
1707 CHECK_STRING (filename, 0);
1708 filename = Fexpand_file_name (filename, Qnil);
32f4334d 1709
642ef245 1710 handler = Ffind_file_name_handler (filename);
32f4334d
RS
1711 if (!NILP (handler))
1712 return call2 (handler, Qdelete_file, filename);
1713
570d7624
JB
1714 if (0 > unlink (XSTRING (filename)->data))
1715 report_file_error ("Removing old name", Flist (1, &filename));
1716 return Qnil;
1717}
1718
1719DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
1720 "fRename file: \nFRename %s to file: \np",
1721 "Rename FILE as NEWNAME. Both args strings.\n\
1722If file has names other than FILE, it continues to have those names.\n\
1723Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1724unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1725A number as third arg means request confirmation if NEWNAME already exists.\n\
1726This is what happens in interactive use with M-x.")
1727 (filename, newname, ok_if_already_exists)
1728 Lisp_Object filename, newname, ok_if_already_exists;
1729{
1730#ifdef NO_ARG_ARRAY
1731 Lisp_Object args[2];
1732#endif
32f4334d 1733 Lisp_Object handler;
570d7624
JB
1734 struct gcpro gcpro1, gcpro2;
1735
1736 GCPRO2 (filename, newname);
1737 CHECK_STRING (filename, 0);
1738 CHECK_STRING (newname, 1);
1739 filename = Fexpand_file_name (filename, Qnil);
1740 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1741
1742 /* If the file name has special constructs in it,
1743 call the corresponding file handler. */
642ef245 1744 handler = Ffind_file_name_handler (filename);
32f4334d
RS
1745 if (!NILP (handler))
1746 return call3 (handler, Qrename_file, filename, newname);
1747
265a9e55 1748 if (NILP (ok_if_already_exists)
570d7624
JB
1749 || XTYPE (ok_if_already_exists) == Lisp_Int)
1750 barf_or_query_if_file_exists (newname, "rename to it",
1751 XTYPE (ok_if_already_exists) == Lisp_Int);
1752#ifndef BSD4_1
1753 if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
1754#else
1755 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data)
1756 || 0 > unlink (XSTRING (filename)->data))
1757#endif
1758 {
1759 if (errno == EXDEV)
1760 {
1761 Fcopy_file (filename, newname, ok_if_already_exists, Qt);
1762 Fdelete_file (filename);
1763 }
1764 else
1765#ifdef NO_ARG_ARRAY
1766 {
1767 args[0] = filename;
1768 args[1] = newname;
1769 report_file_error ("Renaming", Flist (2, args));
1770 }
1771#else
1772 report_file_error ("Renaming", Flist (2, &filename));
1773#endif
1774 }
1775 UNGCPRO;
1776 return Qnil;
1777}
1778
1779DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3,
1780 "fAdd name to file: \nFName to add to %s: \np",
1781 "Give FILE additional name NEWNAME. Both args strings.\n\
1782Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1783unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1784A number as third arg means request confirmation if NEWNAME already exists.\n\
1785This is what happens in interactive use with M-x.")
1786 (filename, newname, ok_if_already_exists)
1787 Lisp_Object filename, newname, ok_if_already_exists;
1788{
1789#ifdef NO_ARG_ARRAY
1790 Lisp_Object args[2];
1791#endif
32f4334d 1792 Lisp_Object handler;
570d7624
JB
1793 struct gcpro gcpro1, gcpro2;
1794
1795 GCPRO2 (filename, newname);
1796 CHECK_STRING (filename, 0);
1797 CHECK_STRING (newname, 1);
1798 filename = Fexpand_file_name (filename, Qnil);
1799 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1800
1801 /* If the file name has special constructs in it,
1802 call the corresponding file handler. */
642ef245 1803 handler = Ffind_file_name_handler (filename);
32f4334d
RS
1804 if (!NILP (handler))
1805 return call3 (handler, Qadd_name_to_file, filename, newname);
1806
265a9e55 1807 if (NILP (ok_if_already_exists)
570d7624
JB
1808 || XTYPE (ok_if_already_exists) == Lisp_Int)
1809 barf_or_query_if_file_exists (newname, "make it a new name",
1810 XTYPE (ok_if_already_exists) == Lisp_Int);
1811 unlink (XSTRING (newname)->data);
1812 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data))
1813 {
1814#ifdef NO_ARG_ARRAY
1815 args[0] = filename;
1816 args[1] = newname;
1817 report_file_error ("Adding new name", Flist (2, args));
1818#else
1819 report_file_error ("Adding new name", Flist (2, &filename));
1820#endif
1821 }
1822
1823 UNGCPRO;
1824 return Qnil;
1825}
1826
1827#ifdef S_IFLNK
1828DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
1829 "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",
1830 "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\
1831Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1832unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1833A number as third arg means request confirmation if NEWNAME already exists.\n\
1834This happens for interactive use with M-x.")
e5d77022
JB
1835 (filename, linkname, ok_if_already_exists)
1836 Lisp_Object filename, linkname, ok_if_already_exists;
570d7624
JB
1837{
1838#ifdef NO_ARG_ARRAY
1839 Lisp_Object args[2];
1840#endif
32f4334d 1841 Lisp_Object handler;
570d7624
JB
1842 struct gcpro gcpro1, gcpro2;
1843
e5d77022 1844 GCPRO2 (filename, linkname);
570d7624 1845 CHECK_STRING (filename, 0);
e5d77022 1846 CHECK_STRING (linkname, 1);
570d7624
JB
1847#if 0 /* This made it impossible to make a link to a relative name. */
1848 filename = Fexpand_file_name (filename, Qnil);
1849#endif
e5d77022 1850 linkname = Fexpand_file_name (linkname, Qnil);
32f4334d
RS
1851
1852 /* If the file name has special constructs in it,
1853 call the corresponding file handler. */
642ef245 1854 handler = Ffind_file_name_handler (filename);
32f4334d 1855 if (!NILP (handler))
3eac9910 1856 return call3 (handler, Qmake_symbolic_link, filename, linkname);
32f4334d 1857
265a9e55 1858 if (NILP (ok_if_already_exists)
570d7624 1859 || XTYPE (ok_if_already_exists) == Lisp_Int)
e5d77022 1860 barf_or_query_if_file_exists (linkname, "make it a link",
570d7624 1861 XTYPE (ok_if_already_exists) == Lisp_Int);
e5d77022 1862 if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
1863 {
1864 /* If we didn't complain already, silently delete existing file. */
1865 if (errno == EEXIST)
1866 {
9083124b 1867 unlink (XSTRING (linkname)->data);
e5d77022 1868 if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
1869 return Qnil;
1870 }
1871
1872#ifdef NO_ARG_ARRAY
1873 args[0] = filename;
e5d77022 1874 args[1] = linkname;
570d7624
JB
1875 report_file_error ("Making symbolic link", Flist (2, args));
1876#else
1877 report_file_error ("Making symbolic link", Flist (2, &filename));
1878#endif
1879 }
1880 UNGCPRO;
1881 return Qnil;
1882}
1883#endif /* S_IFLNK */
1884
1885#ifdef VMS
1886
1887DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
1888 2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
1889 "Define the job-wide logical name NAME to have the value STRING.\n\
1890If STRING is nil or a null string, the logical name NAME is deleted.")
1891 (varname, string)
1892 Lisp_Object varname;
1893 Lisp_Object string;
1894{
1895 CHECK_STRING (varname, 0);
265a9e55 1896 if (NILP (string))
570d7624
JB
1897 delete_logical_name (XSTRING (varname)->data);
1898 else
1899 {
1900 CHECK_STRING (string, 1);
1901
1902 if (XSTRING (string)->size == 0)
1903 delete_logical_name (XSTRING (varname)->data);
1904 else
1905 define_logical_name (XSTRING (varname)->data, XSTRING (string)->data);
1906 }
1907
1908 return string;
1909}
1910#endif /* VMS */
1911
1912#ifdef HPUX_NET
1913
1914DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
1915 "Open a network connection to PATH using LOGIN as the login string.")
1916 (path, login)
1917 Lisp_Object path, login;
1918{
1919 int netresult;
1920
1921 CHECK_STRING (path, 0);
1922 CHECK_STRING (login, 0);
1923
1924 netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
1925
1926 if (netresult == -1)
1927 return Qnil;
1928 else
1929 return Qt;
1930}
1931#endif /* HPUX_NET */
1932\f
1933DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
1934 1, 1, 0,
1935 "Return t if file FILENAME specifies an absolute path name.\n\
1936On Unix, this is a name starting with a `/' or a `~'.")
1937 (filename)
1938 Lisp_Object filename;
1939{
1940 unsigned char *ptr;
1941
1942 CHECK_STRING (filename, 0);
1943 ptr = XSTRING (filename)->data;
1944 if (*ptr == '/' || *ptr == '~'
1945#ifdef VMS
1946/* ??? This criterion is probably wrong for '<'. */
1947 || index (ptr, ':') || index (ptr, '<')
1948 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
1949 && ptr[1] != '.')
1950#endif /* VMS */
1951 )
1952 return Qt;
1953 else
1954 return Qnil;
1955}
1956
1957DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
1958 "Return t if file FILENAME exists. (This does not mean you can read it.)\n\
1959See also `file-readable-p' and `file-attributes'.")
1960 (filename)
1961 Lisp_Object filename;
1962{
1963 Lisp_Object abspath;
32f4334d 1964 Lisp_Object handler;
570d7624
JB
1965
1966 CHECK_STRING (filename, 0);
1967 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1968
1969 /* If the file name has special constructs in it,
1970 call the corresponding file handler. */
642ef245 1971 handler = Ffind_file_name_handler (abspath);
32f4334d 1972 if (!NILP (handler))
09121adc 1973 return call2 (handler, Qfile_exists_p, abspath);
32f4334d 1974
570d7624
JB
1975 return (access (XSTRING (abspath)->data, 0) >= 0) ? Qt : Qnil;
1976}
1977
1978DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
1979 "Return t if FILENAME can be executed by you.\n\
8b235fde 1980For a directory, this means you can access files in that directory.")
570d7624
JB
1981 (filename)
1982 Lisp_Object filename;
1983
1984{
1985 Lisp_Object abspath;
32f4334d 1986 Lisp_Object handler;
570d7624
JB
1987
1988 CHECK_STRING (filename, 0);
1989 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1990
1991 /* If the file name has special constructs in it,
1992 call the corresponding file handler. */
642ef245 1993 handler = Ffind_file_name_handler (abspath);
32f4334d 1994 if (!NILP (handler))
09121adc 1995 return call2 (handler, Qfile_executable_p, abspath);
32f4334d 1996
570d7624
JB
1997 return (access (XSTRING (abspath)->data, 1) >= 0) ? Qt : Qnil;
1998}
1999
2000DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
2001 "Return t if file FILENAME exists and you can read it.\n\
2002See also `file-exists-p' and `file-attributes'.")
2003 (filename)
2004 Lisp_Object filename;
2005{
2006 Lisp_Object abspath;
32f4334d 2007 Lisp_Object handler;
570d7624
JB
2008
2009 CHECK_STRING (filename, 0);
2010 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2011
2012 /* If the file name has special constructs in it,
2013 call the corresponding file handler. */
642ef245 2014 handler = Ffind_file_name_handler (abspath);
32f4334d 2015 if (!NILP (handler))
09121adc 2016 return call2 (handler, Qfile_readable_p, abspath);
32f4334d 2017
570d7624
JB
2018 return (access (XSTRING (abspath)->data, 4) >= 0) ? Qt : Qnil;
2019}
2020
2021DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
2022 "If file FILENAME is the name of a symbolic link\n\
2023returns the name of the file to which it is linked.\n\
2024Otherwise returns NIL.")
2025 (filename)
2026 Lisp_Object filename;
2027{
2028#ifdef S_IFLNK
2029 char *buf;
2030 int bufsize;
2031 int valsize;
2032 Lisp_Object val;
32f4334d 2033 Lisp_Object handler;
570d7624
JB
2034
2035 CHECK_STRING (filename, 0);
2036 filename = Fexpand_file_name (filename, Qnil);
2037
32f4334d
RS
2038 /* If the file name has special constructs in it,
2039 call the corresponding file handler. */
642ef245 2040 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2041 if (!NILP (handler))
2042 return call2 (handler, Qfile_symlink_p, filename);
2043
570d7624
JB
2044 bufsize = 100;
2045 while (1)
2046 {
2047 buf = (char *) xmalloc (bufsize);
2048 bzero (buf, bufsize);
2049 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
2050 if (valsize < bufsize) break;
2051 /* Buffer was not long enough */
9ac0d9e0 2052 xfree (buf);
570d7624
JB
2053 bufsize *= 2;
2054 }
2055 if (valsize == -1)
2056 {
9ac0d9e0 2057 xfree (buf);
570d7624
JB
2058 return Qnil;
2059 }
2060 val = make_string (buf, valsize);
9ac0d9e0 2061 xfree (buf);
570d7624
JB
2062 return val;
2063#else /* not S_IFLNK */
2064 return Qnil;
2065#endif /* not S_IFLNK */
2066}
2067
a253bab2
JB
2068#ifdef SOLARIS_BROKEN_ACCESS
2069/* In Solaris 2.1, the readonly-ness of the filesystem is not
2070 considered by the access system call. This is Sun's bug, but we
2071 still have to make Emacs work. */
2072
2073#include <sys/statvfs.h>
2074
2075static int
2076ro_fsys (path)
2077 char *path;
2078{
2079 struct statvfs statvfsb;
2080
2081 if (statvfs(path, &statvfsb))
2082 return 1; /* error from statvfs, be conservative and say not wrtable */
2083 else
2084 /* Otherwise, fsys is ro if bit is set. */
2085 return statvfsb.f_flag & ST_RDONLY;
2086}
2087#else
2088/* But on every other os, access has already done the right thing. */
2089#define ro_fsys(path) 0
2090#endif
2091
570d7624
JB
2092/* Having this before file-symlink-p mysteriously caused it to be forgotten
2093 on the RT/PC. */
2094DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
2095 "Return t if file FILENAME can be written or created by you.")
2096 (filename)
2097 Lisp_Object filename;
2098{
2099 Lisp_Object abspath, dir;
32f4334d 2100 Lisp_Object handler;
570d7624
JB
2101
2102 CHECK_STRING (filename, 0);
2103 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2104
2105 /* If the file name has special constructs in it,
2106 call the corresponding file handler. */
642ef245 2107 handler = Ffind_file_name_handler (abspath);
32f4334d 2108 if (!NILP (handler))
09121adc 2109 return call2 (handler, Qfile_writable_p, abspath);
32f4334d 2110
570d7624 2111 if (access (XSTRING (abspath)->data, 0) >= 0)
a253bab2
JB
2112 return ((access (XSTRING (abspath)->data, 2) >= 0
2113 && ! ro_fsys (XSTRING (abspath)))
2114 ? Qt : Qnil);
570d7624
JB
2115 dir = Ffile_name_directory (abspath);
2116#ifdef VMS
265a9e55 2117 if (!NILP (dir))
570d7624
JB
2118 dir = Fdirectory_file_name (dir);
2119#endif /* VMS */
a253bab2
JB
2120 return ((access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
2121 && ! ro_fsys ((char *) XSTRING (dir)))
570d7624
JB
2122 ? Qt : Qnil);
2123}
2124
2125DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
2126 "Return t if file FILENAME is the name of a directory as a file.\n\
2127A directory name spec may be given instead; then the value is t\n\
2128if the directory so specified exists and really is a directory.")
2129 (filename)
2130 Lisp_Object filename;
2131{
2132 register Lisp_Object abspath;
2133 struct stat st;
32f4334d 2134 Lisp_Object handler;
570d7624
JB
2135
2136 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2137
32f4334d
RS
2138 /* If the file name has special constructs in it,
2139 call the corresponding file handler. */
642ef245 2140 handler = Ffind_file_name_handler (abspath);
32f4334d 2141 if (!NILP (handler))
09121adc 2142 return call2 (handler, Qfile_directory_p, abspath);
32f4334d 2143
570d7624
JB
2144 if (stat (XSTRING (abspath)->data, &st) < 0)
2145 return Qnil;
2146 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2147}
2148
b72dea2a
JB
2149DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
2150 "Return t if file FILENAME is the name of a directory as a file,\n\
2151and files in that directory can be opened by you. In order to use a\n\
2152directory as a buffer's current directory, this predicate must return true.\n\
2153A directory name spec may be given instead; then the value is t\n\
2154if the directory so specified exists and really is a readable and\n\
2155searchable directory.")
2156 (filename)
2157 Lisp_Object filename;
2158{
32f4334d
RS
2159 Lisp_Object handler;
2160
2161 /* If the file name has special constructs in it,
2162 call the corresponding file handler. */
642ef245 2163 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2164 if (!NILP (handler))
2165 return call2 (handler, Qfile_accessible_directory_p, filename);
2166
b72dea2a
JB
2167 if (NILP (Ffile_directory_p (filename))
2168 || NILP (Ffile_executable_p (filename)))
2169 return Qnil;
2170 else
2171 return Qt;
2172}
2173
570d7624
JB
2174DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2175 "Return mode bits of FILE, as an integer.")
2176 (filename)
2177 Lisp_Object filename;
2178{
2179 Lisp_Object abspath;
2180 struct stat st;
32f4334d 2181 Lisp_Object handler;
570d7624
JB
2182
2183 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2184
32f4334d
RS
2185 /* If the file name has special constructs in it,
2186 call the corresponding file handler. */
642ef245 2187 handler = Ffind_file_name_handler (abspath);
32f4334d 2188 if (!NILP (handler))
09121adc 2189 return call2 (handler, Qfile_modes, abspath);
32f4334d 2190
570d7624
JB
2191 if (stat (XSTRING (abspath)->data, &st) < 0)
2192 return Qnil;
2193 return make_number (st.st_mode & 07777);
2194}
2195
2196DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2197 "Set mode bits of FILE to MODE (an integer).\n\
2198Only the 12 low bits of MODE are used.")
2199 (filename, mode)
2200 Lisp_Object filename, mode;
2201{
2202 Lisp_Object abspath;
32f4334d 2203 Lisp_Object handler;
570d7624
JB
2204
2205 abspath = Fexpand_file_name (filename, current_buffer->directory);
2206 CHECK_NUMBER (mode, 1);
2207
32f4334d
RS
2208 /* If the file name has special constructs in it,
2209 call the corresponding file handler. */
642ef245 2210 handler = Ffind_file_name_handler (abspath);
32f4334d 2211 if (!NILP (handler))
09121adc 2212 return call3 (handler, Qset_file_modes, abspath, mode);
32f4334d 2213
570d7624
JB
2214#ifndef APOLLO
2215 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2216 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2217#else /* APOLLO */
2218 if (!egetenv ("USE_DOMAIN_ACLS"))
2219 {
2220 struct stat st;
2221 struct timeval tvp[2];
2222
2223 /* chmod on apollo also change the file's modtime; need to save the
2224 modtime and then restore it. */
2225 if (stat (XSTRING (abspath)->data, &st) < 0)
2226 {
2227 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2228 return (Qnil);
2229 }
2230
2231 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2232 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2233
2234 /* reset the old accessed and modified times. */
2235 tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
2236 tvp[0].tv_usec = 0;
2237 tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
2238 tvp[1].tv_usec = 0;
2239
2240 if (utimes (XSTRING (abspath)->data, tvp) < 0)
2241 report_file_error ("Doing utimes", Fcons (abspath, Qnil));
2242 }
2243#endif /* APOLLO */
2244
2245 return Qnil;
2246}
2247
c24e9a53 2248DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
5f85ea58
RS
2249 "Set the file permission bits for newly created files.\n\
2250The argument MODE should be an integer; only the low 9 bits are used.\n\
36a8c287 2251This setting is inherited by subprocesses.")
5f85ea58
RS
2252 (mode)
2253 Lisp_Object mode;
36a8c287 2254{
5f85ea58 2255 CHECK_NUMBER (mode, 0);
36a8c287 2256
5f85ea58 2257 umask ((~ XINT (mode)) & 0777);
36a8c287
JB
2258
2259 return Qnil;
2260}
2261
c24e9a53 2262DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
5f85ea58
RS
2263 "Return the default file protection for created files.\n\
2264The value is an integer.")
36a8c287
JB
2265 ()
2266{
5f85ea58
RS
2267 int realmask;
2268 Lisp_Object value;
36a8c287 2269
5f85ea58
RS
2270 realmask = umask (0);
2271 umask (realmask);
36a8c287 2272
5f85ea58
RS
2273 XSET (value, Lisp_Int, (~ realmask) & 0777);
2274 return value;
36a8c287
JB
2275}
2276
85ffea93
RS
2277#ifdef unix
2278
2279DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2280 "Tell Unix to finish all pending disk updates.")
2281 ()
2282{
2283 sync ();
2284 return Qnil;
2285}
2286
2287#endif /* unix */
2288
570d7624
JB
2289DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2290 "Return t if file FILE1 is newer than file FILE2.\n\
2291If FILE1 does not exist, the answer is nil;\n\
2292otherwise, if FILE2 does not exist, the answer is t.")
2293 (file1, file2)
2294 Lisp_Object file1, file2;
2295{
32f4334d 2296 Lisp_Object abspath1, abspath2;
570d7624
JB
2297 struct stat st;
2298 int mtime1;
32f4334d 2299 Lisp_Object handler;
09121adc 2300 struct gcpro gcpro1, gcpro2;
570d7624
JB
2301
2302 CHECK_STRING (file1, 0);
2303 CHECK_STRING (file2, 0);
2304
09121adc
RS
2305 abspath1 = Qnil;
2306 GCPRO2 (abspath1, file2);
32f4334d
RS
2307 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2308 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
09121adc 2309 UNGCPRO;
570d7624 2310
32f4334d
RS
2311 /* If the file name has special constructs in it,
2312 call the corresponding file handler. */
642ef245 2313 handler = Ffind_file_name_handler (abspath1);
32f4334d
RS
2314 if (!NILP (handler))
2315 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2316
2317 if (stat (XSTRING (abspath1)->data, &st) < 0)
570d7624
JB
2318 return Qnil;
2319
2320 mtime1 = st.st_mtime;
2321
32f4334d 2322 if (stat (XSTRING (abspath2)->data, &st) < 0)
570d7624
JB
2323 return Qt;
2324
2325 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2326}
2327\f
570d7624
JB
2328DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
2329 1, 2, 0,
2330 "Insert contents of file FILENAME after point.\n\
2331Returns list of absolute pathname and length of data inserted.\n\
2332If second argument VISIT is non-nil, the buffer's visited filename\n\
2333and last save file modtime are set, and it is marked unmodified.\n\
2334If visiting and the file does not exist, visiting is completed\n\
2335before the error is signaled.")
2336 (filename, visit)
2337 Lisp_Object filename, visit;
2338{
2339 struct stat st;
2340 register int fd;
2341 register int inserted = 0;
2342 register int how_much;
2343 int count = specpdl_ptr - specpdl;
2344 struct gcpro gcpro1;
32f4334d
RS
2345 Lisp_Object handler, val;
2346
2347 val = Qnil;
2348
570d7624 2349 GCPRO1 (filename);
265a9e55 2350 if (!NILP (current_buffer->read_only))
570d7624
JB
2351 Fbarf_if_buffer_read_only();
2352
2353 CHECK_STRING (filename, 0);
2354 filename = Fexpand_file_name (filename, Qnil);
2355
32f4334d
RS
2356 /* If the file name has special constructs in it,
2357 call the corresponding file handler. */
642ef245 2358 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2359 if (!NILP (handler))
2360 {
2361 val = call3 (handler, Qinsert_file_contents, filename, visit);
2362 st.st_mtime = 0;
2363 goto handled;
2364 }
2365
570d7624
JB
2366 fd = -1;
2367
2368#ifndef APOLLO
2369 if (stat (XSTRING (filename)->data, &st) < 0
349a7710 2370 || (fd = open (XSTRING (filename)->data, 0)) < 0)
570d7624
JB
2371#else
2372 if ((fd = open (XSTRING (filename)->data, 0)) < 0
2373 || fstat (fd, &st) < 0)
2374#endif /* not APOLLO */
2375 {
2376 if (fd >= 0) close (fd);
265a9e55 2377 if (NILP (visit))
570d7624
JB
2378 report_file_error ("Opening input file", Fcons (filename, Qnil));
2379 st.st_mtime = -1;
2380 how_much = 0;
2381 goto notfound;
2382 }
2383
2384 record_unwind_protect (close_file_unwind, make_number (fd));
2385
be53b411
JB
2386#ifdef S_IFSOCK
2387 /* This code will need to be changed in order to work on named
2388 pipes, and it's probably just not worth it. So we should at
2389 least signal an error. */
2390 if ((st.st_mode & S_IFMT) == S_IFSOCK)
2391 Fsignal (Qfile_error,
2392 Fcons (build_string ("reading from named pipe"),
2393 Fcons (filename, Qnil)));
2394#endif
2395
570d7624
JB
2396 /* Supposedly happens on VMS. */
2397 if (st.st_size < 0)
2398 error ("File size is negative");
be53b411 2399
570d7624
JB
2400 {
2401 register Lisp_Object temp;
2402
2403 /* Make sure point-max won't overflow after this insertion. */
2404 XSET (temp, Lisp_Int, st.st_size + Z);
2405 if (st.st_size + Z != XINT (temp))
2406 error ("maximum buffer size exceeded");
2407 }
2408
265a9e55 2409 if (NILP (visit))
570d7624
JB
2410 prepare_to_modify_buffer (point, point);
2411
2412 move_gap (point);
2413 if (GAP_SIZE < st.st_size)
2414 make_gap (st.st_size - GAP_SIZE);
2415
2416 while (1)
2417 {
2418 int try = min (st.st_size - inserted, 64 << 10);
b5148e85
RS
2419 int this;
2420
2421 /* Allow quitting out of the actual I/O. */
2422 immediate_quit = 1;
2423 QUIT;
2424 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2425 immediate_quit = 0;
570d7624
JB
2426
2427 if (this <= 0)
2428 {
2429 how_much = this;
2430 break;
2431 }
2432
2433 GPT += this;
2434 GAP_SIZE -= this;
2435 ZV += this;
2436 Z += this;
2437 inserted += this;
2438 }
2439
2440 if (inserted > 0)
7d8451f1
RS
2441 {
2442 record_insert (point, inserted);
8d4e077b
JA
2443
2444 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2445 offset_intervals (current_buffer, point, inserted);
7d8451f1
RS
2446 MODIFF++;
2447 }
570d7624
JB
2448
2449 close (fd);
2450
2451 /* Discard the unwind protect */
2452 specpdl_ptr = specpdl + count;
2453
2454 if (how_much < 0)
2455 error ("IO error reading %s: %s",
2456 XSTRING (filename)->data, err_str (errno));
2457
2458 notfound:
32f4334d 2459 handled:
570d7624 2460
265a9e55 2461 if (!NILP (visit))
570d7624
JB
2462 {
2463 current_buffer->undo_list = Qnil;
2464#ifdef APOLLO
2465 stat (XSTRING (filename)->data, &st);
2466#endif
2467 current_buffer->modtime = st.st_mtime;
2468 current_buffer->save_modified = MODIFF;
2469 current_buffer->auto_save_modified = MODIFF;
2470 XFASTINT (current_buffer->save_length) = Z - BEG;
2471#ifdef CLASH_DETECTION
32f4334d
RS
2472 if (NILP (handler))
2473 {
2474 if (!NILP (current_buffer->filename))
2475 unlock_file (current_buffer->filename);
2476 unlock_file (filename);
2477 }
570d7624
JB
2478#endif /* CLASH_DETECTION */
2479 current_buffer->filename = filename;
2480 /* If visiting nonexistent file, return nil. */
32f4334d 2481 if (current_buffer->modtime == -1)
570d7624
JB
2482 report_file_error ("Opening input file", Fcons (filename, Qnil));
2483 }
2484
2485 signal_after_change (point, 0, inserted);
2486
32f4334d
RS
2487 if (!NILP (val))
2488 RETURN_UNGCPRO (val);
9b7828a5
JB
2489 RETURN_UNGCPRO (Fcons (filename,
2490 Fcons (make_number (inserted),
2491 Qnil)));
570d7624
JB
2492}
2493
2494DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2495 "r\nFWrite region to file: ",
2496 "Write current region into specified file.\n\
2497When called from a program, takes three arguments:\n\
2498START, END and FILENAME. START and END are buffer positions.\n\
2499Optional fourth argument APPEND if non-nil means\n\
2500 append to existing file contents (if any).\n\
2501Optional fifth argument VISIT if t means\n\
2502 set the last-save-file-modtime of buffer to this file's modtime\n\
2503 and mark buffer not modified.\n\
3b7792ed
RS
2504If VISIT is a string, it is a second file name;\n\
2505 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
2506 VISIT is also the file name to lock and unlock for clash detection.\n\
1d386d28
RS
2507If VISIT is neither t nor nil nor a string,\n\
2508 that means do not print the \"Wrote file\" message.\n\
570d7624
JB
2509Kludgy feature: if START is a string, then that string is written\n\
2510to the file, instead of any buffer contents, and END is ignored.")
2511 (start, end, filename, append, visit)
2512 Lisp_Object start, end, filename, append, visit;
2513{
2514 register int desc;
2515 int failure;
2516 int save_errno;
2517 unsigned char *fn;
2518 struct stat st;
2519 int tem;
2520 int count = specpdl_ptr - specpdl;
2521#ifdef VMS
2522 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
2523#endif /* VMS */
3eac9910 2524 Lisp_Object handler;
4ad827c5 2525 Lisp_Object visit_file;
3b7792ed 2526 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
570d7624
JB
2527
2528 /* Special kludge to simplify auto-saving */
265a9e55 2529 if (NILP (start))
570d7624
JB
2530 {
2531 XFASTINT (start) = BEG;
2532 XFASTINT (end) = Z;
2533 }
2534 else if (XTYPE (start) != Lisp_String)
2535 validate_region (&start, &end);
2536
2537 filename = Fexpand_file_name (filename, Qnil);
4ad827c5 2538 if (XTYPE (visit) == Lisp_String)
e5176bae 2539 visit_file = Fexpand_file_name (visit, Qnil);
4ad827c5
RS
2540 else
2541 visit_file = filename;
2542
2543 GCPRO4 (start, filename, visit, visit_file);
570d7624 2544
32f4334d
RS
2545 /* If the file name has special constructs in it,
2546 call the corresponding file handler. */
642ef245 2547 handler = Ffind_file_name_handler (filename);
3eac9910 2548
32f4334d
RS
2549 if (!NILP (handler))
2550 {
2551 Lisp_Object args[7];
2552 Lisp_Object val;
2553 args[0] = handler;
2554 args[1] = Qwrite_region;
2555 args[2] = start;
2556 args[3] = end;
2557 args[4] = filename;
2558 args[5] = append;
2559 args[6] = visit;
2560 val = Ffuncall (7, args);
2561
2562 /* Do this before reporting IO error
2563 to avoid a "file has changed on disk" warning on
2564 next attempt to save. */
3b7792ed 2565 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
32f4334d
RS
2566 {
2567 current_buffer->modtime = 0;
2568 current_buffer->save_modified = MODIFF;
2569 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 2570 current_buffer->filename = visit_file;
32f4334d 2571 }
09121adc 2572 UNGCPRO;
32f4334d
RS
2573 return val;
2574 }
2575
570d7624
JB
2576#ifdef CLASH_DETECTION
2577 if (!auto_saving)
3b7792ed 2578 lock_file (visit_file);
570d7624
JB
2579#endif /* CLASH_DETECTION */
2580
09121adc 2581 fn = XSTRING (filename)->data;
570d7624 2582 desc = -1;
265a9e55 2583 if (!NILP (append))
570d7624
JB
2584 desc = open (fn, O_WRONLY);
2585
2586 if (desc < 0)
2587#ifdef VMS
2588 if (auto_saving) /* Overwrite any previous version of autosave file */
2589 {
2590 vms_truncate (fn); /* if fn exists, truncate to zero length */
2591 desc = open (fn, O_RDWR);
2592 if (desc < 0)
2593 desc = creat_copy_attrs (XTYPE (current_buffer->filename) == Lisp_String
b72dea2a
JB
2594 ? XSTRING (current_buffer->filename)->data : 0,
2595 fn);
570d7624
JB
2596 }
2597 else /* Write to temporary name and rename if no errors */
2598 {
2599 Lisp_Object temp_name;
2600 temp_name = Ffile_name_directory (filename);
2601
265a9e55 2602 if (!NILP (temp_name))
570d7624
JB
2603 {
2604 temp_name = Fmake_temp_name (concat2 (temp_name,
2605 build_string ("$$SAVE$$")));
2606 fname = XSTRING (filename)->data;
2607 fn = XSTRING (temp_name)->data;
2608 desc = creat_copy_attrs (fname, fn);
2609 if (desc < 0)
2610 {
2611 /* If we can't open the temporary file, try creating a new
2612 version of the original file. VMS "creat" creates a
2613 new version rather than truncating an existing file. */
2614 fn = fname;
2615 fname = 0;
2616 desc = creat (fn, 0666);
2617#if 0 /* This can clobber an existing file and fail to replace it,
2618 if the user runs out of space. */
2619 if (desc < 0)
2620 {
2621 /* We can't make a new version;
2622 try to truncate and rewrite existing version if any. */
2623 vms_truncate (fn);
2624 desc = open (fn, O_RDWR);
2625 }
2626#endif
2627 }
2628 }
2629 else
2630 desc = creat (fn, 0666);
2631 }
2632#else /* not VMS */
2633 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
2634#endif /* not VMS */
2635
09121adc
RS
2636 UNGCPRO;
2637
570d7624
JB
2638 if (desc < 0)
2639 {
2640#ifdef CLASH_DETECTION
2641 save_errno = errno;
3b7792ed 2642 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
2643 errno = save_errno;
2644#endif /* CLASH_DETECTION */
2645 report_file_error ("Opening output file", Fcons (filename, Qnil));
2646 }
2647
2648 record_unwind_protect (close_file_unwind, make_number (desc));
2649
265a9e55 2650 if (!NILP (append))
570d7624
JB
2651 if (lseek (desc, 0, 2) < 0)
2652 {
2653#ifdef CLASH_DETECTION
3b7792ed 2654 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
2655#endif /* CLASH_DETECTION */
2656 report_file_error ("Lseek error", Fcons (filename, Qnil));
2657 }
2658
2659#ifdef VMS
2660/*
2661 * Kludge Warning: The VMS C RTL likes to insert carriage returns
2662 * if we do writes that don't end with a carriage return. Furthermore
2663 * it cannot handle writes of more then 16K. The modified
2664 * version of "sys_write" in SYSDEP.C (see comment there) copes with
2665 * this EXCEPT for the last record (iff it doesn't end with a carriage
2666 * return). This implies that if your buffer doesn't end with a carriage
2667 * return, you get one free... tough. However it also means that if
2668 * we make two calls to sys_write (a la the following code) you can
2669 * get one at the gap as well. The easiest way to fix this (honest)
2670 * is to move the gap to the next newline (or the end of the buffer).
2671 * Thus this change.
2672 *
2673 * Yech!
2674 */
2675 if (GPT > BEG && GPT_ADDR[-1] != '\n')
2676 move_gap (find_next_newline (GPT, 1));
2677#endif
2678
2679 failure = 0;
2680 immediate_quit = 1;
2681
2682 if (XTYPE (start) == Lisp_String)
2683 {
2684 failure = 0 > e_write (desc, XSTRING (start)->data,
2685 XSTRING (start)->size);
2686 save_errno = errno;
2687 }
2688 else if (XINT (start) != XINT (end))
2689 {
2690 if (XINT (start) < GPT)
2691 {
2692 register int end1 = XINT (end);
2693 tem = XINT (start);
2694 failure = 0 > e_write (desc, &FETCH_CHAR (tem),
2695 min (GPT, end1) - tem);
2696 save_errno = errno;
2697 }
2698
2699 if (XINT (end) > GPT && !failure)
2700 {
2701 tem = XINT (start);
2702 tem = max (tem, GPT);
2703 failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem);
2704 save_errno = errno;
2705 }
2706 }
2707
2708 immediate_quit = 0;
2709
6e23c83e 2710#ifdef HAVE_FSYNC
570d7624
JB
2711 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
2712 Disk full in NFS may be reported here. */
2713 if (fsync (desc) < 0)
2714 failure = 1, save_errno = errno;
570d7624
JB
2715#endif
2716
2717 /* Spurious "file has changed on disk" warnings have been
2718 observed on Suns as well.
2719 It seems that `close' can change the modtime, under nfs.
2720
2721 (This has supposedly been fixed in Sunos 4,
2722 but who knows about all the other machines with NFS?) */
2723#if 0
2724
2725 /* On VMS and APOLLO, must do the stat after the close
2726 since closing changes the modtime. */
2727#ifndef VMS
2728#ifndef APOLLO
2729 /* Recall that #if defined does not work on VMS. */
2730#define FOO
2731 fstat (desc, &st);
2732#endif
2733#endif
2734#endif
2735
2736 /* NFS can report a write failure now. */
2737 if (close (desc) < 0)
2738 failure = 1, save_errno = errno;
2739
2740#ifdef VMS
2741 /* If we wrote to a temporary name and had no errors, rename to real name. */
2742 if (fname)
2743 {
2744 if (!failure)
2745 failure = (rename (fn, fname) != 0), save_errno = errno;
2746 fn = fname;
2747 }
2748#endif /* VMS */
2749
2750#ifndef FOO
2751 stat (fn, &st);
2752#endif
2753 /* Discard the unwind protect */
2754 specpdl_ptr = specpdl + count;
2755
2756#ifdef CLASH_DETECTION
2757 if (!auto_saving)
3b7792ed 2758 unlock_file (visit_file);
570d7624
JB
2759#endif /* CLASH_DETECTION */
2760
2761 /* Do this before reporting IO error
2762 to avoid a "file has changed on disk" warning on
2763 next attempt to save. */
3b7792ed 2764 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
570d7624
JB
2765 current_buffer->modtime = st.st_mtime;
2766
2767 if (failure)
2768 error ("IO error writing %s: %s", fn, err_str (save_errno));
2769
3b7792ed 2770 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
570d7624
JB
2771 {
2772 current_buffer->save_modified = MODIFF;
2773 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 2774 current_buffer->filename = visit_file;
570d7624 2775 }
265a9e55 2776 else if (!NILP (visit))
570d7624
JB
2777 return Qnil;
2778
2779 if (!auto_saving)
3b7792ed 2780 message ("Wrote %s", XSTRING (visit_file)->data);
570d7624
JB
2781
2782 return Qnil;
2783}
2784
2785int
2786e_write (desc, addr, len)
2787 int desc;
2788 register char *addr;
2789 register int len;
2790{
2791 char buf[16 * 1024];
2792 register char *p, *end;
2793
2794 if (!EQ (current_buffer->selective_display, Qt))
2795 return write (desc, addr, len) - len;
2796 else
2797 {
2798 p = buf;
2799 end = p + sizeof buf;
2800 while (len--)
2801 {
2802 if (p == end)
2803 {
2804 if (write (desc, buf, sizeof buf) != sizeof buf)
2805 return -1;
2806 p = buf;
2807 }
2808 *p = *addr++;
2809 if (*p++ == '\015')
2810 p[-1] = '\n';
2811 }
2812 if (p != buf)
2813 if (write (desc, buf, p - buf) != p - buf)
2814 return -1;
2815 }
2816 return 0;
2817}
2818
2819DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
2820 Sverify_visited_file_modtime, 1, 1, 0,
2821 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
2822This means that the file has not been changed since it was visited or saved.")
2823 (buf)
2824 Lisp_Object buf;
2825{
2826 struct buffer *b;
2827 struct stat st;
32f4334d 2828 Lisp_Object handler;
570d7624
JB
2829
2830 CHECK_BUFFER (buf, 0);
2831 b = XBUFFER (buf);
2832
2833 if (XTYPE (b->filename) != Lisp_String) return Qt;
2834 if (b->modtime == 0) return Qt;
2835
32f4334d
RS
2836 /* If the file name has special constructs in it,
2837 call the corresponding file handler. */
642ef245 2838 handler = Ffind_file_name_handler (b->filename);
32f4334d 2839 if (!NILP (handler))
09121adc 2840 return call2 (handler, Qverify_visited_file_modtime, buf);
32f4334d 2841
570d7624
JB
2842 if (stat (XSTRING (b->filename)->data, &st) < 0)
2843 {
2844 /* If the file doesn't exist now and didn't exist before,
2845 we say that it isn't modified, provided the error is a tame one. */
2846 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
2847 st.st_mtime = -1;
2848 else
2849 st.st_mtime = 0;
2850 }
2851 if (st.st_mtime == b->modtime
2852 /* If both are positive, accept them if they are off by one second. */
2853 || (st.st_mtime > 0 && b->modtime > 0
2854 && (st.st_mtime == b->modtime + 1
2855 || st.st_mtime == b->modtime - 1)))
2856 return Qt;
2857 return Qnil;
2858}
2859
2860DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
2861 Sclear_visited_file_modtime, 0, 0, 0,
2862 "Clear out records of last mod time of visited file.\n\
2863Next attempt to save will certainly not complain of a discrepancy.")
2864 ()
2865{
2866 current_buffer->modtime = 0;
2867 return Qnil;
2868}
2869
f5d5eccf
RS
2870DEFUN ("visited-file-modtime", Fvisited_file_modtime,
2871 Svisited_file_modtime, 0, 0, 0,
2872 "Return the current buffer's recorded visited file modification time.\n\
2873The value is a list of the form (HIGH . LOW), like the time values\n\
2874that `file-attributes' returns.")
2875 ()
2876{
2877 return long_to_cons (current_buffer->modtime);
2878}
2879
570d7624 2880DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
f5d5eccf 2881 Sset_visited_file_modtime, 0, 1, 0,
570d7624
JB
2882 "Update buffer's recorded modification time from the visited file's time.\n\
2883Useful if the buffer was not read from the file normally\n\
f5d5eccf
RS
2884or if the file itself has been changed for some known benign reason.\n\
2885An argument specifies the modification time value to use\n\
2886\(instead of that of the visited file), in the form of a list\n\
2887\(HIGH . LOW) or (HIGH LOW).")
2888 (time_list)
2889 Lisp_Object time_list;
570d7624 2890{
f5d5eccf
RS
2891 if (!NILP (time_list))
2892 current_buffer->modtime = cons_to_long (time_list);
2893 else
2894 {
2895 register Lisp_Object filename;
2896 struct stat st;
2897 Lisp_Object handler;
570d7624 2898
f5d5eccf 2899 filename = Fexpand_file_name (current_buffer->filename, Qnil);
32f4334d 2900
f5d5eccf
RS
2901 /* If the file name has special constructs in it,
2902 call the corresponding file handler. */
2903 handler = Ffind_file_name_handler (filename);
2904 if (!NILP (handler))
2905 return call3 (handler, Qfile_name_directory, filename, Qnil);
2906 else if (stat (XSTRING (filename)->data, &st) >= 0)
2907 current_buffer->modtime = st.st_mtime;
2908 }
570d7624
JB
2909
2910 return Qnil;
2911}
2912\f
2913Lisp_Object
2914auto_save_error ()
2915{
2916 unsigned char *name = XSTRING (current_buffer->name)->data;
2917
2918 ring_bell ();
2919 message ("Autosaving...error for %s", name);
de49a6d3 2920 Fsleep_for (make_number (1), Qnil);
570d7624 2921 message ("Autosaving...error!for %s", name);
de49a6d3 2922 Fsleep_for (make_number (1), Qnil);
570d7624 2923 message ("Autosaving...error for %s", name);
de49a6d3 2924 Fsleep_for (make_number (1), Qnil);
570d7624
JB
2925 return Qnil;
2926}
2927
2928Lisp_Object
2929auto_save_1 ()
2930{
2931 unsigned char *fn;
2932 struct stat st;
2933
2934 /* Get visited file's mode to become the auto save file's mode. */
2935 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
2936 /* But make sure we can overwrite it later! */
2937 auto_save_mode_bits = st.st_mode | 0600;
2938 else
2939 auto_save_mode_bits = 0666;
2940
2941 return
2942 Fwrite_region (Qnil, Qnil,
2943 current_buffer->auto_save_file_name,
2944 Qnil, Qlambda);
2945}
2946
2947DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
2948 "Auto-save all buffers that need it.\n\
2949This is all buffers that have auto-saving enabled\n\
2950and are changed since last auto-saved.\n\
2951Auto-saving writes the buffer into a file\n\
2952so that your editing is not lost if the system crashes.\n\
2953This file is not the file you visited; that changes only when you save.\n\n\
2954Non-nil first argument means do not print any message if successful.\n\
4746118a 2955Non-nil second argument means save only current buffer.")
17857782
JB
2956 (no_message, current_only)
2957 Lisp_Object no_message, current_only;
570d7624
JB
2958{
2959 struct buffer *old = current_buffer, *b;
2960 Lisp_Object tail, buf;
2961 int auto_saved = 0;
2962 char *omessage = echo_area_glyphs;
f14b1c68
JB
2963 extern int minibuf_level;
2964 int do_handled_files;
570d7624
JB
2965
2966 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
2967 point to non-strings reached from Vbuffer_alist. */
2968
2969 auto_saving = 1;
2970 if (minibuf_level)
17857782 2971 no_message = Qt;
570d7624
JB
2972
2973 /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
2974 eventually call do-auto-save, so don't err here in that case. */
265a9e55 2975 if (!NILP (Vrun_hooks))
570d7624
JB
2976 call1 (Vrun_hooks, intern ("auto-save-hook"));
2977
f14b1c68
JB
2978 /* First, save all files which don't have handlers. If Emacs is
2979 crashing, the handlers may tweak what is causing Emacs to crash
2980 in the first place, and it would be a shame if Emacs failed to
2981 autosave perfectly ordinary files because it couldn't handle some
2982 ange-ftp'd file. */
2983 for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
2984 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
2985 tail = XCONS (tail)->cdr)
2986 {
2987 buf = XCONS (XCONS (tail)->car)->cdr;
2988 b = XBUFFER (buf);
17857782 2989
f14b1c68
JB
2990 if (!NILP (current_only)
2991 && b != current_buffer)
2992 continue;
17857782 2993
f14b1c68
JB
2994 /* Check for auto save enabled
2995 and file changed since last auto save
2996 and file changed since last real save. */
2997 if (XTYPE (b->auto_save_file_name) == Lisp_String
2998 && b->save_modified < BUF_MODIFF (b)
2999 && b->auto_save_modified < BUF_MODIFF (b)
3000 && (do_handled_files
3001 || NILP (Ffind_file_name_handler (b->auto_save_file_name))))
3002 {
3003 if ((XFASTINT (b->save_length) * 10
3004 > (BUF_Z (b) - BUF_BEG (b)) * 13)
3005 /* A short file is likely to change a large fraction;
3006 spare the user annoying messages. */
3007 && XFASTINT (b->save_length) > 5000
3008 /* These messages are frequent and annoying for `*mail*'. */
3009 && !EQ (b->filename, Qnil)
3010 && NILP (no_message))
3011 {
3012 /* It has shrunk too much; turn off auto-saving here. */
3013 message ("Buffer %s has shrunk a lot; auto save turned off there",
3014 XSTRING (b->name)->data);
3015 /* User can reenable saving with M-x auto-save. */
3016 b->auto_save_file_name = Qnil;
3017 /* Prevent warning from repeating if user does so. */
3018 XFASTINT (b->save_length) = 0;
3019 Fsleep_for (make_number (1), Qnil);
3020 continue;
3021 }
3022 set_buffer_internal (b);
3023 if (!auto_saved && NILP (no_message))
3024 message1 ("Auto-saving...");
3025 internal_condition_case (auto_save_1, Qt, auto_save_error);
3026 auto_saved++;
3027 b->auto_save_modified = BUF_MODIFF (b);
3028 XFASTINT (current_buffer->save_length) = Z - BEG;
3029 set_buffer_internal (old);
3030 }
3031 }
570d7624 3032
b67f2ca5
RS
3033 /* Prevent another auto save till enough input events come in. */
3034 record_auto_save ();
570d7624 3035
17857782 3036 if (auto_saved && NILP (no_message))
570d7624
JB
3037 message1 (omessage ? omessage : "Auto-saving...done");
3038
3039 auto_saving = 0;
3040 return Qnil;
3041}
3042
3043DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
3044 Sset_buffer_auto_saved, 0, 0, 0,
3045 "Mark current buffer as auto-saved with its current text.\n\
3046No auto-save file will be written until the buffer changes again.")
3047 ()
3048{
3049 current_buffer->auto_save_modified = MODIFF;
3050 XFASTINT (current_buffer->save_length) = Z - BEG;
3051 return Qnil;
3052}
3053
3054DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
3055 0, 0, 0,
3056 "Return t if buffer has been auto-saved since last read in or saved.")
3057 ()
3058{
3059 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
3060}
3061\f
3062/* Reading and completing file names */
3063extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
3064
3065DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
3066 3, 3, 0,
3067 "Internal subroutine for read-file-name. Do not call this.")
3068 (string, dir, action)
3069 Lisp_Object string, dir, action;
3070 /* action is nil for complete, t for return list of completions,
3071 lambda for verify final value */
3072{
3073 Lisp_Object name, specdir, realdir, val, orig_string;
09121adc
RS
3074 int changed;
3075 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3076
3077 realdir = dir;
3078 name = string;
3079 orig_string = Qnil;
3080 specdir = Qnil;
3081 changed = 0;
3082 /* No need to protect ACTION--we only compare it with t and nil. */
3083 GCPRO4 (string, realdir, name, specdir);
570d7624
JB
3084
3085 if (XSTRING (string)->size == 0)
3086 {
570d7624 3087 if (EQ (action, Qlambda))
09121adc
RS
3088 {
3089 UNGCPRO;
3090 return Qnil;
3091 }
570d7624
JB
3092 }
3093 else
3094 {
3095 orig_string = string;
3096 string = Fsubstitute_in_file_name (string);
09121adc 3097 changed = NILP (Fstring_equal (string, orig_string));
570d7624 3098 name = Ffile_name_nondirectory (string);
09121adc
RS
3099 val = Ffile_name_directory (string);
3100 if (! NILP (val))
3101 realdir = Fexpand_file_name (val, realdir);
570d7624
JB
3102 }
3103
265a9e55 3104 if (NILP (action))
570d7624
JB
3105 {
3106 specdir = Ffile_name_directory (string);
3107 val = Ffile_name_completion (name, realdir);
09121adc 3108 UNGCPRO;
570d7624
JB
3109 if (XTYPE (val) != Lisp_String)
3110 {
09121adc 3111 if (changed)
570d7624 3112 return string;
09121adc 3113 return val;
570d7624
JB
3114 }
3115
265a9e55 3116 if (!NILP (specdir))
570d7624
JB
3117 val = concat2 (specdir, val);
3118#ifndef VMS
3119 {
3120 register unsigned char *old, *new;
3121 register int n;
3122 int osize, count;
3123
3124 osize = XSTRING (val)->size;
3125 /* Quote "$" as "$$" to get it past substitute-in-file-name */
3126 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
3127 if (*old++ == '$') count++;
3128 if (count > 0)
3129 {
3130 old = XSTRING (val)->data;
3131 val = Fmake_string (make_number (osize + count), make_number (0));
3132 new = XSTRING (val)->data;
3133 for (n = osize; n > 0; n--)
3134 if (*old != '$')
3135 *new++ = *old++;
3136 else
3137 {
3138 *new++ = '$';
3139 *new++ = '$';
3140 old++;
3141 }
3142 }
3143 }
3144#endif /* Not VMS */
09121adc 3145 return val;
570d7624 3146 }
09121adc 3147 UNGCPRO;
570d7624
JB
3148
3149 if (EQ (action, Qt))
3150 return Ffile_name_all_completions (name, realdir);
3151 /* Only other case actually used is ACTION = lambda */
3152#ifdef VMS
3153 /* Supposedly this helps commands such as `cd' that read directory names,
3154 but can someone explain how it helps them? -- RMS */
3155 if (XSTRING (name)->size == 0)
3156 return Qt;
3157#endif /* VMS */
3158 return Ffile_exists_p (string);
3159}
3160
3161DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3162 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3163Value is not expanded---you must call `expand-file-name' yourself.\n\
3164Default name to DEFAULT if user enters a null string.\n\
3165 (If DEFAULT is omitted, the visited file name is used.)\n\
3166Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3167 Non-nil and non-t means also require confirmation after completion.\n\
3168Fifth arg INITIAL specifies text to start with.\n\
3169DIR defaults to current buffer's directory default.")
3170 (prompt, dir, defalt, mustmatch, initial)
3171 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3172{
85b5fe07 3173 Lisp_Object val, insdef, insdef1, tem;
570d7624
JB
3174 struct gcpro gcpro1, gcpro2;
3175 register char *homedir;
3176 int count;
3177
265a9e55 3178 if (NILP (dir))
570d7624 3179 dir = current_buffer->directory;
265a9e55 3180 if (NILP (defalt))
570d7624
JB
3181 defalt = current_buffer->filename;
3182
3183 /* If dir starts with user's homedir, change that to ~. */
3184 homedir = (char *) egetenv ("HOME");
3185 if (homedir != 0
3186 && XTYPE (dir) == Lisp_String
3187 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3188 && XSTRING (dir)->data[strlen (homedir)] == '/')
3189 {
3190 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3191 XSTRING (dir)->size - strlen (homedir) + 1);
3192 XSTRING (dir)->data[0] = '~';
3193 }
3194
3195 if (insert_default_directory)
3196 {
3197 insdef = dir;
85b5fe07 3198 insdef1 = dir;
265a9e55 3199 if (!NILP (initial))
570d7624 3200 {
15c65264 3201 Lisp_Object args[2], pos;
570d7624
JB
3202
3203 args[0] = insdef;
3204 args[1] = initial;
3205 insdef = Fconcat (2, args);
509b05ed 3206 pos = make_number (XSTRING (dir)->size);
85b5fe07 3207 insdef1 = Fcons (insdef, pos);
570d7624 3208 }
570d7624
JB
3209 }
3210 else
85b5fe07 3211 insdef = Qnil, insdef1 = Qnil;
570d7624
JB
3212
3213#ifdef VMS
3214 count = specpdl_ptr - specpdl;
3215 specbind (intern ("completion-ignore-case"), Qt);
3216#endif
3217
3218 GCPRO2 (insdef, defalt);
3219 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
85b5fe07 3220 dir, mustmatch, insdef1,
15c65264 3221 Qfile_name_history);
570d7624
JB
3222
3223#ifdef VMS
3224 unbind_to (count, Qnil);
3225#endif
3226
3227 UNGCPRO;
265a9e55 3228 if (NILP (val))
570d7624
JB
3229 error ("No file name specified");
3230 tem = Fstring_equal (val, insdef);
265a9e55 3231 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
3232 return defalt;
3233 return Fsubstitute_in_file_name (val);
3234}
3235
3236#if 0 /* Old version */
3237DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3238 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3239Value is not expanded---you must call `expand-file-name' yourself.\n\
3240Default name to DEFAULT if user enters a null string.\n\
3241 (If DEFAULT is omitted, the visited file name is used.)\n\
3242Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3243 Non-nil and non-t means also require confirmation after completion.\n\
3244Fifth arg INITIAL specifies text to start with.\n\
3245DIR defaults to current buffer's directory default.")
3246 (prompt, dir, defalt, mustmatch, initial)
3247 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3248{
3249 Lisp_Object val, insdef, tem;
3250 struct gcpro gcpro1, gcpro2;
3251 register char *homedir;
3252 int count;
3253
265a9e55 3254 if (NILP (dir))
570d7624 3255 dir = current_buffer->directory;
265a9e55 3256 if (NILP (defalt))
570d7624
JB
3257 defalt = current_buffer->filename;
3258
3259 /* If dir starts with user's homedir, change that to ~. */
3260 homedir = (char *) egetenv ("HOME");
3261 if (homedir != 0
3262 && XTYPE (dir) == Lisp_String
3263 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3264 && XSTRING (dir)->data[strlen (homedir)] == '/')
3265 {
3266 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3267 XSTRING (dir)->size - strlen (homedir) + 1);
3268 XSTRING (dir)->data[0] = '~';
3269 }
3270
265a9e55 3271 if (!NILP (initial))
570d7624
JB
3272 insdef = initial;
3273 else if (insert_default_directory)
3274 insdef = dir;
3275 else
3276 insdef = build_string ("");
3277
3278#ifdef VMS
3279 count = specpdl_ptr - specpdl;
3280 specbind (intern ("completion-ignore-case"), Qt);
3281#endif
3282
3283 GCPRO2 (insdef, defalt);
3284 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3285 dir, mustmatch,
15c65264
RS
3286 insert_default_directory ? insdef : Qnil,
3287 Qfile_name_history);
570d7624
JB
3288
3289#ifdef VMS
3290 unbind_to (count, Qnil);
3291#endif
3292
3293 UNGCPRO;
265a9e55 3294 if (NILP (val))
570d7624
JB
3295 error ("No file name specified");
3296 tem = Fstring_equal (val, insdef);
265a9e55 3297 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
3298 return defalt;
3299 return Fsubstitute_in_file_name (val);
3300}
3301#endif /* Old version */
3302\f
3303syms_of_fileio ()
3304{
0bf2eed2
RS
3305 Qexpand_file_name = intern ("expand-file-name");
3306 Qdirectory_file_name = intern ("directory-file-name");
3307 Qfile_name_directory = intern ("file-name-directory");
3308 Qfile_name_nondirectory = intern ("file-name-nondirectory");
642ef245 3309 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
0bf2eed2 3310 Qfile_name_as_directory = intern ("file-name-as-directory");
32f4334d
RS
3311 Qcopy_file = intern ("copy-file");
3312 Qmake_directory = intern ("make-directory");
3313 Qdelete_directory = intern ("delete-directory");
3314 Qdelete_file = intern ("delete-file");
3315 Qrename_file = intern ("rename-file");
3316 Qadd_name_to_file = intern ("add-name-to-file");
3317 Qmake_symbolic_link = intern ("make-symbolic-link");
3318 Qfile_exists_p = intern ("file-exists-p");
3319 Qfile_executable_p = intern ("file-executable-p");
3320 Qfile_readable_p = intern ("file-readable-p");
3321 Qfile_symlink_p = intern ("file-symlink-p");
3322 Qfile_writable_p = intern ("file-writable-p");
3323 Qfile_directory_p = intern ("file-directory-p");
3324 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
3325 Qfile_modes = intern ("file-modes");
3326 Qset_file_modes = intern ("set-file-modes");
3327 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
3328 Qinsert_file_contents = intern ("insert-file-contents");
3329 Qwrite_region = intern ("write-region");
3330 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3331
642ef245
JB
3332 staticpro (&Qexpand_file_name);
3333 staticpro (&Qdirectory_file_name);
3334 staticpro (&Qfile_name_directory);
3335 staticpro (&Qfile_name_nondirectory);
3336 staticpro (&Qunhandled_file_name_directory);
3337 staticpro (&Qfile_name_as_directory);
15c65264
RS
3338 staticpro (&Qcopy_file);
3339 staticpro (&Qmake_directory);
3340 staticpro (&Qdelete_directory);
3341 staticpro (&Qdelete_file);
3342 staticpro (&Qrename_file);
3343 staticpro (&Qadd_name_to_file);
3344 staticpro (&Qmake_symbolic_link);
3345 staticpro (&Qfile_exists_p);
3346 staticpro (&Qfile_executable_p);
3347 staticpro (&Qfile_readable_p);
3348 staticpro (&Qfile_symlink_p);
3349 staticpro (&Qfile_writable_p);
3350 staticpro (&Qfile_directory_p);
3351 staticpro (&Qfile_accessible_directory_p);
3352 staticpro (&Qfile_modes);
3353 staticpro (&Qset_file_modes);
3354 staticpro (&Qfile_newer_than_file_p);
3355 staticpro (&Qinsert_file_contents);
3356 staticpro (&Qwrite_region);
3357 staticpro (&Qverify_visited_file_modtime);
642ef245
JB
3358
3359 Qfile_name_history = intern ("file-name-history");
3360 Fset (Qfile_name_history, Qnil);
15c65264
RS
3361 staticpro (&Qfile_name_history);
3362
570d7624
JB
3363 Qfile_error = intern ("file-error");
3364 staticpro (&Qfile_error);
3365 Qfile_already_exists = intern("file-already-exists");
3366 staticpro (&Qfile_already_exists);
3367
3368 Fput (Qfile_error, Qerror_conditions,
3369 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
3370 Fput (Qfile_error, Qerror_message,
3371 build_string ("File error"));
3372
3373 Fput (Qfile_already_exists, Qerror_conditions,
3374 Fcons (Qfile_already_exists,
3375 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
3376 Fput (Qfile_already_exists, Qerror_message,
3377 build_string ("File already exists"));
3378
3379 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
3380 "*Non-nil means when reading a filename start with default dir in minibuffer.");
3381 insert_default_directory = 1;
3382
3383 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
3384 "*Non-nil means write new files with record format `stmlf'.\n\
3385nil means use format `var'. This variable is meaningful only on VMS.");
3386 vms_stmlf_recfm = 0;
3387
1d1826db
RS
3388 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
3389 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
3390If a file name matches REGEXP, then all I/O on that file is done by calling\n\
3391HANDLER.\n\
3392\n\
3393The first argument given to HANDLER is the name of the I/O primitive\n\
3394to be handled; the remaining arguments are the arguments that were\n\
3395passed to that primitive. For example, if you do\n\
3396 (file-exists-p FILENAME)\n\
3397and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
642ef245
JB
3398 (funcall HANDLER 'file-exists-p FILENAME)\n\
3399The function `find-file-name-handler' checks this list for a handler\n\
3400for its argument.");
09121adc
RS
3401 Vfile_name_handler_alist = Qnil;
3402
642ef245 3403 defsubr (&Sfind_file_name_handler);
570d7624
JB
3404 defsubr (&Sfile_name_directory);
3405 defsubr (&Sfile_name_nondirectory);
642ef245 3406 defsubr (&Sunhandled_file_name_directory);
570d7624
JB
3407 defsubr (&Sfile_name_as_directory);
3408 defsubr (&Sdirectory_file_name);
3409 defsubr (&Smake_temp_name);
3410 defsubr (&Sexpand_file_name);
3411 defsubr (&Ssubstitute_in_file_name);
3412 defsubr (&Scopy_file);
9bbe01fb 3413 defsubr (&Smake_directory_internal);
aa734e17 3414 defsubr (&Sdelete_directory);
570d7624
JB
3415 defsubr (&Sdelete_file);
3416 defsubr (&Srename_file);
3417 defsubr (&Sadd_name_to_file);
3418#ifdef S_IFLNK
3419 defsubr (&Smake_symbolic_link);
3420#endif /* S_IFLNK */
3421#ifdef VMS
3422 defsubr (&Sdefine_logical_name);
3423#endif /* VMS */
3424#ifdef HPUX_NET
3425 defsubr (&Ssysnetunam);
3426#endif /* HPUX_NET */
3427 defsubr (&Sfile_name_absolute_p);
3428 defsubr (&Sfile_exists_p);
3429 defsubr (&Sfile_executable_p);
3430 defsubr (&Sfile_readable_p);
3431 defsubr (&Sfile_writable_p);
3432 defsubr (&Sfile_symlink_p);
3433 defsubr (&Sfile_directory_p);
b72dea2a 3434 defsubr (&Sfile_accessible_directory_p);
570d7624
JB
3435 defsubr (&Sfile_modes);
3436 defsubr (&Sset_file_modes);
c24e9a53
RS
3437 defsubr (&Sset_default_file_modes);
3438 defsubr (&Sdefault_file_modes);
570d7624
JB
3439 defsubr (&Sfile_newer_than_file_p);
3440 defsubr (&Sinsert_file_contents);
3441 defsubr (&Swrite_region);
3442 defsubr (&Sverify_visited_file_modtime);
3443 defsubr (&Sclear_visited_file_modtime);
f5d5eccf 3444 defsubr (&Svisited_file_modtime);
570d7624
JB
3445 defsubr (&Sset_visited_file_modtime);
3446 defsubr (&Sdo_auto_save);
3447 defsubr (&Sset_buffer_auto_saved);
3448 defsubr (&Srecent_auto_save_p);
3449
3450 defsubr (&Sread_file_name_internal);
3451 defsubr (&Sread_file_name);
85ffea93 3452
483a2e10 3453#ifdef unix
85ffea93 3454 defsubr (&Sunix_sync);
483a2e10 3455#endif
570d7624 3456}