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