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