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