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