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