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