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