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