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