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