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