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