(dired-sort-mode): Variable deleted.
[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
ffd56f97 20#include "config.h"
570d7624
JB
21
22#include <sys/types.h>
23#include <sys/stat.h>
bfb61299
JB
24
25#ifdef VMS
de5bf5d3 26#include "vms-pwd.h"
bfb61299 27#else
570d7624 28#include <pwd.h>
bfb61299
JB
29#endif
30
570d7624 31#include <ctype.h>
bfb61299
JB
32
33#ifdef VMS
34#include "dir.h"
35#include <perror.h>
36#include <stddef.h>
37#include <string.h>
bfb61299
JB
38#endif
39
570d7624
JB
40#include <errno.h>
41
bfb61299 42#ifndef vax11c
570d7624
JB
43extern int errno;
44extern char *sys_errlist[];
45extern int sys_nerr;
46#endif
47
48#define err_str(a) ((a) < sys_nerr ? sys_errlist[a] : "unknown error")
49
50#ifdef APOLLO
51#include <sys/time.h>
52#endif
53
6e23c83e
JB
54#ifndef USG
55#ifndef VMS
56#ifndef BSD4_1
57#define HAVE_FSYNC
58#endif
59#endif
60#endif
61
570d7624 62#include "lisp.h"
8d4e077b 63#include "intervals.h"
570d7624
JB
64#include "buffer.h"
65#include "window.h"
66
67#ifdef VMS
570d7624
JB
68#include <file.h>
69#include <rmsdef.h>
70#include <fab.h>
71#include <nam.h>
72#endif
73
de5bf5d3 74#include "systime.h"
570d7624
JB
75
76#ifdef HPUX
77#include <netio.h>
9b7828a5 78#ifndef HPUX8
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
JB
1508/* A slightly faster and more convenient way to get
1509 (directory-file-name (expand-file-name FOO)). The return value may
1510 have had its last character zapped with a '\0' character, meaning
1511 that it is acceptable to system calls, but not to other lisp
1512 functions. Callers should make sure that the return value doesn't
1513 escape. */
1514
570d7624
JB
1515Lisp_Object
1516expand_and_dir_to_file (filename, defdir)
1517 Lisp_Object filename, defdir;
1518{
1519 register Lisp_Object abspath;
1520
1521 abspath = Fexpand_file_name (filename, defdir);
1522#ifdef VMS
1523 {
1524 register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1];
1525 if (c == ':' || c == ']' || c == '>')
1526 abspath = Fdirectory_file_name (abspath);
1527 }
1528#else
1529 /* Remove final slash, if any (unless path is root).
1530 stat behaves differently depending! */
1531 if (XSTRING (abspath)->size > 1
1532 && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/')
1533 {
1534 if (EQ (abspath, filename))
1535 abspath = Fcopy_sequence (abspath);
1536 XSTRING (abspath)->data[XSTRING (abspath)->size - 1] = 0;
1537 }
1538#endif
1539 return abspath;
1540}
1541\f
1542barf_or_query_if_file_exists (absname, querystring, interactive)
1543 Lisp_Object absname;
1544 unsigned char *querystring;
1545 int interactive;
1546{
1547 register Lisp_Object tem;
1548 struct gcpro gcpro1;
1549
1550 if (access (XSTRING (absname)->data, 4) >= 0)
1551 {
1552 if (! interactive)
1553 Fsignal (Qfile_already_exists,
1554 Fcons (build_string ("File already exists"),
1555 Fcons (absname, Qnil)));
1556 GCPRO1 (absname);
1557 tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
1558 XSTRING (absname)->data, querystring));
1559 UNGCPRO;
265a9e55 1560 if (NILP (tem))
570d7624
JB
1561 Fsignal (Qfile_already_exists,
1562 Fcons (build_string ("File already exists"),
1563 Fcons (absname, Qnil)));
1564 }
1565 return;
1566}
1567
1568DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4,
349a7710 1569 "fCopy file: \nFCopy %s to file: \np\nP",
570d7624
JB
1570 "Copy FILE to NEWNAME. Both args must be strings.\n\
1571Signals a `file-already-exists' error if file NEWNAME already exists,\n\
1572unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\
1573A number as third arg means request confirmation if NEWNAME already exists.\n\
1574This is what happens in interactive use with M-x.\n\
349a7710
JB
1575Fourth arg KEEP-TIME non-nil means give the new file the same\n\
1576last-modified time as the old one. (This works on only some systems.)\n\
1577A prefix arg makes KEEP-TIME non-nil.")
570d7624
JB
1578 (filename, newname, ok_if_already_exists, keep_date)
1579 Lisp_Object filename, newname, ok_if_already_exists, keep_date;
1580{
1581 int ifd, ofd, n;
1582 char buf[16 * 1024];
1583 struct stat st;
32f4334d 1584 Lisp_Object handler;
570d7624 1585 struct gcpro gcpro1, gcpro2;
b5148e85 1586 int count = specpdl_ptr - specpdl;
51cf6d37 1587 Lisp_Object args[6];
570d7624
JB
1588
1589 GCPRO2 (filename, newname);
1590 CHECK_STRING (filename, 0);
1591 CHECK_STRING (newname, 1);
1592 filename = Fexpand_file_name (filename, Qnil);
1593 newname = Fexpand_file_name (newname, Qnil);
32f4334d 1594
0bf2eed2 1595 /* If the input file name has special constructs in it,
32f4334d 1596 call the corresponding file handler. */
642ef245 1597 handler = Ffind_file_name_handler (filename);
0bf2eed2 1598 /* Likewise for output file name. */
51cf6d37
RS
1599 if (NILP (handler))
1600 handler = Ffind_file_name_handler (newname);
32f4334d 1601 if (!NILP (handler))
51cf6d37
RS
1602 return call5 (handler, Qcopy_file, filename, newname,
1603 ok_if_already_exists, keep_date);
32f4334d 1604
265a9e55 1605 if (NILP (ok_if_already_exists)
570d7624
JB
1606 || XTYPE (ok_if_already_exists) == Lisp_Int)
1607 barf_or_query_if_file_exists (newname, "copy to it",
1608 XTYPE (ok_if_already_exists) == Lisp_Int);
1609
1610 ifd = open (XSTRING (filename)->data, 0);
1611 if (ifd < 0)
1612 report_file_error ("Opening input file", Fcons (filename, Qnil));
1613
b5148e85
RS
1614 record_unwind_protect (close_file_unwind, make_number (ifd));
1615
570d7624
JB
1616#ifdef VMS
1617 /* Create the copy file with the same record format as the input file */
1618 ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
1619#else
1620 ofd = creat (XSTRING (newname)->data, 0666);
1621#endif /* VMS */
1622 if (ofd < 0)
66331187 1623 report_file_error ("Opening output file", Fcons (newname, Qnil));
b5148e85
RS
1624
1625 record_unwind_protect (close_file_unwind, make_number (ofd));
570d7624 1626
b5148e85
RS
1627 immediate_quit = 1;
1628 QUIT;
570d7624
JB
1629 while ((n = read (ifd, buf, sizeof buf)) > 0)
1630 if (write (ofd, buf, n) != n)
66331187 1631 report_file_error ("I/O error", Fcons (newname, Qnil));
b5148e85 1632 immediate_quit = 0;
570d7624
JB
1633
1634 if (fstat (ifd, &st) >= 0)
1635 {
265a9e55 1636 if (!NILP (keep_date))
570d7624 1637 {
de5bf5d3
JB
1638 EMACS_TIME atime, mtime;
1639 EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
1640 EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
1641 EMACS_SET_UTIMES (XSTRING (newname)->data, atime, mtime);
570d7624 1642 }
570d7624
JB
1643#ifdef APOLLO
1644 if (!egetenv ("USE_DOMAIN_ACLS"))
1645#endif
de5bf5d3 1646 chmod (XSTRING (newname)->data, st.st_mode & 07777);
570d7624
JB
1647 }
1648
b5148e85
RS
1649 /* Discard the unwind protects. */
1650 specpdl_ptr = specpdl + count;
1651
570d7624
JB
1652 close (ifd);
1653 if (close (ofd) < 0)
1654 report_file_error ("I/O error", Fcons (newname, Qnil));
1655
1656 UNGCPRO;
1657 return Qnil;
1658}
1659
9bbe01fb 1660DEFUN ("make-directory-internal", Fmake_directory_internal,
353cfc19 1661 Smake_directory_internal, 1, 1, 0,
570d7624
JB
1662 "Create a directory. One argument, a file name string.")
1663 (dirname)
1664 Lisp_Object dirname;
1665{
1666 unsigned char *dir;
32f4334d 1667 Lisp_Object handler;
570d7624
JB
1668
1669 CHECK_STRING (dirname, 0);
1670 dirname = Fexpand_file_name (dirname, Qnil);
32f4334d 1671
642ef245 1672 handler = Ffind_file_name_handler (dirname);
32f4334d 1673 if (!NILP (handler))
9bbe01fb
RS
1674 return call3 (handler, Qmake_directory, dirname, Qnil);
1675
570d7624
JB
1676 dir = XSTRING (dirname)->data;
1677
1678 if (mkdir (dir, 0777) != 0)
1679 report_file_error ("Creating directory", Flist (1, &dirname));
1680
32f4334d 1681 return Qnil;
570d7624
JB
1682}
1683
aa734e17
RS
1684DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
1685 "Delete a directory. One argument, a file name string.")
570d7624
JB
1686 (dirname)
1687 Lisp_Object dirname;
1688{
1689 unsigned char *dir;
32f4334d 1690 Lisp_Object handler;
570d7624
JB
1691
1692 CHECK_STRING (dirname, 0);
1693 dirname = Fexpand_file_name (dirname, Qnil);
1694 dir = XSTRING (dirname)->data;
1695
642ef245 1696 handler = Ffind_file_name_handler (dirname);
32f4334d
RS
1697 if (!NILP (handler))
1698 return call2 (handler, Qdelete_directory, dirname);
1699
570d7624
JB
1700 if (rmdir (dir) != 0)
1701 report_file_error ("Removing directory", Flist (1, &dirname));
1702
1703 return Qnil;
1704}
1705
1706DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
1707 "Delete specified file. One argument, a file name string.\n\
1708If file has multiple names, it continues to exist with the other names.")
1709 (filename)
1710 Lisp_Object filename;
1711{
32f4334d 1712 Lisp_Object handler;
570d7624
JB
1713 CHECK_STRING (filename, 0);
1714 filename = Fexpand_file_name (filename, Qnil);
32f4334d 1715
642ef245 1716 handler = Ffind_file_name_handler (filename);
32f4334d
RS
1717 if (!NILP (handler))
1718 return call2 (handler, Qdelete_file, filename);
1719
570d7624
JB
1720 if (0 > unlink (XSTRING (filename)->data))
1721 report_file_error ("Removing old name", Flist (1, &filename));
1722 return Qnil;
1723}
1724
1725DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
1726 "fRename file: \nFRename %s to file: \np",
1727 "Rename FILE as NEWNAME. Both args strings.\n\
1728If file has names other than FILE, it continues to have those names.\n\
1729Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1730unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1731A number as third arg means request confirmation if NEWNAME already exists.\n\
1732This is what happens in interactive use with M-x.")
1733 (filename, newname, ok_if_already_exists)
1734 Lisp_Object filename, newname, ok_if_already_exists;
1735{
1736#ifdef NO_ARG_ARRAY
1737 Lisp_Object args[2];
1738#endif
32f4334d 1739 Lisp_Object handler;
570d7624
JB
1740 struct gcpro gcpro1, gcpro2;
1741
1742 GCPRO2 (filename, newname);
1743 CHECK_STRING (filename, 0);
1744 CHECK_STRING (newname, 1);
1745 filename = Fexpand_file_name (filename, Qnil);
1746 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1747
1748 /* If the file name has special constructs in it,
1749 call the corresponding file handler. */
642ef245 1750 handler = Ffind_file_name_handler (filename);
51cf6d37
RS
1751 if (NILP (handler))
1752 handler = Ffind_file_name_handler (newname);
32f4334d 1753 if (!NILP (handler))
a5a44b91
JB
1754 return call4 (handler, Qrename_file,
1755 filename, newname, ok_if_already_exists);
32f4334d 1756
265a9e55 1757 if (NILP (ok_if_already_exists)
570d7624
JB
1758 || XTYPE (ok_if_already_exists) == Lisp_Int)
1759 barf_or_query_if_file_exists (newname, "rename to it",
1760 XTYPE (ok_if_already_exists) == Lisp_Int);
1761#ifndef BSD4_1
1762 if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
1763#else
1764 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data)
1765 || 0 > unlink (XSTRING (filename)->data))
1766#endif
1767 {
1768 if (errno == EXDEV)
1769 {
d093c3ac
RM
1770 Fcopy_file (filename, newname,
1771 /* We have already prompted if it was an integer,
1772 so don't have copy-file prompt again. */
1773 NILP (ok_if_already_exists) ? Qnil : Qt, Qt);
570d7624
JB
1774 Fdelete_file (filename);
1775 }
1776 else
1777#ifdef NO_ARG_ARRAY
1778 {
1779 args[0] = filename;
1780 args[1] = newname;
1781 report_file_error ("Renaming", Flist (2, args));
1782 }
1783#else
1784 report_file_error ("Renaming", Flist (2, &filename));
1785#endif
1786 }
1787 UNGCPRO;
1788 return Qnil;
1789}
1790
1791DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3,
1792 "fAdd name to file: \nFName to add to %s: \np",
1793 "Give FILE additional name NEWNAME. Both args strings.\n\
1794Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1795unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1796A number as third arg means request confirmation if NEWNAME already exists.\n\
1797This is what happens in interactive use with M-x.")
1798 (filename, newname, ok_if_already_exists)
1799 Lisp_Object filename, newname, ok_if_already_exists;
1800{
1801#ifdef NO_ARG_ARRAY
1802 Lisp_Object args[2];
1803#endif
32f4334d 1804 Lisp_Object handler;
570d7624
JB
1805 struct gcpro gcpro1, gcpro2;
1806
1807 GCPRO2 (filename, newname);
1808 CHECK_STRING (filename, 0);
1809 CHECK_STRING (newname, 1);
1810 filename = Fexpand_file_name (filename, Qnil);
1811 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1812
1813 /* If the file name has special constructs in it,
1814 call the corresponding file handler. */
642ef245 1815 handler = Ffind_file_name_handler (filename);
32f4334d 1816 if (!NILP (handler))
51cf6d37
RS
1817 return call4 (handler, Qadd_name_to_file, filename, newname,
1818 ok_if_already_exists);
32f4334d 1819
265a9e55 1820 if (NILP (ok_if_already_exists)
570d7624
JB
1821 || XTYPE (ok_if_already_exists) == Lisp_Int)
1822 barf_or_query_if_file_exists (newname, "make it a new name",
1823 XTYPE (ok_if_already_exists) == Lisp_Int);
1824 unlink (XSTRING (newname)->data);
1825 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data))
1826 {
1827#ifdef NO_ARG_ARRAY
1828 args[0] = filename;
1829 args[1] = newname;
1830 report_file_error ("Adding new name", Flist (2, args));
1831#else
1832 report_file_error ("Adding new name", Flist (2, &filename));
1833#endif
1834 }
1835
1836 UNGCPRO;
1837 return Qnil;
1838}
1839
1840#ifdef S_IFLNK
1841DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
1842 "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",
1843 "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\
1844Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1845unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1846A number as third arg means request confirmation if NEWNAME already exists.\n\
1847This happens for interactive use with M-x.")
e5d77022
JB
1848 (filename, linkname, ok_if_already_exists)
1849 Lisp_Object filename, linkname, ok_if_already_exists;
570d7624
JB
1850{
1851#ifdef NO_ARG_ARRAY
1852 Lisp_Object args[2];
1853#endif
32f4334d 1854 Lisp_Object handler;
570d7624
JB
1855 struct gcpro gcpro1, gcpro2;
1856
e5d77022 1857 GCPRO2 (filename, linkname);
570d7624 1858 CHECK_STRING (filename, 0);
e5d77022 1859 CHECK_STRING (linkname, 1);
570d7624
JB
1860#if 0 /* This made it impossible to make a link to a relative name. */
1861 filename = Fexpand_file_name (filename, Qnil);
1862#endif
e5d77022 1863 linkname = Fexpand_file_name (linkname, Qnil);
32f4334d
RS
1864
1865 /* If the file name has special constructs in it,
1866 call the corresponding file handler. */
642ef245 1867 handler = Ffind_file_name_handler (filename);
32f4334d 1868 if (!NILP (handler))
51cf6d37
RS
1869 return call4 (handler, Qmake_symbolic_link, filename, linkname,
1870 ok_if_already_exists);
32f4334d 1871
265a9e55 1872 if (NILP (ok_if_already_exists)
570d7624 1873 || XTYPE (ok_if_already_exists) == Lisp_Int)
e5d77022 1874 barf_or_query_if_file_exists (linkname, "make it a link",
570d7624 1875 XTYPE (ok_if_already_exists) == Lisp_Int);
e5d77022 1876 if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
1877 {
1878 /* If we didn't complain already, silently delete existing file. */
1879 if (errno == EEXIST)
1880 {
9083124b 1881 unlink (XSTRING (linkname)->data);
e5d77022 1882 if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
1883 return Qnil;
1884 }
1885
1886#ifdef NO_ARG_ARRAY
1887 args[0] = filename;
e5d77022 1888 args[1] = linkname;
570d7624
JB
1889 report_file_error ("Making symbolic link", Flist (2, args));
1890#else
1891 report_file_error ("Making symbolic link", Flist (2, &filename));
1892#endif
1893 }
1894 UNGCPRO;
1895 return Qnil;
1896}
1897#endif /* S_IFLNK */
1898
1899#ifdef VMS
1900
1901DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
1902 2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
1903 "Define the job-wide logical name NAME to have the value STRING.\n\
1904If STRING is nil or a null string, the logical name NAME is deleted.")
1905 (varname, string)
1906 Lisp_Object varname;
1907 Lisp_Object string;
1908{
1909 CHECK_STRING (varname, 0);
265a9e55 1910 if (NILP (string))
570d7624
JB
1911 delete_logical_name (XSTRING (varname)->data);
1912 else
1913 {
1914 CHECK_STRING (string, 1);
1915
1916 if (XSTRING (string)->size == 0)
1917 delete_logical_name (XSTRING (varname)->data);
1918 else
1919 define_logical_name (XSTRING (varname)->data, XSTRING (string)->data);
1920 }
1921
1922 return string;
1923}
1924#endif /* VMS */
1925
1926#ifdef HPUX_NET
1927
1928DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
1929 "Open a network connection to PATH using LOGIN as the login string.")
1930 (path, login)
1931 Lisp_Object path, login;
1932{
1933 int netresult;
1934
1935 CHECK_STRING (path, 0);
1936 CHECK_STRING (login, 0);
1937
1938 netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
1939
1940 if (netresult == -1)
1941 return Qnil;
1942 else
1943 return Qt;
1944}
1945#endif /* HPUX_NET */
1946\f
1947DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
1948 1, 1, 0,
1949 "Return t if file FILENAME specifies an absolute path name.\n\
1950On Unix, this is a name starting with a `/' or a `~'.")
1951 (filename)
1952 Lisp_Object filename;
1953{
1954 unsigned char *ptr;
1955
1956 CHECK_STRING (filename, 0);
1957 ptr = XSTRING (filename)->data;
1958 if (*ptr == '/' || *ptr == '~'
1959#ifdef VMS
1960/* ??? This criterion is probably wrong for '<'. */
1961 || index (ptr, ':') || index (ptr, '<')
1962 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
1963 && ptr[1] != '.')
1964#endif /* VMS */
1965 )
1966 return Qt;
1967 else
1968 return Qnil;
1969}
1970
1971DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
1972 "Return t if file FILENAME exists. (This does not mean you can read it.)\n\
1973See also `file-readable-p' and `file-attributes'.")
1974 (filename)
1975 Lisp_Object filename;
1976{
1977 Lisp_Object abspath;
32f4334d 1978 Lisp_Object handler;
570d7624
JB
1979
1980 CHECK_STRING (filename, 0);
1981 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1982
1983 /* If the file name has special constructs in it,
1984 call the corresponding file handler. */
642ef245 1985 handler = Ffind_file_name_handler (abspath);
32f4334d 1986 if (!NILP (handler))
09121adc 1987 return call2 (handler, Qfile_exists_p, abspath);
32f4334d 1988
570d7624
JB
1989 return (access (XSTRING (abspath)->data, 0) >= 0) ? Qt : Qnil;
1990}
1991
1992DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
1993 "Return t if FILENAME can be executed by you.\n\
8b235fde 1994For a directory, this means you can access files in that directory.")
570d7624
JB
1995 (filename)
1996 Lisp_Object filename;
1997
1998{
1999 Lisp_Object abspath;
32f4334d 2000 Lisp_Object handler;
570d7624
JB
2001
2002 CHECK_STRING (filename, 0);
2003 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2004
2005 /* If the file name has special constructs in it,
2006 call the corresponding file handler. */
642ef245 2007 handler = Ffind_file_name_handler (abspath);
32f4334d 2008 if (!NILP (handler))
09121adc 2009 return call2 (handler, Qfile_executable_p, abspath);
32f4334d 2010
570d7624
JB
2011 return (access (XSTRING (abspath)->data, 1) >= 0) ? Qt : Qnil;
2012}
2013
2014DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
2015 "Return t if file FILENAME exists and you can read it.\n\
2016See also `file-exists-p' and `file-attributes'.")
2017 (filename)
2018 Lisp_Object filename;
2019{
2020 Lisp_Object abspath;
32f4334d 2021 Lisp_Object handler;
570d7624
JB
2022
2023 CHECK_STRING (filename, 0);
2024 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2025
2026 /* If the file name has special constructs in it,
2027 call the corresponding file handler. */
642ef245 2028 handler = Ffind_file_name_handler (abspath);
32f4334d 2029 if (!NILP (handler))
09121adc 2030 return call2 (handler, Qfile_readable_p, abspath);
32f4334d 2031
570d7624
JB
2032 return (access (XSTRING (abspath)->data, 4) >= 0) ? Qt : Qnil;
2033}
2034
2035DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
2036 "If file FILENAME is the name of a symbolic link\n\
2037returns the name of the file to which it is linked.\n\
2038Otherwise returns NIL.")
2039 (filename)
2040 Lisp_Object filename;
2041{
2042#ifdef S_IFLNK
2043 char *buf;
2044 int bufsize;
2045 int valsize;
2046 Lisp_Object val;
32f4334d 2047 Lisp_Object handler;
570d7624
JB
2048
2049 CHECK_STRING (filename, 0);
2050 filename = Fexpand_file_name (filename, Qnil);
2051
32f4334d
RS
2052 /* If the file name has special constructs in it,
2053 call the corresponding file handler. */
642ef245 2054 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2055 if (!NILP (handler))
2056 return call2 (handler, Qfile_symlink_p, filename);
2057
570d7624
JB
2058 bufsize = 100;
2059 while (1)
2060 {
2061 buf = (char *) xmalloc (bufsize);
2062 bzero (buf, bufsize);
2063 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
2064 if (valsize < bufsize) break;
2065 /* Buffer was not long enough */
9ac0d9e0 2066 xfree (buf);
570d7624
JB
2067 bufsize *= 2;
2068 }
2069 if (valsize == -1)
2070 {
9ac0d9e0 2071 xfree (buf);
570d7624
JB
2072 return Qnil;
2073 }
2074 val = make_string (buf, valsize);
9ac0d9e0 2075 xfree (buf);
570d7624
JB
2076 return val;
2077#else /* not S_IFLNK */
2078 return Qnil;
2079#endif /* not S_IFLNK */
2080}
2081
a253bab2
JB
2082#ifdef SOLARIS_BROKEN_ACCESS
2083/* In Solaris 2.1, the readonly-ness of the filesystem is not
2084 considered by the access system call. This is Sun's bug, but we
2085 still have to make Emacs work. */
2086
2087#include <sys/statvfs.h>
2088
2089static int
2090ro_fsys (path)
2091 char *path;
2092{
2093 struct statvfs statvfsb;
2094
2095 if (statvfs(path, &statvfsb))
2096 return 1; /* error from statvfs, be conservative and say not wrtable */
2097 else
2098 /* Otherwise, fsys is ro if bit is set. */
2099 return statvfsb.f_flag & ST_RDONLY;
2100}
2101#else
2102/* But on every other os, access has already done the right thing. */
2103#define ro_fsys(path) 0
2104#endif
2105
570d7624
JB
2106/* Having this before file-symlink-p mysteriously caused it to be forgotten
2107 on the RT/PC. */
2108DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
2109 "Return t if file FILENAME can be written or created by you.")
2110 (filename)
2111 Lisp_Object filename;
2112{
2113 Lisp_Object abspath, dir;
32f4334d 2114 Lisp_Object handler;
570d7624
JB
2115
2116 CHECK_STRING (filename, 0);
2117 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
2118
2119 /* If the file name has special constructs in it,
2120 call the corresponding file handler. */
642ef245 2121 handler = Ffind_file_name_handler (abspath);
32f4334d 2122 if (!NILP (handler))
09121adc 2123 return call2 (handler, Qfile_writable_p, abspath);
32f4334d 2124
570d7624 2125 if (access (XSTRING (abspath)->data, 0) >= 0)
a253bab2 2126 return ((access (XSTRING (abspath)->data, 2) >= 0
e7c7295c 2127 && ! ro_fsys ((char *) XSTRING (abspath)->data))
a253bab2 2128 ? Qt : Qnil);
570d7624
JB
2129 dir = Ffile_name_directory (abspath);
2130#ifdef VMS
265a9e55 2131 if (!NILP (dir))
570d7624
JB
2132 dir = Fdirectory_file_name (dir);
2133#endif /* VMS */
a253bab2 2134 return ((access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
e7c7295c 2135 && ! ro_fsys ((char *) XSTRING (dir)->data))
570d7624
JB
2136 ? Qt : Qnil);
2137}
2138
2139DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
2140 "Return t if file FILENAME is the name of a directory as a file.\n\
2141A directory name spec may be given instead; then the value is t\n\
2142if the directory so specified exists and really is a directory.")
2143 (filename)
2144 Lisp_Object filename;
2145{
2146 register Lisp_Object abspath;
2147 struct stat st;
32f4334d 2148 Lisp_Object handler;
570d7624
JB
2149
2150 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2151
32f4334d
RS
2152 /* If the file name has special constructs in it,
2153 call the corresponding file handler. */
642ef245 2154 handler = Ffind_file_name_handler (abspath);
32f4334d 2155 if (!NILP (handler))
09121adc 2156 return call2 (handler, Qfile_directory_p, abspath);
32f4334d 2157
570d7624
JB
2158 if (stat (XSTRING (abspath)->data, &st) < 0)
2159 return Qnil;
2160 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2161}
2162
b72dea2a
JB
2163DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
2164 "Return t if file FILENAME is the name of a directory as a file,\n\
2165and files in that directory can be opened by you. In order to use a\n\
2166directory as a buffer's current directory, this predicate must return true.\n\
2167A directory name spec may be given instead; then the value is t\n\
2168if the directory so specified exists and really is a readable and\n\
2169searchable directory.")
2170 (filename)
2171 Lisp_Object filename;
2172{
32f4334d
RS
2173 Lisp_Object handler;
2174
2175 /* If the file name has special constructs in it,
2176 call the corresponding file handler. */
642ef245 2177 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2178 if (!NILP (handler))
2179 return call2 (handler, Qfile_accessible_directory_p, filename);
2180
b72dea2a
JB
2181 if (NILP (Ffile_directory_p (filename))
2182 || NILP (Ffile_executable_p (filename)))
2183 return Qnil;
2184 else
2185 return Qt;
2186}
2187
570d7624
JB
2188DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2189 "Return mode bits of FILE, as an integer.")
2190 (filename)
2191 Lisp_Object filename;
2192{
2193 Lisp_Object abspath;
2194 struct stat st;
32f4334d 2195 Lisp_Object handler;
570d7624
JB
2196
2197 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2198
32f4334d
RS
2199 /* If the file name has special constructs in it,
2200 call the corresponding file handler. */
642ef245 2201 handler = Ffind_file_name_handler (abspath);
32f4334d 2202 if (!NILP (handler))
09121adc 2203 return call2 (handler, Qfile_modes, abspath);
32f4334d 2204
570d7624
JB
2205 if (stat (XSTRING (abspath)->data, &st) < 0)
2206 return Qnil;
2207 return make_number (st.st_mode & 07777);
2208}
2209
2210DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2211 "Set mode bits of FILE to MODE (an integer).\n\
2212Only the 12 low bits of MODE are used.")
2213 (filename, mode)
2214 Lisp_Object filename, mode;
2215{
2216 Lisp_Object abspath;
32f4334d 2217 Lisp_Object handler;
570d7624
JB
2218
2219 abspath = Fexpand_file_name (filename, current_buffer->directory);
2220 CHECK_NUMBER (mode, 1);
2221
32f4334d
RS
2222 /* If the file name has special constructs in it,
2223 call the corresponding file handler. */
642ef245 2224 handler = Ffind_file_name_handler (abspath);
32f4334d 2225 if (!NILP (handler))
09121adc 2226 return call3 (handler, Qset_file_modes, abspath, mode);
32f4334d 2227
570d7624
JB
2228#ifndef APOLLO
2229 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2230 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2231#else /* APOLLO */
2232 if (!egetenv ("USE_DOMAIN_ACLS"))
2233 {
2234 struct stat st;
2235 struct timeval tvp[2];
2236
2237 /* chmod on apollo also change the file's modtime; need to save the
2238 modtime and then restore it. */
2239 if (stat (XSTRING (abspath)->data, &st) < 0)
2240 {
2241 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2242 return (Qnil);
2243 }
2244
2245 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2246 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2247
2248 /* reset the old accessed and modified times. */
2249 tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
2250 tvp[0].tv_usec = 0;
2251 tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
2252 tvp[1].tv_usec = 0;
2253
2254 if (utimes (XSTRING (abspath)->data, tvp) < 0)
2255 report_file_error ("Doing utimes", Fcons (abspath, Qnil));
2256 }
2257#endif /* APOLLO */
2258
2259 return Qnil;
2260}
2261
c24e9a53 2262DEFUN ("set-default-file-modes", Fset_default_file_modes, Sset_default_file_modes, 1, 1, 0,
5f85ea58
RS
2263 "Set the file permission bits for newly created files.\n\
2264The argument MODE should be an integer; only the low 9 bits are used.\n\
36a8c287 2265This setting is inherited by subprocesses.")
5f85ea58
RS
2266 (mode)
2267 Lisp_Object mode;
36a8c287 2268{
5f85ea58 2269 CHECK_NUMBER (mode, 0);
36a8c287 2270
5f85ea58 2271 umask ((~ XINT (mode)) & 0777);
36a8c287
JB
2272
2273 return Qnil;
2274}
2275
c24e9a53 2276DEFUN ("default-file-modes", Fdefault_file_modes, Sdefault_file_modes, 0, 0, 0,
5f85ea58
RS
2277 "Return the default file protection for created files.\n\
2278The value is an integer.")
36a8c287
JB
2279 ()
2280{
5f85ea58
RS
2281 int realmask;
2282 Lisp_Object value;
36a8c287 2283
5f85ea58
RS
2284 realmask = umask (0);
2285 umask (realmask);
36a8c287 2286
5f85ea58
RS
2287 XSET (value, Lisp_Int, (~ realmask) & 0777);
2288 return value;
36a8c287
JB
2289}
2290
85ffea93
RS
2291#ifdef unix
2292
2293DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2294 "Tell Unix to finish all pending disk updates.")
2295 ()
2296{
2297 sync ();
2298 return Qnil;
2299}
2300
2301#endif /* unix */
2302
570d7624
JB
2303DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2304 "Return t if file FILE1 is newer than file FILE2.\n\
2305If FILE1 does not exist, the answer is nil;\n\
2306otherwise, if FILE2 does not exist, the answer is t.")
2307 (file1, file2)
2308 Lisp_Object file1, file2;
2309{
32f4334d 2310 Lisp_Object abspath1, abspath2;
570d7624
JB
2311 struct stat st;
2312 int mtime1;
32f4334d 2313 Lisp_Object handler;
09121adc 2314 struct gcpro gcpro1, gcpro2;
570d7624
JB
2315
2316 CHECK_STRING (file1, 0);
2317 CHECK_STRING (file2, 0);
2318
09121adc
RS
2319 abspath1 = Qnil;
2320 GCPRO2 (abspath1, file2);
32f4334d
RS
2321 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2322 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
09121adc 2323 UNGCPRO;
570d7624 2324
32f4334d
RS
2325 /* If the file name has special constructs in it,
2326 call the corresponding file handler. */
642ef245 2327 handler = Ffind_file_name_handler (abspath1);
51cf6d37
RS
2328 if (NILP (handler))
2329 handler = Ffind_file_name_handler (abspath2);
32f4334d
RS
2330 if (!NILP (handler))
2331 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2332
2333 if (stat (XSTRING (abspath1)->data, &st) < 0)
570d7624
JB
2334 return Qnil;
2335
2336 mtime1 = st.st_mtime;
2337
32f4334d 2338 if (stat (XSTRING (abspath2)->data, &st) < 0)
570d7624
JB
2339 return Qt;
2340
2341 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2342}
2343\f
570d7624 2344DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
7fded690 2345 1, 4, 0,
570d7624 2346 "Insert contents of file FILENAME after point.\n\
7fded690 2347Returns list of absolute file name and length of data inserted.\n\
570d7624
JB
2348If second argument VISIT is non-nil, the buffer's visited filename\n\
2349and last save file modtime are set, and it is marked unmodified.\n\
2350If visiting and the file does not exist, visiting is completed\n\
7fded690
JB
2351before the error is signaled.\n\n\
2352The optional third and fourth arguments BEG and END\n\
2353specify what portion of the file to insert.\n\
2354If VISIT is non-nil, BEG and END must be nil.")
2355 (filename, visit, beg, end)
2356 Lisp_Object filename, visit, beg, end;
570d7624
JB
2357{
2358 struct stat st;
2359 register int fd;
2360 register int inserted = 0;
2361 register int how_much;
2362 int count = specpdl_ptr - specpdl;
2363 struct gcpro gcpro1;
32f4334d 2364 Lisp_Object handler, val;
7fded690 2365 int total;
32f4334d
RS
2366
2367 val = Qnil;
2368
570d7624 2369 GCPRO1 (filename);
265a9e55 2370 if (!NILP (current_buffer->read_only))
570d7624
JB
2371 Fbarf_if_buffer_read_only();
2372
2373 CHECK_STRING (filename, 0);
2374 filename = Fexpand_file_name (filename, Qnil);
2375
32f4334d
RS
2376 /* If the file name has special constructs in it,
2377 call the corresponding file handler. */
642ef245 2378 handler = Ffind_file_name_handler (filename);
32f4334d
RS
2379 if (!NILP (handler))
2380 {
7fded690 2381 val = call5 (handler, Qinsert_file_contents, filename, visit, beg, end);
32f4334d
RS
2382 st.st_mtime = 0;
2383 goto handled;
2384 }
2385
570d7624
JB
2386 fd = -1;
2387
2388#ifndef APOLLO
2389 if (stat (XSTRING (filename)->data, &st) < 0
349a7710 2390 || (fd = open (XSTRING (filename)->data, 0)) < 0)
570d7624
JB
2391#else
2392 if ((fd = open (XSTRING (filename)->data, 0)) < 0
2393 || fstat (fd, &st) < 0)
2394#endif /* not APOLLO */
2395 {
2396 if (fd >= 0) close (fd);
265a9e55 2397 if (NILP (visit))
570d7624
JB
2398 report_file_error ("Opening input file", Fcons (filename, Qnil));
2399 st.st_mtime = -1;
2400 how_much = 0;
2401 goto notfound;
2402 }
2403
2404 record_unwind_protect (close_file_unwind, make_number (fd));
2405
be53b411
JB
2406#ifdef S_IFSOCK
2407 /* This code will need to be changed in order to work on named
2408 pipes, and it's probably just not worth it. So we should at
2409 least signal an error. */
2410 if ((st.st_mode & S_IFMT) == S_IFSOCK)
2411 Fsignal (Qfile_error,
2412 Fcons (build_string ("reading from named pipe"),
2413 Fcons (filename, Qnil)));
2414#endif
2415
570d7624
JB
2416 /* Supposedly happens on VMS. */
2417 if (st.st_size < 0)
2418 error ("File size is negative");
be53b411 2419
7fded690
JB
2420 if (!NILP (beg) || !NILP (end))
2421 if (!NILP (visit))
2422 error ("Attempt to visit less than an entire file");
2423
2424 if (!NILP (beg))
2425 CHECK_NUMBER (beg, 0);
2426 else
2427 XFASTINT (beg) = 0;
2428
2429 if (!NILP (end))
2430 CHECK_NUMBER (end, 0);
2431 else
2432 {
2433 XSETINT (end, st.st_size);
2434 if (XINT (end) != st.st_size)
2435 error ("maximum buffer size exceeded");
2436 }
2437
2438 total = XINT (end) - XINT (beg);
2439
570d7624
JB
2440 {
2441 register Lisp_Object temp;
2442
2443 /* Make sure point-max won't overflow after this insertion. */
7fded690
JB
2444 XSET (temp, Lisp_Int, total);
2445 if (total != XINT (temp))
570d7624
JB
2446 error ("maximum buffer size exceeded");
2447 }
2448
265a9e55 2449 if (NILP (visit))
570d7624
JB
2450 prepare_to_modify_buffer (point, point);
2451
2452 move_gap (point);
7fded690
JB
2453 if (GAP_SIZE < total)
2454 make_gap (total - GAP_SIZE);
2455
2456 if (XINT (beg) != 0)
2457 {
2458 if (lseek (fd, XINT (beg), 0) < 0)
2459 report_file_error ("Setting file position", Fcons (filename, Qnil));
2460 }
2461
570d7624
JB
2462 while (1)
2463 {
7fded690 2464 int try = min (total - inserted, 64 << 10);
b5148e85
RS
2465 int this;
2466
2467 /* Allow quitting out of the actual I/O. */
2468 immediate_quit = 1;
2469 QUIT;
2470 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2471 immediate_quit = 0;
570d7624
JB
2472
2473 if (this <= 0)
2474 {
2475 how_much = this;
2476 break;
2477 }
2478
2479 GPT += this;
2480 GAP_SIZE -= this;
2481 ZV += this;
2482 Z += this;
2483 inserted += this;
2484 }
2485
2486 if (inserted > 0)
7d8451f1
RS
2487 {
2488 record_insert (point, inserted);
8d4e077b
JA
2489
2490 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2491 offset_intervals (current_buffer, point, inserted);
7d8451f1
RS
2492 MODIFF++;
2493 }
570d7624
JB
2494
2495 close (fd);
2496
2497 /* Discard the unwind protect */
2498 specpdl_ptr = specpdl + count;
2499
2500 if (how_much < 0)
2501 error ("IO error reading %s: %s",
2502 XSTRING (filename)->data, err_str (errno));
2503
2504 notfound:
32f4334d 2505 handled:
570d7624 2506
265a9e55 2507 if (!NILP (visit))
570d7624
JB
2508 {
2509 current_buffer->undo_list = Qnil;
2510#ifdef APOLLO
2511 stat (XSTRING (filename)->data, &st);
2512#endif
2513 current_buffer->modtime = st.st_mtime;
2514 current_buffer->save_modified = MODIFF;
2515 current_buffer->auto_save_modified = MODIFF;
2516 XFASTINT (current_buffer->save_length) = Z - BEG;
2517#ifdef CLASH_DETECTION
32f4334d
RS
2518 if (NILP (handler))
2519 {
2520 if (!NILP (current_buffer->filename))
2521 unlock_file (current_buffer->filename);
2522 unlock_file (filename);
2523 }
570d7624
JB
2524#endif /* CLASH_DETECTION */
2525 current_buffer->filename = filename;
2526 /* If visiting nonexistent file, return nil. */
32f4334d 2527 if (current_buffer->modtime == -1)
570d7624
JB
2528 report_file_error ("Opening input file", Fcons (filename, Qnil));
2529 }
2530
2531 signal_after_change (point, 0, inserted);
2532
32f4334d
RS
2533 if (!NILP (val))
2534 RETURN_UNGCPRO (val);
9b7828a5
JB
2535 RETURN_UNGCPRO (Fcons (filename,
2536 Fcons (make_number (inserted),
2537 Qnil)));
570d7624 2538}
7fded690 2539\f
570d7624
JB
2540DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2541 "r\nFWrite region to file: ",
2542 "Write current region into specified file.\n\
2543When called from a program, takes three arguments:\n\
2544START, END and FILENAME. START and END are buffer positions.\n\
2545Optional fourth argument APPEND if non-nil means\n\
2546 append to existing file contents (if any).\n\
2547Optional fifth argument VISIT if t means\n\
2548 set the last-save-file-modtime of buffer to this file's modtime\n\
2549 and mark buffer not modified.\n\
3b7792ed
RS
2550If VISIT is a string, it is a second file name;\n\
2551 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
2552 VISIT is also the file name to lock and unlock for clash detection.\n\
1d386d28
RS
2553If VISIT is neither t nor nil nor a string,\n\
2554 that means do not print the \"Wrote file\" message.\n\
570d7624
JB
2555Kludgy feature: if START is a string, then that string is written\n\
2556to the file, instead of any buffer contents, and END is ignored.")
2557 (start, end, filename, append, visit)
2558 Lisp_Object start, end, filename, append, visit;
2559{
2560 register int desc;
2561 int failure;
2562 int save_errno;
2563 unsigned char *fn;
2564 struct stat st;
2565 int tem;
2566 int count = specpdl_ptr - specpdl;
2567#ifdef VMS
2568 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
2569#endif /* VMS */
3eac9910 2570 Lisp_Object handler;
4ad827c5 2571 Lisp_Object visit_file;
3b7792ed 2572 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
570d7624
JB
2573
2574 /* Special kludge to simplify auto-saving */
265a9e55 2575 if (NILP (start))
570d7624
JB
2576 {
2577 XFASTINT (start) = BEG;
2578 XFASTINT (end) = Z;
2579 }
2580 else if (XTYPE (start) != Lisp_String)
2581 validate_region (&start, &end);
2582
2583 filename = Fexpand_file_name (filename, Qnil);
4ad827c5 2584 if (XTYPE (visit) == Lisp_String)
e5176bae 2585 visit_file = Fexpand_file_name (visit, Qnil);
4ad827c5
RS
2586 else
2587 visit_file = filename;
2588
2589 GCPRO4 (start, filename, visit, visit_file);
570d7624 2590
32f4334d
RS
2591 /* If the file name has special constructs in it,
2592 call the corresponding file handler. */
642ef245 2593 handler = Ffind_file_name_handler (filename);
3eac9910 2594
32f4334d
RS
2595 if (!NILP (handler))
2596 {
32f4334d 2597 Lisp_Object val;
51cf6d37
RS
2598 val = call6 (handler, Qwrite_region, start, end,
2599 filename, append, visit);
32f4334d
RS
2600
2601 /* Do this before reporting IO error
2602 to avoid a "file has changed on disk" warning on
2603 next attempt to save. */
3b7792ed 2604 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
32f4334d
RS
2605 {
2606 current_buffer->modtime = 0;
2607 current_buffer->save_modified = MODIFF;
2608 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 2609 current_buffer->filename = visit_file;
32f4334d 2610 }
09121adc 2611 UNGCPRO;
32f4334d
RS
2612 return val;
2613 }
2614
570d7624
JB
2615#ifdef CLASH_DETECTION
2616 if (!auto_saving)
3b7792ed 2617 lock_file (visit_file);
570d7624
JB
2618#endif /* CLASH_DETECTION */
2619
09121adc 2620 fn = XSTRING (filename)->data;
570d7624 2621 desc = -1;
265a9e55 2622 if (!NILP (append))
570d7624
JB
2623 desc = open (fn, O_WRONLY);
2624
2625 if (desc < 0)
2626#ifdef VMS
2627 if (auto_saving) /* Overwrite any previous version of autosave file */
2628 {
2629 vms_truncate (fn); /* if fn exists, truncate to zero length */
2630 desc = open (fn, O_RDWR);
2631 if (desc < 0)
2632 desc = creat_copy_attrs (XTYPE (current_buffer->filename) == Lisp_String
b72dea2a
JB
2633 ? XSTRING (current_buffer->filename)->data : 0,
2634 fn);
570d7624
JB
2635 }
2636 else /* Write to temporary name and rename if no errors */
2637 {
2638 Lisp_Object temp_name;
2639 temp_name = Ffile_name_directory (filename);
2640
265a9e55 2641 if (!NILP (temp_name))
570d7624
JB
2642 {
2643 temp_name = Fmake_temp_name (concat2 (temp_name,
2644 build_string ("$$SAVE$$")));
2645 fname = XSTRING (filename)->data;
2646 fn = XSTRING (temp_name)->data;
2647 desc = creat_copy_attrs (fname, fn);
2648 if (desc < 0)
2649 {
2650 /* If we can't open the temporary file, try creating a new
2651 version of the original file. VMS "creat" creates a
2652 new version rather than truncating an existing file. */
2653 fn = fname;
2654 fname = 0;
2655 desc = creat (fn, 0666);
2656#if 0 /* This can clobber an existing file and fail to replace it,
2657 if the user runs out of space. */
2658 if (desc < 0)
2659 {
2660 /* We can't make a new version;
2661 try to truncate and rewrite existing version if any. */
2662 vms_truncate (fn);
2663 desc = open (fn, O_RDWR);
2664 }
2665#endif
2666 }
2667 }
2668 else
2669 desc = creat (fn, 0666);
2670 }
2671#else /* not VMS */
2672 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
2673#endif /* not VMS */
2674
09121adc
RS
2675 UNGCPRO;
2676
570d7624
JB
2677 if (desc < 0)
2678 {
2679#ifdef CLASH_DETECTION
2680 save_errno = errno;
3b7792ed 2681 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
2682 errno = save_errno;
2683#endif /* CLASH_DETECTION */
2684 report_file_error ("Opening output file", Fcons (filename, Qnil));
2685 }
2686
2687 record_unwind_protect (close_file_unwind, make_number (desc));
2688
265a9e55 2689 if (!NILP (append))
570d7624
JB
2690 if (lseek (desc, 0, 2) < 0)
2691 {
2692#ifdef CLASH_DETECTION
3b7792ed 2693 if (!auto_saving) unlock_file (visit_file);
570d7624
JB
2694#endif /* CLASH_DETECTION */
2695 report_file_error ("Lseek error", Fcons (filename, Qnil));
2696 }
2697
2698#ifdef VMS
2699/*
2700 * Kludge Warning: The VMS C RTL likes to insert carriage returns
2701 * if we do writes that don't end with a carriage return. Furthermore
2702 * it cannot handle writes of more then 16K. The modified
2703 * version of "sys_write" in SYSDEP.C (see comment there) copes with
2704 * this EXCEPT for the last record (iff it doesn't end with a carriage
2705 * return). This implies that if your buffer doesn't end with a carriage
2706 * return, you get one free... tough. However it also means that if
2707 * we make two calls to sys_write (a la the following code) you can
2708 * get one at the gap as well. The easiest way to fix this (honest)
2709 * is to move the gap to the next newline (or the end of the buffer).
2710 * Thus this change.
2711 *
2712 * Yech!
2713 */
2714 if (GPT > BEG && GPT_ADDR[-1] != '\n')
2715 move_gap (find_next_newline (GPT, 1));
2716#endif
2717
2718 failure = 0;
2719 immediate_quit = 1;
2720
2721 if (XTYPE (start) == Lisp_String)
2722 {
2723 failure = 0 > e_write (desc, XSTRING (start)->data,
2724 XSTRING (start)->size);
2725 save_errno = errno;
2726 }
2727 else if (XINT (start) != XINT (end))
2728 {
2729 if (XINT (start) < GPT)
2730 {
2731 register int end1 = XINT (end);
2732 tem = XINT (start);
2733 failure = 0 > e_write (desc, &FETCH_CHAR (tem),
2734 min (GPT, end1) - tem);
2735 save_errno = errno;
2736 }
2737
2738 if (XINT (end) > GPT && !failure)
2739 {
2740 tem = XINT (start);
2741 tem = max (tem, GPT);
2742 failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem);
2743 save_errno = errno;
2744 }
2745 }
2746
2747 immediate_quit = 0;
2748
6e23c83e 2749#ifdef HAVE_FSYNC
570d7624
JB
2750 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
2751 Disk full in NFS may be reported here. */
1daffa1c
RS
2752 /* mib says that closing the file will try to write as fast as NFS can do
2753 it, and that means the fsync here is not crucial for autosave files. */
2754 if (!auto_saving && fsync (desc) < 0)
570d7624 2755 failure = 1, save_errno = errno;
570d7624
JB
2756#endif
2757
2758 /* Spurious "file has changed on disk" warnings have been
2759 observed on Suns as well.
2760 It seems that `close' can change the modtime, under nfs.
2761
2762 (This has supposedly been fixed in Sunos 4,
2763 but who knows about all the other machines with NFS?) */
2764#if 0
2765
2766 /* On VMS and APOLLO, must do the stat after the close
2767 since closing changes the modtime. */
2768#ifndef VMS
2769#ifndef APOLLO
2770 /* Recall that #if defined does not work on VMS. */
2771#define FOO
2772 fstat (desc, &st);
2773#endif
2774#endif
2775#endif
2776
2777 /* NFS can report a write failure now. */
2778 if (close (desc) < 0)
2779 failure = 1, save_errno = errno;
2780
2781#ifdef VMS
2782 /* If we wrote to a temporary name and had no errors, rename to real name. */
2783 if (fname)
2784 {
2785 if (!failure)
2786 failure = (rename (fn, fname) != 0), save_errno = errno;
2787 fn = fname;
2788 }
2789#endif /* VMS */
2790
2791#ifndef FOO
2792 stat (fn, &st);
2793#endif
2794 /* Discard the unwind protect */
2795 specpdl_ptr = specpdl + count;
2796
2797#ifdef CLASH_DETECTION
2798 if (!auto_saving)
3b7792ed 2799 unlock_file (visit_file);
570d7624
JB
2800#endif /* CLASH_DETECTION */
2801
2802 /* Do this before reporting IO error
2803 to avoid a "file has changed on disk" warning on
2804 next attempt to save. */
3b7792ed 2805 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
570d7624
JB
2806 current_buffer->modtime = st.st_mtime;
2807
2808 if (failure)
2809 error ("IO error writing %s: %s", fn, err_str (save_errno));
2810
3b7792ed 2811 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
570d7624
JB
2812 {
2813 current_buffer->save_modified = MODIFF;
2814 XFASTINT (current_buffer->save_length) = Z - BEG;
3b7792ed 2815 current_buffer->filename = visit_file;
570d7624 2816 }
265a9e55 2817 else if (!NILP (visit))
570d7624
JB
2818 return Qnil;
2819
2820 if (!auto_saving)
3b7792ed 2821 message ("Wrote %s", XSTRING (visit_file)->data);
570d7624
JB
2822
2823 return Qnil;
2824}
2825
2826int
2827e_write (desc, addr, len)
2828 int desc;
2829 register char *addr;
2830 register int len;
2831{
2832 char buf[16 * 1024];
2833 register char *p, *end;
2834
2835 if (!EQ (current_buffer->selective_display, Qt))
2836 return write (desc, addr, len) - len;
2837 else
2838 {
2839 p = buf;
2840 end = p + sizeof buf;
2841 while (len--)
2842 {
2843 if (p == end)
2844 {
2845 if (write (desc, buf, sizeof buf) != sizeof buf)
2846 return -1;
2847 p = buf;
2848 }
2849 *p = *addr++;
2850 if (*p++ == '\015')
2851 p[-1] = '\n';
2852 }
2853 if (p != buf)
2854 if (write (desc, buf, p - buf) != p - buf)
2855 return -1;
2856 }
2857 return 0;
2858}
2859
2860DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
2861 Sverify_visited_file_modtime, 1, 1, 0,
2862 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
2863This means that the file has not been changed since it was visited or saved.")
2864 (buf)
2865 Lisp_Object buf;
2866{
2867 struct buffer *b;
2868 struct stat st;
32f4334d 2869 Lisp_Object handler;
570d7624
JB
2870
2871 CHECK_BUFFER (buf, 0);
2872 b = XBUFFER (buf);
2873
2874 if (XTYPE (b->filename) != Lisp_String) return Qt;
2875 if (b->modtime == 0) return Qt;
2876
32f4334d
RS
2877 /* If the file name has special constructs in it,
2878 call the corresponding file handler. */
642ef245 2879 handler = Ffind_file_name_handler (b->filename);
32f4334d 2880 if (!NILP (handler))
09121adc 2881 return call2 (handler, Qverify_visited_file_modtime, buf);
32f4334d 2882
570d7624
JB
2883 if (stat (XSTRING (b->filename)->data, &st) < 0)
2884 {
2885 /* If the file doesn't exist now and didn't exist before,
2886 we say that it isn't modified, provided the error is a tame one. */
2887 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
2888 st.st_mtime = -1;
2889 else
2890 st.st_mtime = 0;
2891 }
2892 if (st.st_mtime == b->modtime
2893 /* If both are positive, accept them if they are off by one second. */
2894 || (st.st_mtime > 0 && b->modtime > 0
2895 && (st.st_mtime == b->modtime + 1
2896 || st.st_mtime == b->modtime - 1)))
2897 return Qt;
2898 return Qnil;
2899}
2900
2901DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
2902 Sclear_visited_file_modtime, 0, 0, 0,
2903 "Clear out records of last mod time of visited file.\n\
2904Next attempt to save will certainly not complain of a discrepancy.")
2905 ()
2906{
2907 current_buffer->modtime = 0;
2908 return Qnil;
2909}
2910
f5d5eccf
RS
2911DEFUN ("visited-file-modtime", Fvisited_file_modtime,
2912 Svisited_file_modtime, 0, 0, 0,
2913 "Return the current buffer's recorded visited file modification time.\n\
2914The value is a list of the form (HIGH . LOW), like the time values\n\
2915that `file-attributes' returns.")
2916 ()
2917{
2918 return long_to_cons (current_buffer->modtime);
2919}
2920
570d7624 2921DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
f5d5eccf 2922 Sset_visited_file_modtime, 0, 1, 0,
570d7624
JB
2923 "Update buffer's recorded modification time from the visited file's time.\n\
2924Useful if the buffer was not read from the file normally\n\
f5d5eccf
RS
2925or if the file itself has been changed for some known benign reason.\n\
2926An argument specifies the modification time value to use\n\
2927\(instead of that of the visited file), in the form of a list\n\
2928\(HIGH . LOW) or (HIGH LOW).")
2929 (time_list)
2930 Lisp_Object time_list;
570d7624 2931{
f5d5eccf
RS
2932 if (!NILP (time_list))
2933 current_buffer->modtime = cons_to_long (time_list);
2934 else
2935 {
2936 register Lisp_Object filename;
2937 struct stat st;
2938 Lisp_Object handler;
570d7624 2939
f5d5eccf 2940 filename = Fexpand_file_name (current_buffer->filename, Qnil);
32f4334d 2941
f5d5eccf
RS
2942 /* If the file name has special constructs in it,
2943 call the corresponding file handler. */
2944 handler = Ffind_file_name_handler (filename);
2945 if (!NILP (handler))
caf3c431 2946 /* The handler can find the file name the same way we did. */
76c881b0 2947 return call2 (handler, Qset_visited_file_modtime, Qnil);
f5d5eccf
RS
2948 else if (stat (XSTRING (filename)->data, &st) >= 0)
2949 current_buffer->modtime = st.st_mtime;
2950 }
570d7624
JB
2951
2952 return Qnil;
2953}
2954\f
2955Lisp_Object
2956auto_save_error ()
2957{
2958 unsigned char *name = XSTRING (current_buffer->name)->data;
2959
2960 ring_bell ();
2961 message ("Autosaving...error for %s", name);
de49a6d3 2962 Fsleep_for (make_number (1), Qnil);
570d7624 2963 message ("Autosaving...error!for %s", name);
de49a6d3 2964 Fsleep_for (make_number (1), Qnil);
570d7624 2965 message ("Autosaving...error for %s", name);
de49a6d3 2966 Fsleep_for (make_number (1), Qnil);
570d7624
JB
2967 return Qnil;
2968}
2969
2970Lisp_Object
2971auto_save_1 ()
2972{
2973 unsigned char *fn;
2974 struct stat st;
2975
2976 /* Get visited file's mode to become the auto save file's mode. */
2977 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
2978 /* But make sure we can overwrite it later! */
2979 auto_save_mode_bits = st.st_mode | 0600;
2980 else
2981 auto_save_mode_bits = 0666;
2982
2983 return
2984 Fwrite_region (Qnil, Qnil,
2985 current_buffer->auto_save_file_name,
2986 Qnil, Qlambda);
2987}
2988
2989DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
2990 "Auto-save all buffers that need it.\n\
2991This is all buffers that have auto-saving enabled\n\
2992and are changed since last auto-saved.\n\
2993Auto-saving writes the buffer into a file\n\
2994so that your editing is not lost if the system crashes.\n\
2995This file is not the file you visited; that changes only when you save.\n\n\
2996Non-nil first argument means do not print any message if successful.\n\
4746118a 2997Non-nil second argument means save only current buffer.")
17857782
JB
2998 (no_message, current_only)
2999 Lisp_Object no_message, current_only;
570d7624
JB
3000{
3001 struct buffer *old = current_buffer, *b;
3002 Lisp_Object tail, buf;
3003 int auto_saved = 0;
3004 char *omessage = echo_area_glyphs;
f14b1c68
JB
3005 extern int minibuf_level;
3006 int do_handled_files;
ff4c9993
RS
3007 Lisp_Object oquit;
3008
3009 /* Ordinarily don't quit within this function,
3010 but don't make it impossible to quit (in case we get hung in I/O). */
3011 oquit = Vquit_flag;
3012 Vquit_flag = Qnil;
570d7624
JB
3013
3014 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
3015 point to non-strings reached from Vbuffer_alist. */
3016
3017 auto_saving = 1;
3018 if (minibuf_level)
17857782 3019 no_message = Qt;
570d7624
JB
3020
3021 /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
3022 eventually call do-auto-save, so don't err here in that case. */
265a9e55 3023 if (!NILP (Vrun_hooks))
570d7624
JB
3024 call1 (Vrun_hooks, intern ("auto-save-hook"));
3025
f14b1c68
JB
3026 /* First, save all files which don't have handlers. If Emacs is
3027 crashing, the handlers may tweak what is causing Emacs to crash
3028 in the first place, and it would be a shame if Emacs failed to
3029 autosave perfectly ordinary files because it couldn't handle some
3030 ange-ftp'd file. */
3031 for (do_handled_files = 0; do_handled_files < 2; do_handled_files++)
3032 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
3033 tail = XCONS (tail)->cdr)
3034 {
3035 buf = XCONS (XCONS (tail)->car)->cdr;
3036 b = XBUFFER (buf);
17857782 3037
f14b1c68
JB
3038 if (!NILP (current_only)
3039 && b != current_buffer)
3040 continue;
17857782 3041
f14b1c68
JB
3042 /* Check for auto save enabled
3043 and file changed since last auto save
3044 and file changed since last real save. */
3045 if (XTYPE (b->auto_save_file_name) == Lisp_String
3046 && b->save_modified < BUF_MODIFF (b)
3047 && b->auto_save_modified < BUF_MODIFF (b)
3048 && (do_handled_files
3049 || NILP (Ffind_file_name_handler (b->auto_save_file_name))))
3050 {
3051 if ((XFASTINT (b->save_length) * 10
3052 > (BUF_Z (b) - BUF_BEG (b)) * 13)
3053 /* A short file is likely to change a large fraction;
3054 spare the user annoying messages. */
3055 && XFASTINT (b->save_length) > 5000
3056 /* These messages are frequent and annoying for `*mail*'. */
3057 && !EQ (b->filename, Qnil)
3058 && NILP (no_message))
3059 {
3060 /* It has shrunk too much; turn off auto-saving here. */
3061 message ("Buffer %s has shrunk a lot; auto save turned off there",
3062 XSTRING (b->name)->data);
3063 /* User can reenable saving with M-x auto-save. */
3064 b->auto_save_file_name = Qnil;
3065 /* Prevent warning from repeating if user does so. */
3066 XFASTINT (b->save_length) = 0;
3067 Fsleep_for (make_number (1), Qnil);
3068 continue;
3069 }
3070 set_buffer_internal (b);
3071 if (!auto_saved && NILP (no_message))
3072 message1 ("Auto-saving...");
3073 internal_condition_case (auto_save_1, Qt, auto_save_error);
3074 auto_saved++;
3075 b->auto_save_modified = BUF_MODIFF (b);
3076 XFASTINT (current_buffer->save_length) = Z - BEG;
3077 set_buffer_internal (old);
3078 }
3079 }
570d7624 3080
b67f2ca5
RS
3081 /* Prevent another auto save till enough input events come in. */
3082 record_auto_save ();
570d7624 3083
17857782 3084 if (auto_saved && NILP (no_message))
570d7624
JB
3085 message1 (omessage ? omessage : "Auto-saving...done");
3086
ff4c9993
RS
3087 Vquit_flag = oquit;
3088
570d7624
JB
3089 auto_saving = 0;
3090 return Qnil;
3091}
3092
3093DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
3094 Sset_buffer_auto_saved, 0, 0, 0,
3095 "Mark current buffer as auto-saved with its current text.\n\
3096No auto-save file will be written until the buffer changes again.")
3097 ()
3098{
3099 current_buffer->auto_save_modified = MODIFF;
3100 XFASTINT (current_buffer->save_length) = Z - BEG;
3101 return Qnil;
3102}
3103
3104DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
3105 0, 0, 0,
3106 "Return t if buffer has been auto-saved since last read in or saved.")
3107 ()
3108{
3109 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
3110}
3111\f
3112/* Reading and completing file names */
3113extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
3114
3115DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
3116 3, 3, 0,
3117 "Internal subroutine for read-file-name. Do not call this.")
3118 (string, dir, action)
3119 Lisp_Object string, dir, action;
3120 /* action is nil for complete, t for return list of completions,
3121 lambda for verify final value */
3122{
3123 Lisp_Object name, specdir, realdir, val, orig_string;
09121adc
RS
3124 int changed;
3125 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3126
3127 realdir = dir;
3128 name = string;
3129 orig_string = Qnil;
3130 specdir = Qnil;
3131 changed = 0;
3132 /* No need to protect ACTION--we only compare it with t and nil. */
3133 GCPRO4 (string, realdir, name, specdir);
570d7624
JB
3134
3135 if (XSTRING (string)->size == 0)
3136 {
570d7624 3137 if (EQ (action, Qlambda))
09121adc
RS
3138 {
3139 UNGCPRO;
3140 return Qnil;
3141 }
570d7624
JB
3142 }
3143 else
3144 {
3145 orig_string = string;
3146 string = Fsubstitute_in_file_name (string);
09121adc 3147 changed = NILP (Fstring_equal (string, orig_string));
570d7624 3148 name = Ffile_name_nondirectory (string);
09121adc
RS
3149 val = Ffile_name_directory (string);
3150 if (! NILP (val))
3151 realdir = Fexpand_file_name (val, realdir);
570d7624
JB
3152 }
3153
265a9e55 3154 if (NILP (action))
570d7624
JB
3155 {
3156 specdir = Ffile_name_directory (string);
3157 val = Ffile_name_completion (name, realdir);
09121adc 3158 UNGCPRO;
570d7624
JB
3159 if (XTYPE (val) != Lisp_String)
3160 {
09121adc 3161 if (changed)
570d7624 3162 return string;
09121adc 3163 return val;
570d7624
JB
3164 }
3165
265a9e55 3166 if (!NILP (specdir))
570d7624
JB
3167 val = concat2 (specdir, val);
3168#ifndef VMS
3169 {
3170 register unsigned char *old, *new;
3171 register int n;
3172 int osize, count;
3173
3174 osize = XSTRING (val)->size;
3175 /* Quote "$" as "$$" to get it past substitute-in-file-name */
3176 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
3177 if (*old++ == '$') count++;
3178 if (count > 0)
3179 {
3180 old = XSTRING (val)->data;
3181 val = Fmake_string (make_number (osize + count), make_number (0));
3182 new = XSTRING (val)->data;
3183 for (n = osize; n > 0; n--)
3184 if (*old != '$')
3185 *new++ = *old++;
3186 else
3187 {
3188 *new++ = '$';
3189 *new++ = '$';
3190 old++;
3191 }
3192 }
3193 }
3194#endif /* Not VMS */
09121adc 3195 return val;
570d7624 3196 }
09121adc 3197 UNGCPRO;
570d7624
JB
3198
3199 if (EQ (action, Qt))
3200 return Ffile_name_all_completions (name, realdir);
3201 /* Only other case actually used is ACTION = lambda */
3202#ifdef VMS
3203 /* Supposedly this helps commands such as `cd' that read directory names,
3204 but can someone explain how it helps them? -- RMS */
3205 if (XSTRING (name)->size == 0)
3206 return Qt;
3207#endif /* VMS */
3208 return Ffile_exists_p (string);
3209}
3210
3211DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3212 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3213Value is not expanded---you must call `expand-file-name' yourself.\n\
3214Default name to DEFAULT if user enters a null string.\n\
3215 (If DEFAULT is omitted, the visited file name is used.)\n\
3216Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3217 Non-nil and non-t means also require confirmation after completion.\n\
3218Fifth arg INITIAL specifies text to start with.\n\
3219DIR defaults to current buffer's directory default.")
3220 (prompt, dir, defalt, mustmatch, initial)
3221 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3222{
85b5fe07 3223 Lisp_Object val, insdef, insdef1, tem;
570d7624
JB
3224 struct gcpro gcpro1, gcpro2;
3225 register char *homedir;
3226 int count;
3227
265a9e55 3228 if (NILP (dir))
570d7624 3229 dir = current_buffer->directory;
265a9e55 3230 if (NILP (defalt))
570d7624
JB
3231 defalt = current_buffer->filename;
3232
3233 /* If dir starts with user's homedir, change that to ~. */
3234 homedir = (char *) egetenv ("HOME");
3235 if (homedir != 0
3236 && XTYPE (dir) == Lisp_String
3237 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3238 && XSTRING (dir)->data[strlen (homedir)] == '/')
3239 {
3240 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3241 XSTRING (dir)->size - strlen (homedir) + 1);
3242 XSTRING (dir)->data[0] = '~';
3243 }
3244
3245 if (insert_default_directory)
3246 {
3247 insdef = dir;
85b5fe07 3248 insdef1 = dir;
265a9e55 3249 if (!NILP (initial))
570d7624 3250 {
15c65264 3251 Lisp_Object args[2], pos;
570d7624
JB
3252
3253 args[0] = insdef;
3254 args[1] = initial;
3255 insdef = Fconcat (2, args);
509b05ed 3256 pos = make_number (XSTRING (dir)->size);
85b5fe07 3257 insdef1 = Fcons (insdef, pos);
570d7624 3258 }
570d7624
JB
3259 }
3260 else
85b5fe07 3261 insdef = Qnil, insdef1 = Qnil;
570d7624
JB
3262
3263#ifdef VMS
3264 count = specpdl_ptr - specpdl;
3265 specbind (intern ("completion-ignore-case"), Qt);
3266#endif
3267
3268 GCPRO2 (insdef, defalt);
3269 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
85b5fe07 3270 dir, mustmatch, insdef1,
15c65264 3271 Qfile_name_history);
570d7624
JB
3272
3273#ifdef VMS
3274 unbind_to (count, Qnil);
3275#endif
3276
3277 UNGCPRO;
265a9e55 3278 if (NILP (val))
570d7624
JB
3279 error ("No file name specified");
3280 tem = Fstring_equal (val, insdef);
265a9e55 3281 if (!NILP (tem) && !NILP (defalt))
570d7624 3282 return defalt;
b320926a
RS
3283 if (XSTRING (val)->size == 0 && NILP (insdef))
3284 return defalt;
570d7624
JB
3285 return Fsubstitute_in_file_name (val);
3286}
3287
3288#if 0 /* Old version */
3289DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3290 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3291Value is not expanded---you must call `expand-file-name' yourself.\n\
3292Default name to DEFAULT if user enters a null string.\n\
3293 (If DEFAULT is omitted, the visited file name is used.)\n\
3294Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3295 Non-nil and non-t means also require confirmation after completion.\n\
3296Fifth arg INITIAL specifies text to start with.\n\
3297DIR defaults to current buffer's directory default.")
3298 (prompt, dir, defalt, mustmatch, initial)
3299 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3300{
3301 Lisp_Object val, insdef, tem;
3302 struct gcpro gcpro1, gcpro2;
3303 register char *homedir;
3304 int count;
3305
265a9e55 3306 if (NILP (dir))
570d7624 3307 dir = current_buffer->directory;
265a9e55 3308 if (NILP (defalt))
570d7624
JB
3309 defalt = current_buffer->filename;
3310
3311 /* If dir starts with user's homedir, change that to ~. */
3312 homedir = (char *) egetenv ("HOME");
3313 if (homedir != 0
3314 && XTYPE (dir) == Lisp_String
3315 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3316 && XSTRING (dir)->data[strlen (homedir)] == '/')
3317 {
3318 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3319 XSTRING (dir)->size - strlen (homedir) + 1);
3320 XSTRING (dir)->data[0] = '~';
3321 }
3322
265a9e55 3323 if (!NILP (initial))
570d7624
JB
3324 insdef = initial;
3325 else if (insert_default_directory)
3326 insdef = dir;
3327 else
3328 insdef = build_string ("");
3329
3330#ifdef VMS
3331 count = specpdl_ptr - specpdl;
3332 specbind (intern ("completion-ignore-case"), Qt);
3333#endif
3334
3335 GCPRO2 (insdef, defalt);
3336 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3337 dir, mustmatch,
15c65264
RS
3338 insert_default_directory ? insdef : Qnil,
3339 Qfile_name_history);
570d7624
JB
3340
3341#ifdef VMS
3342 unbind_to (count, Qnil);
3343#endif
3344
3345 UNGCPRO;
265a9e55 3346 if (NILP (val))
570d7624
JB
3347 error ("No file name specified");
3348 tem = Fstring_equal (val, insdef);
265a9e55 3349 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
3350 return defalt;
3351 return Fsubstitute_in_file_name (val);
3352}
3353#endif /* Old version */
3354\f
3355syms_of_fileio ()
3356{
0bf2eed2
RS
3357 Qexpand_file_name = intern ("expand-file-name");
3358 Qdirectory_file_name = intern ("directory-file-name");
3359 Qfile_name_directory = intern ("file-name-directory");
3360 Qfile_name_nondirectory = intern ("file-name-nondirectory");
642ef245 3361 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
0bf2eed2 3362 Qfile_name_as_directory = intern ("file-name-as-directory");
32f4334d
RS
3363 Qcopy_file = intern ("copy-file");
3364 Qmake_directory = intern ("make-directory");
3365 Qdelete_directory = intern ("delete-directory");
3366 Qdelete_file = intern ("delete-file");
3367 Qrename_file = intern ("rename-file");
3368 Qadd_name_to_file = intern ("add-name-to-file");
3369 Qmake_symbolic_link = intern ("make-symbolic-link");
3370 Qfile_exists_p = intern ("file-exists-p");
3371 Qfile_executable_p = intern ("file-executable-p");
3372 Qfile_readable_p = intern ("file-readable-p");
3373 Qfile_symlink_p = intern ("file-symlink-p");
3374 Qfile_writable_p = intern ("file-writable-p");
3375 Qfile_directory_p = intern ("file-directory-p");
3376 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
3377 Qfile_modes = intern ("file-modes");
3378 Qset_file_modes = intern ("set-file-modes");
3379 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
3380 Qinsert_file_contents = intern ("insert-file-contents");
3381 Qwrite_region = intern ("write-region");
3382 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3ec46acd 3383 Qset_visited_file_modtime = intern ("set-visited-file-modtime");
32f4334d 3384
642ef245
JB
3385 staticpro (&Qexpand_file_name);
3386 staticpro (&Qdirectory_file_name);
3387 staticpro (&Qfile_name_directory);
3388 staticpro (&Qfile_name_nondirectory);
3389 staticpro (&Qunhandled_file_name_directory);
3390 staticpro (&Qfile_name_as_directory);
15c65264
RS
3391 staticpro (&Qcopy_file);
3392 staticpro (&Qmake_directory);
3393 staticpro (&Qdelete_directory);
3394 staticpro (&Qdelete_file);
3395 staticpro (&Qrename_file);
3396 staticpro (&Qadd_name_to_file);
3397 staticpro (&Qmake_symbolic_link);
3398 staticpro (&Qfile_exists_p);
3399 staticpro (&Qfile_executable_p);
3400 staticpro (&Qfile_readable_p);
3401 staticpro (&Qfile_symlink_p);
3402 staticpro (&Qfile_writable_p);
3403 staticpro (&Qfile_directory_p);
3404 staticpro (&Qfile_accessible_directory_p);
3405 staticpro (&Qfile_modes);
3406 staticpro (&Qset_file_modes);
3407 staticpro (&Qfile_newer_than_file_p);
3408 staticpro (&Qinsert_file_contents);
3409 staticpro (&Qwrite_region);
3410 staticpro (&Qverify_visited_file_modtime);
642ef245
JB
3411
3412 Qfile_name_history = intern ("file-name-history");
3413 Fset (Qfile_name_history, Qnil);
15c65264
RS
3414 staticpro (&Qfile_name_history);
3415
570d7624
JB
3416 Qfile_error = intern ("file-error");
3417 staticpro (&Qfile_error);
3418 Qfile_already_exists = intern("file-already-exists");
3419 staticpro (&Qfile_already_exists);
3420
3421 Fput (Qfile_error, Qerror_conditions,
3422 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
3423 Fput (Qfile_error, Qerror_message,
3424 build_string ("File error"));
3425
3426 Fput (Qfile_already_exists, Qerror_conditions,
3427 Fcons (Qfile_already_exists,
3428 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
3429 Fput (Qfile_already_exists, Qerror_message,
3430 build_string ("File already exists"));
3431
3432 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
3433 "*Non-nil means when reading a filename start with default dir in minibuffer.");
3434 insert_default_directory = 1;
3435
3436 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
3437 "*Non-nil means write new files with record format `stmlf'.\n\
3438nil means use format `var'. This variable is meaningful only on VMS.");
3439 vms_stmlf_recfm = 0;
3440
1d1826db
RS
3441 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
3442 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
3443If a file name matches REGEXP, then all I/O on that file is done by calling\n\
3444HANDLER.\n\
3445\n\
3446The first argument given to HANDLER is the name of the I/O primitive\n\
3447to be handled; the remaining arguments are the arguments that were\n\
3448passed to that primitive. For example, if you do\n\
3449 (file-exists-p FILENAME)\n\
3450and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
642ef245
JB
3451 (funcall HANDLER 'file-exists-p FILENAME)\n\
3452The function `find-file-name-handler' checks this list for a handler\n\
3453for its argument.");
09121adc
RS
3454 Vfile_name_handler_alist = Qnil;
3455
642ef245 3456 defsubr (&Sfind_file_name_handler);
570d7624
JB
3457 defsubr (&Sfile_name_directory);
3458 defsubr (&Sfile_name_nondirectory);
642ef245 3459 defsubr (&Sunhandled_file_name_directory);
570d7624
JB
3460 defsubr (&Sfile_name_as_directory);
3461 defsubr (&Sdirectory_file_name);
3462 defsubr (&Smake_temp_name);
3463 defsubr (&Sexpand_file_name);
3464 defsubr (&Ssubstitute_in_file_name);
3465 defsubr (&Scopy_file);
9bbe01fb 3466 defsubr (&Smake_directory_internal);
aa734e17 3467 defsubr (&Sdelete_directory);
570d7624
JB
3468 defsubr (&Sdelete_file);
3469 defsubr (&Srename_file);
3470 defsubr (&Sadd_name_to_file);
3471#ifdef S_IFLNK
3472 defsubr (&Smake_symbolic_link);
3473#endif /* S_IFLNK */
3474#ifdef VMS
3475 defsubr (&Sdefine_logical_name);
3476#endif /* VMS */
3477#ifdef HPUX_NET
3478 defsubr (&Ssysnetunam);
3479#endif /* HPUX_NET */
3480 defsubr (&Sfile_name_absolute_p);
3481 defsubr (&Sfile_exists_p);
3482 defsubr (&Sfile_executable_p);
3483 defsubr (&Sfile_readable_p);
3484 defsubr (&Sfile_writable_p);
3485 defsubr (&Sfile_symlink_p);
3486 defsubr (&Sfile_directory_p);
b72dea2a 3487 defsubr (&Sfile_accessible_directory_p);
570d7624
JB
3488 defsubr (&Sfile_modes);
3489 defsubr (&Sset_file_modes);
c24e9a53
RS
3490 defsubr (&Sset_default_file_modes);
3491 defsubr (&Sdefault_file_modes);
570d7624
JB
3492 defsubr (&Sfile_newer_than_file_p);
3493 defsubr (&Sinsert_file_contents);
3494 defsubr (&Swrite_region);
3495 defsubr (&Sverify_visited_file_modtime);
3496 defsubr (&Sclear_visited_file_modtime);
f5d5eccf 3497 defsubr (&Svisited_file_modtime);
570d7624
JB
3498 defsubr (&Sset_visited_file_modtime);
3499 defsubr (&Sdo_auto_save);
3500 defsubr (&Sset_buffer_auto_saved);
3501 defsubr (&Srecent_auto_save_p);
3502
3503 defsubr (&Sread_file_name_internal);
3504 defsubr (&Sread_file_name);
85ffea93 3505
483a2e10 3506#ifdef unix
85ffea93 3507 defsubr (&Sunix_sync);
483a2e10 3508#endif
570d7624 3509}