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