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