*** empty log message ***
[bpt/emacs.git] / src / fileio.c
CommitLineData
570d7624 1/* File IO for GNU Emacs.
4746118a 2 Copyright (C) 1985, 1986, 1987, 1988, 1992 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
ffd56f97 20#include "config.h"
570d7624
JB
21
22#include <sys/types.h>
23#include <sys/stat.h>
bfb61299
JB
24
25#ifdef VMS
de5bf5d3 26#include "vms-pwd.h"
bfb61299 27#else
570d7624 28#include <pwd.h>
bfb61299
JB
29#endif
30
570d7624 31#include <ctype.h>
bfb61299
JB
32
33#ifdef VMS
34#include "dir.h"
35#include <perror.h>
36#include <stddef.h>
37#include <string.h>
38#else
570d7624 39#include <sys/dir.h>
bfb61299
JB
40#endif
41
570d7624
JB
42#include <errno.h>
43
bfb61299 44#ifndef vax11c
570d7624
JB
45extern int errno;
46extern char *sys_errlist[];
47extern int sys_nerr;
48#endif
49
50#define err_str(a) ((a) < sys_nerr ? sys_errlist[a] : "unknown error")
51
52#ifdef APOLLO
53#include <sys/time.h>
54#endif
55
570d7624
JB
56#include "lisp.h"
57#include "buffer.h"
58#include "window.h"
59
60#ifdef VMS
570d7624
JB
61#include <file.h>
62#include <rmsdef.h>
63#include <fab.h>
64#include <nam.h>
65#endif
66
de5bf5d3 67#include "systime.h"
570d7624
JB
68
69#ifdef HPUX
70#include <netio.h>
9b7828a5 71#ifndef HPUX8
570d7624
JB
72#include <errnet.h>
73#endif
9b7828a5 74#endif
570d7624
JB
75
76#ifndef O_WRONLY
77#define O_WRONLY 1
78#endif
79
80#define min(a, b) ((a) < (b) ? (a) : (b))
81#define max(a, b) ((a) > (b) ? (a) : (b))
82
83/* Nonzero during writing of auto-save files */
84int auto_saving;
85
86/* Set by auto_save_1 to mode of original file so Fwrite_region will create
87 a new file with the same mode as the original */
88int auto_save_mode_bits;
89
32f4334d
RS
90/* Alist of elements (REGEXP . HANDLER) for file names
91 whose I/O is done with a special handler. */
92Lisp_Object Vfile_name_handler_alist;
93
570d7624
JB
94/* Nonzero means, when reading a filename in the minibuffer,
95 start out by inserting the default directory into the minibuffer. */
96int insert_default_directory;
97
98/* On VMS, nonzero means write new files with record format stmlf.
99 Zero means use var format. */
100int vms_stmlf_recfm;
101
102Lisp_Object Qfile_error, Qfile_already_exists;
103
104report_file_error (string, data)
105 char *string;
106 Lisp_Object data;
107{
108 Lisp_Object errstring;
109
110 if (errno >= 0 && errno < sys_nerr)
111 errstring = build_string (sys_errlist[errno]);
112 else
113 errstring = build_string ("undocumented error code");
114
115 /* System error messages are capitalized. Downcase the initial
116 unless it is followed by a slash. */
117 if (XSTRING (errstring)->data[1] != '/')
118 XSTRING (errstring)->data[0] = DOWNCASE (XSTRING (errstring)->data[0]);
119
120 while (1)
121 Fsignal (Qfile_error,
122 Fcons (build_string (string), Fcons (errstring, data)));
123}
b5148e85
RS
124
125close_file_unwind (fd)
126 Lisp_Object fd;
127{
128 close (XFASTINT (fd));
129}
570d7624 130\f
32f4334d
RS
131Lisp_Object Qcopy_file;
132Lisp_Object Qmake_directory;
133Lisp_Object Qdelete_directory;
134Lisp_Object Qdelete_file;
135Lisp_Object Qrename_file;
136Lisp_Object Qadd_name_to_file;
137Lisp_Object Qmake_symbolic_link;
138Lisp_Object Qfile_exists_p;
139Lisp_Object Qfile_executable_p;
140Lisp_Object Qfile_readable_p;
141Lisp_Object Qfile_symlink_p;
142Lisp_Object Qfile_writable_p;
143Lisp_Object Qfile_directory_p;
144Lisp_Object Qfile_accessible_directory_p;
145Lisp_Object Qfile_modes;
146Lisp_Object Qset_file_modes;
147Lisp_Object Qfile_newer_than_file_p;
148Lisp_Object Qinsert_file_contents;
149Lisp_Object Qwrite_region;
150Lisp_Object Qverify_visited_file_modtime;
151
152/* If FILENAME is handled specially on account of its syntax,
153 return its handler function. Otherwise, return nil. */
154
155Lisp_Object
156find_file_handler (filename)
157 Lisp_Object filename;
158{
159 Lisp_Object chain;
3eac9910 160 for (chain = Vfile_name_handler_alist; XTYPE (chain) == Lisp_Cons;
32f4334d
RS
161 chain = XCONS (chain)->cdr)
162 {
163 Lisp_Object elt;
164 elt = XCONS (chain)->car;
165 if (XTYPE (elt) == Lisp_Cons)
166 {
167 Lisp_Object string;
168 string = XCONS (elt)->car;
169 if (XTYPE (string) == Lisp_String
170 && fast_string_match (string, filename))
171 return XCONS (elt)->cdr;
172 }
173 }
174 return Qnil;
175}
176\f
570d7624
JB
177DEFUN ("file-name-directory", Ffile_name_directory, Sfile_name_directory,
178 1, 1, 0,
179 "Return the directory component in file name NAME.\n\
180Return nil if NAME does not include a directory.\n\
181Otherwise return a directory spec.\n\
182Given a Unix syntax file name, returns a string ending in slash;\n\
183on VMS, perhaps instead a string ending in `:', `]' or `>'.")
184 (file)
185 Lisp_Object file;
186{
187 register unsigned char *beg;
188 register unsigned char *p;
189
190 CHECK_STRING (file, 0);
191
192 beg = XSTRING (file)->data;
193 p = beg + XSTRING (file)->size;
194
195 while (p != beg && p[-1] != '/'
196#ifdef VMS
197 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
198#endif /* VMS */
199 ) p--;
200
201 if (p == beg)
202 return Qnil;
203 return make_string (beg, p - beg);
204}
205
206DEFUN ("file-name-nondirectory", Ffile_name_nondirectory, Sfile_name_nondirectory,
207 1, 1, 0,
208 "Return file name NAME sans its directory.\n\
209For example, in a Unix-syntax file name,\n\
210this is everything after the last slash,\n\
211or the entire name if it contains no slash.")
212 (file)
213 Lisp_Object file;
214{
215 register unsigned char *beg, *p, *end;
216
217 CHECK_STRING (file, 0);
218
219 beg = XSTRING (file)->data;
220 end = p = beg + XSTRING (file)->size;
221
222 while (p != beg && p[-1] != '/'
223#ifdef VMS
224 && p[-1] != ':' && p[-1] != ']' && p[-1] != '>'
225#endif /* VMS */
226 ) p--;
227
228 return make_string (p, end - p);
229}
230\f
231char *
232file_name_as_directory (out, in)
233 char *out, *in;
234{
235 int size = strlen (in) - 1;
236
237 strcpy (out, in);
238
239#ifdef VMS
240 /* Is it already a directory string? */
241 if (in[size] == ':' || in[size] == ']' || in[size] == '>')
242 return out;
243 /* Is it a VMS directory file name? If so, hack VMS syntax. */
244 else if (! index (in, '/')
245 && ((size > 3 && ! strcmp (&in[size - 3], ".DIR"))
246 || (size > 3 && ! strcmp (&in[size - 3], ".dir"))
247 || (size > 5 && (! strncmp (&in[size - 5], ".DIR", 4)
248 || ! strncmp (&in[size - 5], ".dir", 4))
249 && (in[size - 1] == '.' || in[size - 1] == ';')
250 && in[size] == '1')))
251 {
252 register char *p, *dot;
253 char brack;
254
255 /* x.dir -> [.x]
256 dir:x.dir --> dir:[x]
257 dir:[x]y.dir --> dir:[x.y] */
258 p = in + size;
259 while (p != in && *p != ':' && *p != '>' && *p != ']') p--;
260 if (p != in)
261 {
262 strncpy (out, in, p - in);
263 out[p - in] = '\0';
264 if (*p == ':')
265 {
266 brack = ']';
267 strcat (out, ":[");
268 }
269 else
270 {
271 brack = *p;
272 strcat (out, ".");
273 }
274 p++;
275 }
276 else
277 {
278 brack = ']';
279 strcpy (out, "[.");
280 }
bfb61299
JB
281 dot = index (p, '.');
282 if (dot)
570d7624
JB
283 {
284 /* blindly remove any extension */
285 size = strlen (out) + (dot - p);
286 strncat (out, p, dot - p);
287 }
288 else
289 {
290 strcat (out, p);
291 size = strlen (out);
292 }
293 out[size++] = brack;
294 out[size] = '\0';
295 }
296#else /* not VMS */
297 /* For Unix syntax, Append a slash if necessary */
298 if (out[size] != '/')
299 strcat (out, "/");
300#endif /* not VMS */
301 return out;
302}
303
304DEFUN ("file-name-as-directory", Ffile_name_as_directory,
305 Sfile_name_as_directory, 1, 1, 0,
306 "Return a string representing file FILENAME interpreted as a directory.\n\
307This operation exists because a directory is also a file, but its name as\n\
308a directory is different from its name as a file.\n\
309The result can be used as the value of `default-directory'\n\
310or passed as second argument to `expand-file-name'.\n\
311For a Unix-syntax file name, just appends a slash.\n\
312On VMS, converts \"[X]FOO.DIR\" to \"[X.FOO]\", etc.")
313 (file)
314 Lisp_Object file;
315{
316 char *buf;
317
318 CHECK_STRING (file, 0);
265a9e55 319 if (NILP (file))
570d7624
JB
320 return Qnil;
321 buf = (char *) alloca (XSTRING (file)->size + 10);
322 return build_string (file_name_as_directory (buf, XSTRING (file)->data));
323}
324\f
325/*
326 * Convert from directory name to filename.
327 * On VMS:
328 * xyzzy:[mukesh.emacs] => xyzzy:[mukesh]emacs.dir.1
329 * xyzzy:[mukesh] => xyzzy:[000000]mukesh.dir.1
330 * On UNIX, it's simple: just make sure there is a terminating /
331
332 * Value is nonzero if the string output is different from the input.
333 */
334
335directory_file_name (src, dst)
336 char *src, *dst;
337{
338 long slen;
339#ifdef VMS
340 long rlen;
341 char * ptr, * rptr;
342 char bracket;
343 struct FAB fab = cc$rms_fab;
344 struct NAM nam = cc$rms_nam;
345 char esa[NAM$C_MAXRSS];
346#endif /* VMS */
347
348 slen = strlen (src);
349#ifdef VMS
350 if (! index (src, '/')
351 && (src[slen - 1] == ']'
352 || src[slen - 1] == ':'
353 || src[slen - 1] == '>'))
354 {
355 /* VMS style - convert [x.y.z] to [x.y]z, [x] to [000000]x */
356 fab.fab$l_fna = src;
357 fab.fab$b_fns = slen;
358 fab.fab$l_nam = &nam;
359 fab.fab$l_fop = FAB$M_NAM;
360
361 nam.nam$l_esa = esa;
362 nam.nam$b_ess = sizeof esa;
363 nam.nam$b_nop |= NAM$M_SYNCHK;
364
365 /* We call SYS$PARSE to handle such things as [--] for us. */
366 if (SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL)
367 {
368 slen = nam.nam$b_esl;
369 if (esa[slen - 1] == ';' && esa[slen - 2] == '.')
370 slen -= 2;
371 esa[slen] = '\0';
372 src = esa;
373 }
374 if (src[slen - 1] != ']' && src[slen - 1] != '>')
375 {
376 /* what about when we have logical_name:???? */
377 if (src[slen - 1] == ':')
378 { /* Xlate logical name and see what we get */
379 ptr = strcpy (dst, src); /* upper case for getenv */
380 while (*ptr)
381 {
382 if ('a' <= *ptr && *ptr <= 'z')
383 *ptr -= 040;
384 ptr++;
385 }
386 dst[slen - 1] = 0; /* remove colon */
387 if (!(src = egetenv (dst)))
388 return 0;
389 /* should we jump to the beginning of this procedure?
390 Good points: allows us to use logical names that xlate
391 to Unix names,
392 Bad points: can be a problem if we just translated to a device
393 name...
394 For now, I'll punt and always expect VMS names, and hope for
395 the best! */
396 slen = strlen (src);
397 if (src[slen - 1] != ']' && src[slen - 1] != '>')
398 { /* no recursion here! */
399 strcpy (dst, src);
400 return 0;
401 }
402 }
403 else
404 { /* not a directory spec */
405 strcpy (dst, src);
406 return 0;
407 }
408 }
409 bracket = src[slen - 1];
410
411 /* If bracket is ']' or '>', bracket - 2 is the corresponding
412 opening bracket. */
bfb61299
JB
413 ptr = index (src, bracket - 2);
414 if (ptr == 0)
570d7624
JB
415 { /* no opening bracket */
416 strcpy (dst, src);
417 return 0;
418 }
419 if (!(rptr = rindex (src, '.')))
420 rptr = ptr;
421 slen = rptr - src;
422 strncpy (dst, src, slen);
423 dst[slen] = '\0';
424 if (*rptr == '.')
425 {
426 dst[slen++] = bracket;
427 dst[slen] = '\0';
428 }
429 else
430 {
431 /* If we have the top-level of a rooted directory (i.e. xx:[000000]),
432 then translate the device and recurse. */
433 if (dst[slen - 1] == ':'
434 && dst[slen - 2] != ':' /* skip decnet nodes */
435 && strcmp(src + slen, "[000000]") == 0)
436 {
437 dst[slen - 1] = '\0';
438 if ((ptr = egetenv (dst))
439 && (rlen = strlen (ptr) - 1) > 0
440 && (ptr[rlen] == ']' || ptr[rlen] == '>')
441 && ptr[rlen - 1] == '.')
442 {
443 ptr[rlen - 1] = ']';
444 ptr[rlen] = '\0';
445 return directory_file_name (ptr, dst);
446 }
447 else
448 dst[slen - 1] = ':';
449 }
450 strcat (dst, "[000000]");
451 slen += 8;
452 }
453 rptr++;
454 rlen = strlen (rptr) - 1;
455 strncat (dst, rptr, rlen);
456 dst[slen + rlen] = '\0';
457 strcat (dst, ".DIR.1");
458 return 1;
459 }
460#endif /* VMS */
461 /* Process as Unix format: just remove any final slash.
462 But leave "/" unchanged; do not change it to "". */
463 strcpy (dst, src);
4746118a 464 if (slen > 1 && dst[slen - 1] == '/')
570d7624
JB
465 dst[slen - 1] = 0;
466 return 1;
467}
468
469DEFUN ("directory-file-name", Fdirectory_file_name, Sdirectory_file_name,
470 1, 1, 0,
471 "Returns the file name of the directory named DIR.\n\
472This is the name of the file that holds the data for the directory DIR.\n\
473This operation exists because a directory is also a file, but its name as\n\
474a directory is different from its name as a file.\n\
475In Unix-syntax, this function just removes the final slash.\n\
476On VMS, given a VMS-syntax directory name such as \"[X.Y]\",\n\
477it returns a file name such as \"[X]Y.DIR.1\".")
478 (directory)
479 Lisp_Object directory;
480{
481 char *buf;
482
483 CHECK_STRING (directory, 0);
484
265a9e55 485 if (NILP (directory))
570d7624
JB
486 return Qnil;
487#ifdef VMS
488 /* 20 extra chars is insufficient for VMS, since we might perform a
489 logical name translation. an equivalence string can be up to 255
490 chars long, so grab that much extra space... - sss */
491 buf = (char *) alloca (XSTRING (directory)->size + 20 + 255);
492#else
493 buf = (char *) alloca (XSTRING (directory)->size + 20);
494#endif
495 directory_file_name (XSTRING (directory)->data, buf);
496 return build_string (buf);
497}
498
499DEFUN ("make-temp-name", Fmake_temp_name, Smake_temp_name, 1, 1, 0,
500 "Generate temporary file name (string) starting with PREFIX (a string).\n\
501The Emacs process number forms part of the result,\n\
502so there is no danger of generating a name being used by another process.")
503 (prefix)
504 Lisp_Object prefix;
505{
506 Lisp_Object val;
507 val = concat2 (prefix, build_string ("XXXXXX"));
508 mktemp (XSTRING (val)->data);
509 return val;
510}
511\f
512DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
513 "Convert FILENAME to absolute, and canonicalize it.\n\
514Second arg DEFAULT is directory to start with if FILENAME is relative\n\
515 (does not start with slash); if DEFAULT is nil or missing,\n\
516the current buffer's value of default-directory is used.\n\
b72dea2a
JB
517Path components that are `.' are removed, and \n\
518path components followed by `..' are removed, along with the `..' itself;\n\
519note that these simplifications are done without checking the resulting\n\
520paths in the file system.\n\
521An initial `~/' expands to your home directory.\n\
522An initial `~USER/' expands to USER's home directory.\n\
570d7624
JB
523See also the function `substitute-in-file-name'.")
524 (name, defalt)
525 Lisp_Object name, defalt;
526{
527 unsigned char *nm;
528
529 register unsigned char *newdir, *p, *o;
530 int tlen;
531 unsigned char *target;
532 struct passwd *pw;
533 int lose;
534#ifdef VMS
535 unsigned char * colon = 0;
536 unsigned char * close = 0;
537 unsigned char * slash = 0;
538 unsigned char * brack = 0;
539 int lbrack = 0, rbrack = 0;
540 int dots = 0;
541#endif /* VMS */
542
543 CHECK_STRING (name, 0);
544
545#ifdef VMS
546 /* Filenames on VMS are always upper case. */
547 name = Fupcase (name);
548#endif
549
550 nm = XSTRING (name)->data;
551
552 /* If nm is absolute, flush ...// and detect /./ and /../.
553 If no /./ or /../ we can return right away. */
554 if (
555 nm[0] == '/'
556#ifdef VMS
557 || index (nm, ':')
558#endif /* VMS */
559 )
560 {
561 p = nm;
562 lose = 0;
563 while (*p)
564 {
565 if (p[0] == '/' && p[1] == '/'
566#ifdef APOLLO
567 /* // at start of filename is meaningful on Apollo system */
568 && nm != p
569#endif /* APOLLO */
570 )
571 nm = p + 1;
572 if (p[0] == '/' && p[1] == '~')
573 nm = p + 1, lose = 1;
574 if (p[0] == '/' && p[1] == '.'
575 && (p[2] == '/' || p[2] == 0
576 || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
577 lose = 1;
578#ifdef VMS
579 if (p[0] == '\\')
580 lose = 1;
581 if (p[0] == '/') {
582 /* if dev:[dir]/, move nm to / */
583 if (!slash && p > nm && (brack || colon)) {
584 nm = (brack ? brack + 1 : colon + 1);
585 lbrack = rbrack = 0;
586 brack = 0;
587 colon = 0;
588 }
589 slash = p;
590 }
591 if (p[0] == '-')
592#ifndef VMS4_4
593 /* VMS pre V4.4,convert '-'s in filenames. */
594 if (lbrack == rbrack)
595 {
596 if (dots < 2) /* this is to allow negative version numbers */
597 p[0] = '_';
598 }
599 else
600#endif /* VMS4_4 */
601 if (lbrack > rbrack &&
602 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
603 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
604 lose = 1;
605#ifndef VMS4_4
606 else
607 p[0] = '_';
608#endif /* VMS4_4 */
609 /* count open brackets, reset close bracket pointer */
610 if (p[0] == '[' || p[0] == '<')
611 lbrack++, brack = 0;
612 /* count close brackets, set close bracket pointer */
613 if (p[0] == ']' || p[0] == '>')
614 rbrack++, brack = p;
615 /* detect ][ or >< */
616 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
617 lose = 1;
618 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
619 nm = p + 1, lose = 1;
620 if (p[0] == ':' && (colon || slash))
621 /* if dev1:[dir]dev2:, move nm to dev2: */
622 if (brack)
623 {
624 nm = brack + 1;
625 brack = 0;
626 }
627 /* if /pathname/dev:, move nm to dev: */
628 else if (slash)
629 nm = slash + 1;
630 /* if node::dev:, move colon following dev */
631 else if (colon && colon[-1] == ':')
632 colon = p;
633 /* if dev1:dev2:, move nm to dev2: */
634 else if (colon && colon[-1] != ':')
635 {
636 nm = colon + 1;
637 colon = 0;
638 }
639 if (p[0] == ':' && !colon)
640 {
641 if (p[1] == ':')
642 p++;
643 colon = p;
644 }
645 if (lbrack == rbrack)
646 if (p[0] == ';')
647 dots = 2;
648 else if (p[0] == '.')
649 dots++;
650#endif /* VMS */
651 p++;
652 }
653 if (!lose)
654 {
655#ifdef VMS
656 if (index (nm, '/'))
657 return build_string (sys_translate_unix (nm));
658#endif /* VMS */
659 if (nm == XSTRING (name)->data)
660 return name;
661 return build_string (nm);
662 }
663 }
664
665 /* Now determine directory to start with and put it in newdir */
666
667 newdir = 0;
668
669 if (nm[0] == '~') /* prefix ~ */
670 if (nm[1] == '/'
671#ifdef VMS
672 || nm[1] == ':'
673#endif /* VMS */
e5d77022 674 || nm[1] == 0)/* ~ by itself */
570d7624
JB
675 {
676 if (!(newdir = (unsigned char *) egetenv ("HOME")))
677 newdir = (unsigned char *) "";
678 nm++;
679#ifdef VMS
680 nm++; /* Don't leave the slash in nm. */
681#endif /* VMS */
682 }
683 else /* ~user/filename */
684 {
685 for (p = nm; *p && (*p != '/'
686#ifdef VMS
687 && *p != ':'
688#endif /* VMS */
689 ); p++);
690 o = (unsigned char *) alloca (p - nm + 1);
691 bcopy ((char *) nm, o, p - nm);
692 o [p - nm] = 0;
693
694 pw = (struct passwd *) getpwnam (o + 1);
e5d77022
JB
695 if (pw)
696 {
697 newdir = (unsigned char *) pw -> pw_dir;
570d7624 698#ifdef VMS
e5d77022 699 nm = p + 1; /* skip the terminator */
570d7624 700#else
e5d77022 701 nm = p;
570d7624 702#endif /* VMS */
e5d77022
JB
703 }
704
705 /* If we don't find a user of that name, leave the name
706 unchanged; don't move nm forward to p. */
570d7624
JB
707 }
708
709 if (nm[0] != '/'
710#ifdef VMS
711 && !index (nm, ':')
712#endif /* not VMS */
713 && !newdir)
714 {
265a9e55 715 if (NILP (defalt))
570d7624
JB
716 defalt = current_buffer->directory;
717 CHECK_STRING (defalt, 1);
718 newdir = XSTRING (defalt)->data;
719 }
720
bfb61299
JB
721 if (newdir != 0)
722 {
723 /* Get rid of any slash at the end of newdir. */
724 int length = strlen (newdir);
725 if (newdir[length - 1] == '/')
726 {
727 unsigned char *temp = (unsigned char *) alloca (length);
728 bcopy (newdir, temp, length - 1);
729 temp[length - 1] = 0;
730 newdir = temp;
731 }
732 tlen = length + 1;
733 }
734 else
735 tlen = 0;
570d7624 736
bfb61299
JB
737 /* Now concatenate the directory and name to new space in the stack frame */
738 tlen += strlen (nm) + 1;
570d7624
JB
739 target = (unsigned char *) alloca (tlen);
740 *target = 0;
741
742 if (newdir)
743 {
744#ifndef VMS
745 if (nm[0] == 0 || nm[0] == '/')
746 strcpy (target, newdir);
747 else
748#endif
749 file_name_as_directory (target, newdir);
750 }
751
752 strcat (target, nm);
753#ifdef VMS
754 if (index (target, '/'))
755 strcpy (target, sys_translate_unix (target));
756#endif /* VMS */
757
758 /* Now canonicalize by removing /. and /foo/.. if they appear */
759
760 p = target;
761 o = target;
762
763 while (*p)
764 {
765#ifdef VMS
766 if (*p != ']' && *p != '>' && *p != '-')
767 {
768 if (*p == '\\')
769 p++;
770 *o++ = *p++;
771 }
772 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
773 /* brackets are offset from each other by 2 */
774 {
775 p += 2;
776 if (*p != '.' && *p != '-' && o[-1] != '.')
777 /* convert [foo][bar] to [bar] */
778 while (o[-1] != '[' && o[-1] != '<')
779 o--;
780 else if (*p == '-' && *o != '.')
781 *--p = '.';
782 }
783 else if (p[0] == '-' && o[-1] == '.' &&
784 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
785 /* flush .foo.- ; leave - if stopped by '[' or '<' */
786 {
787 do
788 o--;
789 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
790 if (p[1] == '.') /* foo.-.bar ==> bar*/
791 p += 2;
792 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
793 p++, o--;
794 /* else [foo.-] ==> [-] */
795 }
796 else
797 {
798#ifndef VMS4_4
799 if (*p == '-' &&
800 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
801 p[1] != ']' && p[1] != '>' && p[1] != '.')
802 *p = '_';
803#endif /* VMS4_4 */
804 *o++ = *p++;
805 }
806#else /* not VMS */
807 if (*p != '/')
808 {
809 *o++ = *p++;
810 }
811 else if (!strncmp (p, "//", 2)
812#ifdef APOLLO
813 /* // at start of filename is meaningful in Apollo system */
814 && o != target
815#endif /* APOLLO */
816 )
817 {
818 o = target;
819 p++;
820 }
821 else if (p[0] == '/' && p[1] == '.' &&
822 (p[2] == '/' || p[2] == 0))
823 p += 2;
824 else if (!strncmp (p, "/..", 3)
825 /* `/../' is the "superroot" on certain file systems. */
826 && o != target
827 && (p[3] == '/' || p[3] == 0))
828 {
829 while (o != target && *--o != '/')
830 ;
831#ifdef APOLLO
832 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
833 ++o;
834 else
835#endif /* APOLLO */
836 if (o == target && *o == '/')
837 ++o;
838 p += 3;
839 }
840 else
841 {
842 *o++ = *p++;
843 }
844#endif /* not VMS */
845 }
846
847 return make_string (target, o - target);
848}
849#if 0
e5d77022
JB
850/* Changed this DEFUN to a DEAFUN, so as not to confuse `make-docfile'.
851DEAFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0,
570d7624
JB
852 "Convert FILENAME to absolute, and canonicalize it.\n\
853Second arg DEFAULT is directory to start with if FILENAME is relative\n\
854 (does not start with slash); if DEFAULT is nil or missing,\n\
855the current buffer's value of default-directory is used.\n\
856Filenames containing `.' or `..' as components are simplified;\n\
857initial `~/' expands to your home directory.\n\
858See also the function `substitute-in-file-name'.")
859 (name, defalt)
860 Lisp_Object name, defalt;
861{
862 unsigned char *nm;
863
864 register unsigned char *newdir, *p, *o;
865 int tlen;
866 unsigned char *target;
867 struct passwd *pw;
868 int lose;
869#ifdef VMS
870 unsigned char * colon = 0;
871 unsigned char * close = 0;
872 unsigned char * slash = 0;
873 unsigned char * brack = 0;
874 int lbrack = 0, rbrack = 0;
875 int dots = 0;
876#endif /* VMS */
877
878 CHECK_STRING (name, 0);
879
880#ifdef VMS
881 /* Filenames on VMS are always upper case. */
882 name = Fupcase (name);
883#endif
884
885 nm = XSTRING (name)->data;
886
887 /* If nm is absolute, flush ...// and detect /./ and /../.
888 If no /./ or /../ we can return right away. */
889 if (
890 nm[0] == '/'
891#ifdef VMS
892 || index (nm, ':')
893#endif /* VMS */
894 )
895 {
896 p = nm;
897 lose = 0;
898 while (*p)
899 {
900 if (p[0] == '/' && p[1] == '/'
901#ifdef APOLLO
902 /* // at start of filename is meaningful on Apollo system */
903 && nm != p
904#endif /* APOLLO */
905 )
906 nm = p + 1;
907 if (p[0] == '/' && p[1] == '~')
908 nm = p + 1, lose = 1;
909 if (p[0] == '/' && p[1] == '.'
910 && (p[2] == '/' || p[2] == 0
911 || (p[2] == '.' && (p[3] == '/' || p[3] == 0))))
912 lose = 1;
913#ifdef VMS
914 if (p[0] == '\\')
915 lose = 1;
916 if (p[0] == '/') {
917 /* if dev:[dir]/, move nm to / */
918 if (!slash && p > nm && (brack || colon)) {
919 nm = (brack ? brack + 1 : colon + 1);
920 lbrack = rbrack = 0;
921 brack = 0;
922 colon = 0;
923 }
924 slash = p;
925 }
926 if (p[0] == '-')
927#ifndef VMS4_4
928 /* VMS pre V4.4,convert '-'s in filenames. */
929 if (lbrack == rbrack)
930 {
931 if (dots < 2) /* this is to allow negative version numbers */
932 p[0] = '_';
933 }
934 else
935#endif /* VMS4_4 */
936 if (lbrack > rbrack &&
937 ((p[-1] == '.' || p[-1] == '[' || p[-1] == '<') &&
938 (p[1] == '.' || p[1] == ']' || p[1] == '>')))
939 lose = 1;
940#ifndef VMS4_4
941 else
942 p[0] = '_';
943#endif /* VMS4_4 */
944 /* count open brackets, reset close bracket pointer */
945 if (p[0] == '[' || p[0] == '<')
946 lbrack++, brack = 0;
947 /* count close brackets, set close bracket pointer */
948 if (p[0] == ']' || p[0] == '>')
949 rbrack++, brack = p;
950 /* detect ][ or >< */
951 if ((p[0] == ']' || p[0] == '>') && (p[1] == '[' || p[1] == '<'))
952 lose = 1;
953 if ((p[0] == ':' || p[0] == ']' || p[0] == '>') && p[1] == '~')
954 nm = p + 1, lose = 1;
955 if (p[0] == ':' && (colon || slash))
956 /* if dev1:[dir]dev2:, move nm to dev2: */
957 if (brack)
958 {
959 nm = brack + 1;
960 brack = 0;
961 }
962 /* if /pathname/dev:, move nm to dev: */
963 else if (slash)
964 nm = slash + 1;
965 /* if node::dev:, move colon following dev */
966 else if (colon && colon[-1] == ':')
967 colon = p;
968 /* if dev1:dev2:, move nm to dev2: */
969 else if (colon && colon[-1] != ':')
970 {
971 nm = colon + 1;
972 colon = 0;
973 }
974 if (p[0] == ':' && !colon)
975 {
976 if (p[1] == ':')
977 p++;
978 colon = p;
979 }
980 if (lbrack == rbrack)
981 if (p[0] == ';')
982 dots = 2;
983 else if (p[0] == '.')
984 dots++;
985#endif /* VMS */
986 p++;
987 }
988 if (!lose)
989 {
990#ifdef VMS
991 if (index (nm, '/'))
992 return build_string (sys_translate_unix (nm));
993#endif /* VMS */
994 if (nm == XSTRING (name)->data)
995 return name;
996 return build_string (nm);
997 }
998 }
999
1000 /* Now determine directory to start with and put it in NEWDIR */
1001
1002 newdir = 0;
1003
1004 if (nm[0] == '~') /* prefix ~ */
1005 if (nm[1] == '/'
1006#ifdef VMS
1007 || nm[1] == ':'
1008#endif /* VMS */
1009 || nm[1] == 0)/* ~/filename */
1010 {
1011 if (!(newdir = (unsigned char *) egetenv ("HOME")))
1012 newdir = (unsigned char *) "";
1013 nm++;
1014#ifdef VMS
1015 nm++; /* Don't leave the slash in nm. */
1016#endif /* VMS */
1017 }
1018 else /* ~user/filename */
1019 {
1020 /* Get past ~ to user */
1021 unsigned char *user = nm + 1;
1022 /* Find end of name. */
1023 unsigned char *ptr = (unsigned char *) index (user, '/');
1024 int len = ptr ? ptr - user : strlen (user);
1025#ifdef VMS
1026 unsigned char *ptr1 = index (user, ':');
1027 if (ptr1 != 0 && ptr1 - user < len)
1028 len = ptr1 - user;
1029#endif /* VMS */
1030 /* Copy the user name into temp storage. */
1031 o = (unsigned char *) alloca (len + 1);
1032 bcopy ((char *) user, o, len);
1033 o[len] = 0;
1034
1035 /* Look up the user name. */
1036 pw = (struct passwd *) getpwnam (o + 1);
1037 if (!pw)
1038 error ("\"%s\" isn't a registered user", o + 1);
1039
1040 newdir = (unsigned char *) pw->pw_dir;
1041
1042 /* Discard the user name from NM. */
1043 nm += len;
1044 }
1045
1046 if (nm[0] != '/'
1047#ifdef VMS
1048 && !index (nm, ':')
1049#endif /* not VMS */
1050 && !newdir)
1051 {
265a9e55 1052 if (NILP (defalt))
570d7624
JB
1053 defalt = current_buffer->directory;
1054 CHECK_STRING (defalt, 1);
1055 newdir = XSTRING (defalt)->data;
1056 }
1057
1058 /* Now concatenate the directory and name to new space in the stack frame */
1059
1060 tlen = (newdir ? strlen (newdir) + 1 : 0) + strlen (nm) + 1;
1061 target = (unsigned char *) alloca (tlen);
1062 *target = 0;
1063
1064 if (newdir)
1065 {
1066#ifndef VMS
1067 if (nm[0] == 0 || nm[0] == '/')
1068 strcpy (target, newdir);
1069 else
1070#endif
1071 file_name_as_directory (target, newdir);
1072 }
1073
1074 strcat (target, nm);
1075#ifdef VMS
1076 if (index (target, '/'))
1077 strcpy (target, sys_translate_unix (target));
1078#endif /* VMS */
1079
1080 /* Now canonicalize by removing /. and /foo/.. if they appear */
1081
1082 p = target;
1083 o = target;
1084
1085 while (*p)
1086 {
1087#ifdef VMS
1088 if (*p != ']' && *p != '>' && *p != '-')
1089 {
1090 if (*p == '\\')
1091 p++;
1092 *o++ = *p++;
1093 }
1094 else if ((p[0] == ']' || p[0] == '>') && p[0] == p[1] + 2)
1095 /* brackets are offset from each other by 2 */
1096 {
1097 p += 2;
1098 if (*p != '.' && *p != '-' && o[-1] != '.')
1099 /* convert [foo][bar] to [bar] */
1100 while (o[-1] != '[' && o[-1] != '<')
1101 o--;
1102 else if (*p == '-' && *o != '.')
1103 *--p = '.';
1104 }
1105 else if (p[0] == '-' && o[-1] == '.' &&
1106 (p[1] == '.' || p[1] == ']' || p[1] == '>'))
1107 /* flush .foo.- ; leave - if stopped by '[' or '<' */
1108 {
1109 do
1110 o--;
1111 while (o[-1] != '.' && o[-1] != '[' && o[-1] != '<');
1112 if (p[1] == '.') /* foo.-.bar ==> bar*/
1113 p += 2;
1114 else if (o[-1] == '.') /* '.foo.-]' ==> ']' */
1115 p++, o--;
1116 /* else [foo.-] ==> [-] */
1117 }
1118 else
1119 {
1120#ifndef VMS4_4
1121 if (*p == '-' &&
1122 o[-1] != '[' && o[-1] != '<' && o[-1] != '.' &&
1123 p[1] != ']' && p[1] != '>' && p[1] != '.')
1124 *p = '_';
1125#endif /* VMS4_4 */
1126 *o++ = *p++;
1127 }
1128#else /* not VMS */
1129 if (*p != '/')
1130 {
1131 *o++ = *p++;
1132 }
1133 else if (!strncmp (p, "//", 2)
1134#ifdef APOLLO
1135 /* // at start of filename is meaningful in Apollo system */
1136 && o != target
1137#endif /* APOLLO */
1138 )
1139 {
1140 o = target;
1141 p++;
1142 }
1143 else if (p[0] == '/' && p[1] == '.' &&
1144 (p[2] == '/' || p[2] == 0))
1145 p += 2;
1146 else if (!strncmp (p, "/..", 3)
1147 /* `/../' is the "superroot" on certain file systems. */
1148 && o != target
1149 && (p[3] == '/' || p[3] == 0))
1150 {
1151 while (o != target && *--o != '/')
1152 ;
1153#ifdef APOLLO
1154 if (o == target + 1 && o[-1] == '/' && o[0] == '/')
1155 ++o;
1156 else
1157#endif /* APOLLO */
1158 if (o == target && *o == '/')
1159 ++o;
1160 p += 3;
1161 }
1162 else
1163 {
1164 *o++ = *p++;
1165 }
1166#endif /* not VMS */
1167 }
1168
1169 return make_string (target, o - target);
1170}
1171#endif
1172\f
1173DEFUN ("substitute-in-file-name", Fsubstitute_in_file_name,
1174 Ssubstitute_in_file_name, 1, 1, 0,
1175 "Substitute environment variables referred to in FILENAME.\n\
1176`$FOO' where FOO is an environment variable name means to substitute\n\
1177the value of that variable. The variable name should be terminated\n\
1178with a character not a letter, digit or underscore; otherwise, enclose\n\
1179the entire variable name in braces.\n\
1180If `/~' appears, all of FILENAME through that `/' is discarded.\n\n\
1181On VMS, `$' substitution is not done; this function does little and only\n\
1182duplicates what `expand-file-name' does.")
1183 (string)
1184 Lisp_Object string;
1185{
1186 unsigned char *nm;
1187
1188 register unsigned char *s, *p, *o, *x, *endp;
1189 unsigned char *target;
1190 int total = 0;
1191 int substituted = 0;
1192 unsigned char *xnm;
1193
1194 CHECK_STRING (string, 0);
1195
1196 nm = XSTRING (string)->data;
1197 endp = nm + XSTRING (string)->size;
1198
1199 /* If /~ or // appears, discard everything through first slash. */
1200
1201 for (p = nm; p != endp; p++)
1202 {
1203 if ((p[0] == '~' ||
1204#ifdef APOLLO
1205 /* // at start of file name is meaningful in Apollo system */
1206 (p[0] == '/' && p - 1 != nm)
1207#else /* not APOLLO */
1208 p[0] == '/'
1209#endif /* not APOLLO */
1210 )
1211 && p != nm &&
1212#ifdef VMS
1213 (p[-1] == ':' || p[-1] == ']' || p[-1] == '>' ||
1214#endif /* VMS */
1215 p[-1] == '/')
1216#ifdef VMS
1217 )
1218#endif /* VMS */
1219 {
1220 nm = p;
1221 substituted = 1;
1222 }
1223 }
1224
1225#ifdef VMS
1226 return build_string (nm);
1227#else
1228
1229 /* See if any variables are substituted into the string
1230 and find the total length of their values in `total' */
1231
1232 for (p = nm; p != endp;)
1233 if (*p != '$')
1234 p++;
1235 else
1236 {
1237 p++;
1238 if (p == endp)
1239 goto badsubst;
1240 else if (*p == '$')
1241 {
1242 /* "$$" means a single "$" */
1243 p++;
1244 total -= 1;
1245 substituted = 1;
1246 continue;
1247 }
1248 else if (*p == '{')
1249 {
1250 o = ++p;
1251 while (p != endp && *p != '}') p++;
1252 if (*p != '}') goto missingclose;
1253 s = p;
1254 }
1255 else
1256 {
1257 o = p;
1258 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1259 s = p;
1260 }
1261
1262 /* Copy out the variable name */
1263 target = (unsigned char *) alloca (s - o + 1);
1264 strncpy (target, o, s - o);
1265 target[s - o] = 0;
1266
1267 /* Get variable value */
1268 o = (unsigned char *) egetenv (target);
1269/* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
1270#if 0
1271#ifdef USG
1272 if (!o && !strcmp (target, "USER"))
1273 o = egetenv ("LOGNAME");
1274#endif /* USG */
1275#endif /* 0 */
1276 if (!o) goto badvar;
1277 total += strlen (o);
1278 substituted = 1;
1279 }
1280
1281 if (!substituted)
1282 return string;
1283
1284 /* If substitution required, recopy the string and do it */
1285 /* Make space in stack frame for the new copy */
1286 xnm = (unsigned char *) alloca (XSTRING (string)->size + total + 1);
1287 x = xnm;
1288
1289 /* Copy the rest of the name through, replacing $ constructs with values */
1290 for (p = nm; *p;)
1291 if (*p != '$')
1292 *x++ = *p++;
1293 else
1294 {
1295 p++;
1296 if (p == endp)
1297 goto badsubst;
1298 else if (*p == '$')
1299 {
1300 *x++ = *p++;
1301 continue;
1302 }
1303 else if (*p == '{')
1304 {
1305 o = ++p;
1306 while (p != endp && *p != '}') p++;
1307 if (*p != '}') goto missingclose;
1308 s = p++;
1309 }
1310 else
1311 {
1312 o = p;
1313 while (p != endp && (isalnum (*p) || *p == '_')) p++;
1314 s = p;
1315 }
1316
1317 /* Copy out the variable name */
1318 target = (unsigned char *) alloca (s - o + 1);
1319 strncpy (target, o, s - o);
1320 target[s - o] = 0;
1321
1322 /* Get variable value */
1323 o = (unsigned char *) egetenv (target);
1324/* The presence of this code makes vax 5.0 crash, for reasons yet unknown */
1325#if 0
1326#ifdef USG
1327 if (!o && !strcmp (target, "USER"))
1328 o = egetenv ("LOGNAME");
1329#endif /* USG */
1330#endif /* 0 */
1331 if (!o)
1332 goto badvar;
1333
1334 strcpy (x, o);
1335 x += strlen (o);
1336 }
1337
1338 *x = 0;
1339
1340 /* If /~ or // appears, discard everything through first slash. */
1341
1342 for (p = xnm; p != x; p++)
1343 if ((p[0] == '~' ||
1344#ifdef APOLLO
1345 /* // at start of file name is meaningful in Apollo system */
1346 (p[0] == '/' && p - 1 != xnm)
1347#else /* not APOLLO */
1348 p[0] == '/'
1349#endif /* not APOLLO */
1350 )
1351 && p != nm && p[-1] == '/')
1352 xnm = p;
1353
1354 return make_string (xnm, x - xnm);
1355
1356 badsubst:
1357 error ("Bad format environment-variable substitution");
1358 missingclose:
1359 error ("Missing \"}\" in environment-variable substitution");
1360 badvar:
1361 error ("Substituting nonexistent environment variable \"%s\"", target);
1362
1363 /* NOTREACHED */
1364#endif /* not VMS */
1365}
1366\f
1367Lisp_Object
1368expand_and_dir_to_file (filename, defdir)
1369 Lisp_Object filename, defdir;
1370{
1371 register Lisp_Object abspath;
1372
1373 abspath = Fexpand_file_name (filename, defdir);
1374#ifdef VMS
1375 {
1376 register int c = XSTRING (abspath)->data[XSTRING (abspath)->size - 1];
1377 if (c == ':' || c == ']' || c == '>')
1378 abspath = Fdirectory_file_name (abspath);
1379 }
1380#else
1381 /* Remove final slash, if any (unless path is root).
1382 stat behaves differently depending! */
1383 if (XSTRING (abspath)->size > 1
1384 && XSTRING (abspath)->data[XSTRING (abspath)->size - 1] == '/')
1385 {
1386 if (EQ (abspath, filename))
1387 abspath = Fcopy_sequence (abspath);
1388 XSTRING (abspath)->data[XSTRING (abspath)->size - 1] = 0;
1389 }
1390#endif
1391 return abspath;
1392}
1393\f
1394barf_or_query_if_file_exists (absname, querystring, interactive)
1395 Lisp_Object absname;
1396 unsigned char *querystring;
1397 int interactive;
1398{
1399 register Lisp_Object tem;
1400 struct gcpro gcpro1;
1401
1402 if (access (XSTRING (absname)->data, 4) >= 0)
1403 {
1404 if (! interactive)
1405 Fsignal (Qfile_already_exists,
1406 Fcons (build_string ("File already exists"),
1407 Fcons (absname, Qnil)));
1408 GCPRO1 (absname);
1409 tem = do_yes_or_no_p (format1 ("File %s already exists; %s anyway? ",
1410 XSTRING (absname)->data, querystring));
1411 UNGCPRO;
265a9e55 1412 if (NILP (tem))
570d7624
JB
1413 Fsignal (Qfile_already_exists,
1414 Fcons (build_string ("File already exists"),
1415 Fcons (absname, Qnil)));
1416 }
1417 return;
1418}
1419
1420DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 4,
349a7710 1421 "fCopy file: \nFCopy %s to file: \np\nP",
570d7624
JB
1422 "Copy FILE to NEWNAME. Both args must be strings.\n\
1423Signals a `file-already-exists' error if file NEWNAME already exists,\n\
1424unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.\n\
1425A number as third arg means request confirmation if NEWNAME already exists.\n\
1426This is what happens in interactive use with M-x.\n\
349a7710
JB
1427Fourth arg KEEP-TIME non-nil means give the new file the same\n\
1428last-modified time as the old one. (This works on only some systems.)\n\
1429A prefix arg makes KEEP-TIME non-nil.")
570d7624
JB
1430 (filename, newname, ok_if_already_exists, keep_date)
1431 Lisp_Object filename, newname, ok_if_already_exists, keep_date;
1432{
1433 int ifd, ofd, n;
1434 char buf[16 * 1024];
1435 struct stat st;
32f4334d 1436 Lisp_Object handler;
570d7624 1437 struct gcpro gcpro1, gcpro2;
b5148e85 1438 int count = specpdl_ptr - specpdl;
570d7624
JB
1439
1440 GCPRO2 (filename, newname);
1441 CHECK_STRING (filename, 0);
1442 CHECK_STRING (newname, 1);
1443 filename = Fexpand_file_name (filename, Qnil);
1444 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1445
1446 /* If the file name has special constructs in it,
1447 call the corresponding file handler. */
1448 handler = find_file_handler (filename);
1449 if (!NILP (handler))
1450 return call3 (handler, Qcopy_file, filename, newname);
1451
265a9e55 1452 if (NILP (ok_if_already_exists)
570d7624
JB
1453 || XTYPE (ok_if_already_exists) == Lisp_Int)
1454 barf_or_query_if_file_exists (newname, "copy to it",
1455 XTYPE (ok_if_already_exists) == Lisp_Int);
1456
1457 ifd = open (XSTRING (filename)->data, 0);
1458 if (ifd < 0)
1459 report_file_error ("Opening input file", Fcons (filename, Qnil));
1460
b5148e85
RS
1461 record_unwind_protect (close_file_unwind, make_number (ifd));
1462
570d7624
JB
1463#ifdef VMS
1464 /* Create the copy file with the same record format as the input file */
1465 ofd = sys_creat (XSTRING (newname)->data, 0666, ifd);
1466#else
1467 ofd = creat (XSTRING (newname)->data, 0666);
1468#endif /* VMS */
1469 if (ofd < 0)
66331187 1470 report_file_error ("Opening output file", Fcons (newname, Qnil));
b5148e85
RS
1471
1472 record_unwind_protect (close_file_unwind, make_number (ofd));
570d7624 1473
b5148e85
RS
1474 immediate_quit = 1;
1475 QUIT;
570d7624
JB
1476 while ((n = read (ifd, buf, sizeof buf)) > 0)
1477 if (write (ofd, buf, n) != n)
66331187 1478 report_file_error ("I/O error", Fcons (newname, Qnil));
b5148e85 1479 immediate_quit = 0;
570d7624
JB
1480
1481 if (fstat (ifd, &st) >= 0)
1482 {
265a9e55 1483 if (!NILP (keep_date))
570d7624 1484 {
de5bf5d3
JB
1485 EMACS_TIME atime, mtime;
1486 EMACS_SET_SECS_USECS (atime, st.st_atime, 0);
1487 EMACS_SET_SECS_USECS (mtime, st.st_mtime, 0);
1488 EMACS_SET_UTIMES (XSTRING (newname)->data, atime, mtime);
570d7624 1489 }
570d7624
JB
1490#ifdef APOLLO
1491 if (!egetenv ("USE_DOMAIN_ACLS"))
1492#endif
de5bf5d3 1493 chmod (XSTRING (newname)->data, st.st_mode & 07777);
570d7624
JB
1494 }
1495
b5148e85
RS
1496 /* Discard the unwind protects. */
1497 specpdl_ptr = specpdl + count;
1498
570d7624
JB
1499 close (ifd);
1500 if (close (ofd) < 0)
1501 report_file_error ("I/O error", Fcons (newname, Qnil));
1502
1503 UNGCPRO;
1504 return Qnil;
1505}
1506
1507DEFUN ("make-directory", Fmake_directory, Smake_directory, 1, 1, "FMake directory: ",
1508 "Create a directory. One argument, a file name string.")
1509 (dirname)
1510 Lisp_Object dirname;
1511{
1512 unsigned char *dir;
32f4334d 1513 Lisp_Object handler;
570d7624
JB
1514
1515 CHECK_STRING (dirname, 0);
1516 dirname = Fexpand_file_name (dirname, Qnil);
32f4334d
RS
1517
1518 handler = find_file_handler (dirname);
1519 if (!NILP (handler))
1520 return call2 (handler, Qmake_directory, dirname);
1521
570d7624
JB
1522 dir = XSTRING (dirname)->data;
1523
1524 if (mkdir (dir, 0777) != 0)
1525 report_file_error ("Creating directory", Flist (1, &dirname));
1526
32f4334d 1527 return Qnil;
570d7624
JB
1528}
1529
aa734e17
RS
1530DEFUN ("delete-directory", Fdelete_directory, Sdelete_directory, 1, 1, "FDelete directory: ",
1531 "Delete a directory. One argument, a file name string.")
570d7624
JB
1532 (dirname)
1533 Lisp_Object dirname;
1534{
1535 unsigned char *dir;
32f4334d 1536 Lisp_Object handler;
570d7624
JB
1537
1538 CHECK_STRING (dirname, 0);
1539 dirname = Fexpand_file_name (dirname, Qnil);
1540 dir = XSTRING (dirname)->data;
1541
32f4334d
RS
1542 handler = find_file_handler (dirname);
1543 if (!NILP (handler))
1544 return call2 (handler, Qdelete_directory, dirname);
1545
570d7624
JB
1546 if (rmdir (dir) != 0)
1547 report_file_error ("Removing directory", Flist (1, &dirname));
1548
1549 return Qnil;
1550}
1551
1552DEFUN ("delete-file", Fdelete_file, Sdelete_file, 1, 1, "fDelete file: ",
1553 "Delete specified file. One argument, a file name string.\n\
1554If file has multiple names, it continues to exist with the other names.")
1555 (filename)
1556 Lisp_Object filename;
1557{
32f4334d 1558 Lisp_Object handler;
570d7624
JB
1559 CHECK_STRING (filename, 0);
1560 filename = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1561
1562 handler = find_file_handler (filename);
1563 if (!NILP (handler))
1564 return call2 (handler, Qdelete_file, filename);
1565
570d7624
JB
1566 if (0 > unlink (XSTRING (filename)->data))
1567 report_file_error ("Removing old name", Flist (1, &filename));
1568 return Qnil;
1569}
1570
1571DEFUN ("rename-file", Frename_file, Srename_file, 2, 3,
1572 "fRename file: \nFRename %s to file: \np",
1573 "Rename FILE as NEWNAME. Both args strings.\n\
1574If file has names other than FILE, it continues to have those names.\n\
1575Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1576unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1577A number as third arg means request confirmation if NEWNAME already exists.\n\
1578This is what happens in interactive use with M-x.")
1579 (filename, newname, ok_if_already_exists)
1580 Lisp_Object filename, newname, ok_if_already_exists;
1581{
1582#ifdef NO_ARG_ARRAY
1583 Lisp_Object args[2];
1584#endif
32f4334d 1585 Lisp_Object handler;
570d7624
JB
1586 struct gcpro gcpro1, gcpro2;
1587
1588 GCPRO2 (filename, newname);
1589 CHECK_STRING (filename, 0);
1590 CHECK_STRING (newname, 1);
1591 filename = Fexpand_file_name (filename, Qnil);
1592 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1593
1594 /* If the file name has special constructs in it,
1595 call the corresponding file handler. */
1596 handler = find_file_handler (filename);
1597 if (!NILP (handler))
1598 return call3 (handler, Qrename_file, filename, newname);
1599
265a9e55 1600 if (NILP (ok_if_already_exists)
570d7624
JB
1601 || XTYPE (ok_if_already_exists) == Lisp_Int)
1602 barf_or_query_if_file_exists (newname, "rename to it",
1603 XTYPE (ok_if_already_exists) == Lisp_Int);
1604#ifndef BSD4_1
1605 if (0 > rename (XSTRING (filename)->data, XSTRING (newname)->data))
1606#else
1607 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data)
1608 || 0 > unlink (XSTRING (filename)->data))
1609#endif
1610 {
1611 if (errno == EXDEV)
1612 {
1613 Fcopy_file (filename, newname, ok_if_already_exists, Qt);
1614 Fdelete_file (filename);
1615 }
1616 else
1617#ifdef NO_ARG_ARRAY
1618 {
1619 args[0] = filename;
1620 args[1] = newname;
1621 report_file_error ("Renaming", Flist (2, args));
1622 }
1623#else
1624 report_file_error ("Renaming", Flist (2, &filename));
1625#endif
1626 }
1627 UNGCPRO;
1628 return Qnil;
1629}
1630
1631DEFUN ("add-name-to-file", Fadd_name_to_file, Sadd_name_to_file, 2, 3,
1632 "fAdd name to file: \nFName to add to %s: \np",
1633 "Give FILE additional name NEWNAME. Both args strings.\n\
1634Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1635unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1636A number as third arg means request confirmation if NEWNAME already exists.\n\
1637This is what happens in interactive use with M-x.")
1638 (filename, newname, ok_if_already_exists)
1639 Lisp_Object filename, newname, ok_if_already_exists;
1640{
1641#ifdef NO_ARG_ARRAY
1642 Lisp_Object args[2];
1643#endif
32f4334d 1644 Lisp_Object handler;
570d7624
JB
1645 struct gcpro gcpro1, gcpro2;
1646
1647 GCPRO2 (filename, newname);
1648 CHECK_STRING (filename, 0);
1649 CHECK_STRING (newname, 1);
1650 filename = Fexpand_file_name (filename, Qnil);
1651 newname = Fexpand_file_name (newname, Qnil);
32f4334d
RS
1652
1653 /* If the file name has special constructs in it,
1654 call the corresponding file handler. */
1655 handler = find_file_handler (filename);
1656 if (!NILP (handler))
1657 return call3 (handler, Qadd_name_to_file, filename, newname);
1658
265a9e55 1659 if (NILP (ok_if_already_exists)
570d7624
JB
1660 || XTYPE (ok_if_already_exists) == Lisp_Int)
1661 barf_or_query_if_file_exists (newname, "make it a new name",
1662 XTYPE (ok_if_already_exists) == Lisp_Int);
1663 unlink (XSTRING (newname)->data);
1664 if (0 > link (XSTRING (filename)->data, XSTRING (newname)->data))
1665 {
1666#ifdef NO_ARG_ARRAY
1667 args[0] = filename;
1668 args[1] = newname;
1669 report_file_error ("Adding new name", Flist (2, args));
1670#else
1671 report_file_error ("Adding new name", Flist (2, &filename));
1672#endif
1673 }
1674
1675 UNGCPRO;
1676 return Qnil;
1677}
1678
1679#ifdef S_IFLNK
1680DEFUN ("make-symbolic-link", Fmake_symbolic_link, Smake_symbolic_link, 2, 3,
1681 "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",
1682 "Make a symbolic link to FILENAME, named LINKNAME. Both args strings.\n\
1683Signals a `file-already-exists' error if a file NEWNAME already exists\n\
1684unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.\n\
1685A number as third arg means request confirmation if NEWNAME already exists.\n\
1686This happens for interactive use with M-x.")
e5d77022
JB
1687 (filename, linkname, ok_if_already_exists)
1688 Lisp_Object filename, linkname, ok_if_already_exists;
570d7624
JB
1689{
1690#ifdef NO_ARG_ARRAY
1691 Lisp_Object args[2];
1692#endif
32f4334d 1693 Lisp_Object handler;
570d7624
JB
1694 struct gcpro gcpro1, gcpro2;
1695
e5d77022 1696 GCPRO2 (filename, linkname);
570d7624 1697 CHECK_STRING (filename, 0);
e5d77022 1698 CHECK_STRING (linkname, 1);
570d7624
JB
1699#if 0 /* This made it impossible to make a link to a relative name. */
1700 filename = Fexpand_file_name (filename, Qnil);
1701#endif
e5d77022 1702 linkname = Fexpand_file_name (linkname, Qnil);
32f4334d
RS
1703
1704 /* If the file name has special constructs in it,
1705 call the corresponding file handler. */
1706 handler = find_file_handler (filename);
1707 if (!NILP (handler))
3eac9910 1708 return call3 (handler, Qmake_symbolic_link, filename, linkname);
32f4334d 1709
265a9e55 1710 if (NILP (ok_if_already_exists)
570d7624 1711 || XTYPE (ok_if_already_exists) == Lisp_Int)
e5d77022 1712 barf_or_query_if_file_exists (linkname, "make it a link",
570d7624 1713 XTYPE (ok_if_already_exists) == Lisp_Int);
e5d77022 1714 if (0 > symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
1715 {
1716 /* If we didn't complain already, silently delete existing file. */
1717 if (errno == EEXIST)
1718 {
1719 unlink (XSTRING (filename)->data);
e5d77022 1720 if (0 <= symlink (XSTRING (filename)->data, XSTRING (linkname)->data))
570d7624
JB
1721 return Qnil;
1722 }
1723
1724#ifdef NO_ARG_ARRAY
1725 args[0] = filename;
e5d77022 1726 args[1] = linkname;
570d7624
JB
1727 report_file_error ("Making symbolic link", Flist (2, args));
1728#else
1729 report_file_error ("Making symbolic link", Flist (2, &filename));
1730#endif
1731 }
1732 UNGCPRO;
1733 return Qnil;
1734}
1735#endif /* S_IFLNK */
1736
1737#ifdef VMS
1738
1739DEFUN ("define-logical-name", Fdefine_logical_name, Sdefine_logical_name,
1740 2, 2, "sDefine logical name: \nsDefine logical name %s as: ",
1741 "Define the job-wide logical name NAME to have the value STRING.\n\
1742If STRING is nil or a null string, the logical name NAME is deleted.")
1743 (varname, string)
1744 Lisp_Object varname;
1745 Lisp_Object string;
1746{
1747 CHECK_STRING (varname, 0);
265a9e55 1748 if (NILP (string))
570d7624
JB
1749 delete_logical_name (XSTRING (varname)->data);
1750 else
1751 {
1752 CHECK_STRING (string, 1);
1753
1754 if (XSTRING (string)->size == 0)
1755 delete_logical_name (XSTRING (varname)->data);
1756 else
1757 define_logical_name (XSTRING (varname)->data, XSTRING (string)->data);
1758 }
1759
1760 return string;
1761}
1762#endif /* VMS */
1763
1764#ifdef HPUX_NET
1765
1766DEFUN ("sysnetunam", Fsysnetunam, Ssysnetunam, 2, 2, 0,
1767 "Open a network connection to PATH using LOGIN as the login string.")
1768 (path, login)
1769 Lisp_Object path, login;
1770{
1771 int netresult;
1772
1773 CHECK_STRING (path, 0);
1774 CHECK_STRING (login, 0);
1775
1776 netresult = netunam (XSTRING (path)->data, XSTRING (login)->data);
1777
1778 if (netresult == -1)
1779 return Qnil;
1780 else
1781 return Qt;
1782}
1783#endif /* HPUX_NET */
1784\f
1785DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolute_p,
1786 1, 1, 0,
1787 "Return t if file FILENAME specifies an absolute path name.\n\
1788On Unix, this is a name starting with a `/' or a `~'.")
1789 (filename)
1790 Lisp_Object filename;
1791{
1792 unsigned char *ptr;
1793
1794 CHECK_STRING (filename, 0);
1795 ptr = XSTRING (filename)->data;
1796 if (*ptr == '/' || *ptr == '~'
1797#ifdef VMS
1798/* ??? This criterion is probably wrong for '<'. */
1799 || index (ptr, ':') || index (ptr, '<')
1800 || (*ptr == '[' && (ptr[1] != '-' || (ptr[2] != '.' && ptr[2] != ']'))
1801 && ptr[1] != '.')
1802#endif /* VMS */
1803 )
1804 return Qt;
1805 else
1806 return Qnil;
1807}
1808
1809DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0,
1810 "Return t if file FILENAME exists. (This does not mean you can read it.)\n\
1811See also `file-readable-p' and `file-attributes'.")
1812 (filename)
1813 Lisp_Object filename;
1814{
1815 Lisp_Object abspath;
32f4334d 1816 Lisp_Object handler;
570d7624
JB
1817
1818 CHECK_STRING (filename, 0);
1819 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1820
1821 /* If the file name has special constructs in it,
1822 call the corresponding file handler. */
1823 handler = find_file_handler (filename);
1824 if (!NILP (handler))
1825 return call2 (handler, Qfile_exists_p, filename);
1826
570d7624
JB
1827 return (access (XSTRING (abspath)->data, 0) >= 0) ? Qt : Qnil;
1828}
1829
1830DEFUN ("file-executable-p", Ffile_executable_p, Sfile_executable_p, 1, 1, 0,
1831 "Return t if FILENAME can be executed by you.\n\
1832For directories this means you can change to that directory.")
1833 (filename)
1834 Lisp_Object filename;
1835
1836{
1837 Lisp_Object abspath;
32f4334d 1838 Lisp_Object handler;
570d7624
JB
1839
1840 CHECK_STRING (filename, 0);
1841 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1842
1843 /* If the file name has special constructs in it,
1844 call the corresponding file handler. */
1845 handler = find_file_handler (filename);
1846 if (!NILP (handler))
1847 return call2 (handler, Qfile_executable_p, filename);
1848
570d7624
JB
1849 return (access (XSTRING (abspath)->data, 1) >= 0) ? Qt : Qnil;
1850}
1851
1852DEFUN ("file-readable-p", Ffile_readable_p, Sfile_readable_p, 1, 1, 0,
1853 "Return t if file FILENAME exists and you can read it.\n\
1854See also `file-exists-p' and `file-attributes'.")
1855 (filename)
1856 Lisp_Object filename;
1857{
1858 Lisp_Object abspath;
32f4334d 1859 Lisp_Object handler;
570d7624
JB
1860
1861 CHECK_STRING (filename, 0);
1862 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1863
1864 /* If the file name has special constructs in it,
1865 call the corresponding file handler. */
1866 handler = find_file_handler (filename);
1867 if (!NILP (handler))
1868 return call2 (handler, Qfile_readable_p, filename);
1869
570d7624
JB
1870 return (access (XSTRING (abspath)->data, 4) >= 0) ? Qt : Qnil;
1871}
1872
1873DEFUN ("file-symlink-p", Ffile_symlink_p, Sfile_symlink_p, 1, 1, 0,
1874 "If file FILENAME is the name of a symbolic link\n\
1875returns the name of the file to which it is linked.\n\
1876Otherwise returns NIL.")
1877 (filename)
1878 Lisp_Object filename;
1879{
1880#ifdef S_IFLNK
1881 char *buf;
1882 int bufsize;
1883 int valsize;
1884 Lisp_Object val;
32f4334d 1885 Lisp_Object handler;
570d7624
JB
1886
1887 CHECK_STRING (filename, 0);
1888 filename = Fexpand_file_name (filename, Qnil);
1889
32f4334d
RS
1890 /* If the file name has special constructs in it,
1891 call the corresponding file handler. */
1892 handler = find_file_handler (filename);
1893 if (!NILP (handler))
1894 return call2 (handler, Qfile_symlink_p, filename);
1895
570d7624
JB
1896 bufsize = 100;
1897 while (1)
1898 {
1899 buf = (char *) xmalloc (bufsize);
1900 bzero (buf, bufsize);
1901 valsize = readlink (XSTRING (filename)->data, buf, bufsize);
1902 if (valsize < bufsize) break;
1903 /* Buffer was not long enough */
1904 free (buf);
1905 bufsize *= 2;
1906 }
1907 if (valsize == -1)
1908 {
1909 free (buf);
1910 return Qnil;
1911 }
1912 val = make_string (buf, valsize);
1913 free (buf);
1914 return val;
1915#else /* not S_IFLNK */
1916 return Qnil;
1917#endif /* not S_IFLNK */
1918}
1919
1920/* Having this before file-symlink-p mysteriously caused it to be forgotten
1921 on the RT/PC. */
1922DEFUN ("file-writable-p", Ffile_writable_p, Sfile_writable_p, 1, 1, 0,
1923 "Return t if file FILENAME can be written or created by you.")
1924 (filename)
1925 Lisp_Object filename;
1926{
1927 Lisp_Object abspath, dir;
32f4334d 1928 Lisp_Object handler;
570d7624
JB
1929
1930 CHECK_STRING (filename, 0);
1931 abspath = Fexpand_file_name (filename, Qnil);
32f4334d
RS
1932
1933 /* If the file name has special constructs in it,
1934 call the corresponding file handler. */
1935 handler = find_file_handler (filename);
1936 if (!NILP (handler))
1937 return call2 (handler, Qfile_writable_p, filename);
1938
570d7624
JB
1939 if (access (XSTRING (abspath)->data, 0) >= 0)
1940 return (access (XSTRING (abspath)->data, 2) >= 0) ? Qt : Qnil;
1941 dir = Ffile_name_directory (abspath);
1942#ifdef VMS
265a9e55 1943 if (!NILP (dir))
570d7624
JB
1944 dir = Fdirectory_file_name (dir);
1945#endif /* VMS */
265a9e55 1946 return (access (!NILP (dir) ? (char *) XSTRING (dir)->data : "", 2) >= 0
570d7624
JB
1947 ? Qt : Qnil);
1948}
1949
1950DEFUN ("file-directory-p", Ffile_directory_p, Sfile_directory_p, 1, 1, 0,
1951 "Return t if file FILENAME is the name of a directory as a file.\n\
1952A directory name spec may be given instead; then the value is t\n\
1953if the directory so specified exists and really is a directory.")
1954 (filename)
1955 Lisp_Object filename;
1956{
1957 register Lisp_Object abspath;
1958 struct stat st;
32f4334d 1959 Lisp_Object handler;
570d7624
JB
1960
1961 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
1962
32f4334d
RS
1963 /* If the file name has special constructs in it,
1964 call the corresponding file handler. */
1965 handler = find_file_handler (filename);
1966 if (!NILP (handler))
1967 return call2 (handler, Qfile_directory_p, filename);
1968
570d7624
JB
1969 if (stat (XSTRING (abspath)->data, &st) < 0)
1970 return Qnil;
1971 return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
1972}
1973
b72dea2a
JB
1974DEFUN ("file-accessible-directory-p", Ffile_accessible_directory_p, Sfile_accessible_directory_p, 1, 1, 0,
1975 "Return t if file FILENAME is the name of a directory as a file,\n\
1976and files in that directory can be opened by you. In order to use a\n\
1977directory as a buffer's current directory, this predicate must return true.\n\
1978A directory name spec may be given instead; then the value is t\n\
1979if the directory so specified exists and really is a readable and\n\
1980searchable directory.")
1981 (filename)
1982 Lisp_Object filename;
1983{
32f4334d
RS
1984 Lisp_Object handler;
1985
1986 /* If the file name has special constructs in it,
1987 call the corresponding file handler. */
1988 handler = find_file_handler (filename);
1989 if (!NILP (handler))
1990 return call2 (handler, Qfile_accessible_directory_p, filename);
1991
b72dea2a
JB
1992 if (NILP (Ffile_directory_p (filename))
1993 || NILP (Ffile_executable_p (filename)))
1994 return Qnil;
1995 else
1996 return Qt;
1997}
1998
570d7624
JB
1999DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2000 "Return mode bits of FILE, as an integer.")
2001 (filename)
2002 Lisp_Object filename;
2003{
2004 Lisp_Object abspath;
2005 struct stat st;
32f4334d 2006 Lisp_Object handler;
570d7624
JB
2007
2008 abspath = expand_and_dir_to_file (filename, current_buffer->directory);
2009
32f4334d
RS
2010 /* If the file name has special constructs in it,
2011 call the corresponding file handler. */
2012 handler = find_file_handler (filename);
2013 if (!NILP (handler))
2014 return call2 (handler, Qfile_modes, filename);
2015
570d7624
JB
2016 if (stat (XSTRING (abspath)->data, &st) < 0)
2017 return Qnil;
2018 return make_number (st.st_mode & 07777);
2019}
2020
2021DEFUN ("set-file-modes", Fset_file_modes, Sset_file_modes, 2, 2, 0,
2022 "Set mode bits of FILE to MODE (an integer).\n\
2023Only the 12 low bits of MODE are used.")
2024 (filename, mode)
2025 Lisp_Object filename, mode;
2026{
2027 Lisp_Object abspath;
32f4334d 2028 Lisp_Object handler;
570d7624
JB
2029
2030 abspath = Fexpand_file_name (filename, current_buffer->directory);
2031 CHECK_NUMBER (mode, 1);
2032
32f4334d
RS
2033 /* If the file name has special constructs in it,
2034 call the corresponding file handler. */
2035 handler = find_file_handler (filename);
2036 if (!NILP (handler))
2037 return call3 (handler, Qset_file_modes, filename, mode);
2038
570d7624
JB
2039#ifndef APOLLO
2040 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2041 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2042#else /* APOLLO */
2043 if (!egetenv ("USE_DOMAIN_ACLS"))
2044 {
2045 struct stat st;
2046 struct timeval tvp[2];
2047
2048 /* chmod on apollo also change the file's modtime; need to save the
2049 modtime and then restore it. */
2050 if (stat (XSTRING (abspath)->data, &st) < 0)
2051 {
2052 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2053 return (Qnil);
2054 }
2055
2056 if (chmod (XSTRING (abspath)->data, XINT (mode)) < 0)
2057 report_file_error ("Doing chmod", Fcons (abspath, Qnil));
2058
2059 /* reset the old accessed and modified times. */
2060 tvp[0].tv_sec = st.st_atime + 1; /* +1 due to an Apollo roundoff bug */
2061 tvp[0].tv_usec = 0;
2062 tvp[1].tv_sec = st.st_mtime + 1; /* +1 due to an Apollo roundoff bug */
2063 tvp[1].tv_usec = 0;
2064
2065 if (utimes (XSTRING (abspath)->data, tvp) < 0)
2066 report_file_error ("Doing utimes", Fcons (abspath, Qnil));
2067 }
2068#endif /* APOLLO */
2069
2070 return Qnil;
2071}
2072
36a8c287
JB
2073DEFUN ("set-umask", Fset_umask, Sset_umask, 1, 1, 0,
2074 "Select which permission bits to disable in newly created files.\n\
2075MASK should be an integer; if a permission's bit in MASK is 1,\n\
2076subsequently created files will not have that permission enabled.\n\
2077Only the low 9 bits are used.\n\
2078This setting is inherited by subprocesses.")
2079 (mask)
2080 Lisp_Object mask;
2081{
2082 CHECK_NUMBER (mask, 0);
2083
2084 umask (XINT (mask) & 0777);
2085
2086 return Qnil;
2087}
2088
2089DEFUN ("umask", Fumask, Sumask, 0, 0, 0,
2090 "Return the current umask value.\n\
2091The umask value determines which permissions are enabled in newly\n\
2092created files. If a permission's bit in the umask is 1, subsequently\n\
2093created files will not have that permission enabled.")
2094 ()
2095{
2096 Lisp_Object mask;
2097
2098 XSET (mask, Lisp_Int, umask (0));
2099 umask (XINT (mask));
2100
2101 return mask;
2102}
2103
85ffea93
RS
2104#ifdef unix
2105
2106DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2107 "Tell Unix to finish all pending disk updates.")
2108 ()
2109{
2110 sync ();
2111 return Qnil;
2112}
2113
2114#endif /* unix */
2115
570d7624
JB
2116DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2117 "Return t if file FILE1 is newer than file FILE2.\n\
2118If FILE1 does not exist, the answer is nil;\n\
2119otherwise, if FILE2 does not exist, the answer is t.")
2120 (file1, file2)
2121 Lisp_Object file1, file2;
2122{
32f4334d 2123 Lisp_Object abspath1, abspath2;
570d7624
JB
2124 struct stat st;
2125 int mtime1;
32f4334d 2126 Lisp_Object handler;
570d7624
JB
2127
2128 CHECK_STRING (file1, 0);
2129 CHECK_STRING (file2, 0);
2130
32f4334d
RS
2131 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2132 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
570d7624 2133
32f4334d
RS
2134 /* If the file name has special constructs in it,
2135 call the corresponding file handler. */
2136 handler = find_file_handler (abspath1);
2137 if (!NILP (handler))
2138 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2139
2140 if (stat (XSTRING (abspath1)->data, &st) < 0)
570d7624
JB
2141 return Qnil;
2142
2143 mtime1 = st.st_mtime;
2144
32f4334d 2145 if (stat (XSTRING (abspath2)->data, &st) < 0)
570d7624
JB
2146 return Qt;
2147
2148 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2149}
2150\f
570d7624
JB
2151DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
2152 1, 2, 0,
2153 "Insert contents of file FILENAME after point.\n\
2154Returns list of absolute pathname and length of data inserted.\n\
2155If second argument VISIT is non-nil, the buffer's visited filename\n\
2156and last save file modtime are set, and it is marked unmodified.\n\
2157If visiting and the file does not exist, visiting is completed\n\
2158before the error is signaled.")
2159 (filename, visit)
2160 Lisp_Object filename, visit;
2161{
2162 struct stat st;
2163 register int fd;
2164 register int inserted = 0;
2165 register int how_much;
2166 int count = specpdl_ptr - specpdl;
2167 struct gcpro gcpro1;
32f4334d
RS
2168 Lisp_Object handler, val;
2169
2170 val = Qnil;
2171
570d7624 2172 GCPRO1 (filename);
265a9e55 2173 if (!NILP (current_buffer->read_only))
570d7624
JB
2174 Fbarf_if_buffer_read_only();
2175
2176 CHECK_STRING (filename, 0);
2177 filename = Fexpand_file_name (filename, Qnil);
2178
32f4334d
RS
2179 /* If the file name has special constructs in it,
2180 call the corresponding file handler. */
2181 handler = find_file_handler (filename);
2182 if (!NILP (handler))
2183 {
2184 val = call3 (handler, Qinsert_file_contents, filename, visit);
2185 st.st_mtime = 0;
2186 goto handled;
2187 }
2188
570d7624
JB
2189 fd = -1;
2190
2191#ifndef APOLLO
2192 if (stat (XSTRING (filename)->data, &st) < 0
349a7710 2193 || (fd = open (XSTRING (filename)->data, 0)) < 0)
570d7624
JB
2194#else
2195 if ((fd = open (XSTRING (filename)->data, 0)) < 0
2196 || fstat (fd, &st) < 0)
2197#endif /* not APOLLO */
2198 {
2199 if (fd >= 0) close (fd);
265a9e55 2200 if (NILP (visit))
570d7624
JB
2201 report_file_error ("Opening input file", Fcons (filename, Qnil));
2202 st.st_mtime = -1;
2203 how_much = 0;
2204 goto notfound;
2205 }
2206
2207 record_unwind_protect (close_file_unwind, make_number (fd));
2208
be53b411
JB
2209#ifdef S_IFSOCK
2210 /* This code will need to be changed in order to work on named
2211 pipes, and it's probably just not worth it. So we should at
2212 least signal an error. */
2213 if ((st.st_mode & S_IFMT) == S_IFSOCK)
2214 Fsignal (Qfile_error,
2215 Fcons (build_string ("reading from named pipe"),
2216 Fcons (filename, Qnil)));
2217#endif
2218
570d7624
JB
2219 /* Supposedly happens on VMS. */
2220 if (st.st_size < 0)
2221 error ("File size is negative");
be53b411 2222
570d7624
JB
2223 {
2224 register Lisp_Object temp;
2225
2226 /* Make sure point-max won't overflow after this insertion. */
2227 XSET (temp, Lisp_Int, st.st_size + Z);
2228 if (st.st_size + Z != XINT (temp))
2229 error ("maximum buffer size exceeded");
2230 }
2231
265a9e55 2232 if (NILP (visit))
570d7624
JB
2233 prepare_to_modify_buffer (point, point);
2234
2235 move_gap (point);
2236 if (GAP_SIZE < st.st_size)
2237 make_gap (st.st_size - GAP_SIZE);
2238
2239 while (1)
2240 {
2241 int try = min (st.st_size - inserted, 64 << 10);
b5148e85
RS
2242 int this;
2243
2244 /* Allow quitting out of the actual I/O. */
2245 immediate_quit = 1;
2246 QUIT;
2247 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2248 immediate_quit = 0;
570d7624
JB
2249
2250 if (this <= 0)
2251 {
2252 how_much = this;
2253 break;
2254 }
2255
2256 GPT += this;
2257 GAP_SIZE -= this;
2258 ZV += this;
2259 Z += this;
2260 inserted += this;
2261 }
2262
2263 if (inserted > 0)
2264 MODIFF++;
2265 record_insert (point, inserted);
2266
2267 close (fd);
2268
2269 /* Discard the unwind protect */
2270 specpdl_ptr = specpdl + count;
2271
2272 if (how_much < 0)
2273 error ("IO error reading %s: %s",
2274 XSTRING (filename)->data, err_str (errno));
2275
2276 notfound:
32f4334d 2277 handled:
570d7624 2278
265a9e55 2279 if (!NILP (visit))
570d7624
JB
2280 {
2281 current_buffer->undo_list = Qnil;
2282#ifdef APOLLO
2283 stat (XSTRING (filename)->data, &st);
2284#endif
2285 current_buffer->modtime = st.st_mtime;
2286 current_buffer->save_modified = MODIFF;
2287 current_buffer->auto_save_modified = MODIFF;
2288 XFASTINT (current_buffer->save_length) = Z - BEG;
2289#ifdef CLASH_DETECTION
32f4334d
RS
2290 if (NILP (handler))
2291 {
2292 if (!NILP (current_buffer->filename))
2293 unlock_file (current_buffer->filename);
2294 unlock_file (filename);
2295 }
570d7624
JB
2296#endif /* CLASH_DETECTION */
2297 current_buffer->filename = filename;
2298 /* If visiting nonexistent file, return nil. */
32f4334d 2299 if (current_buffer->modtime == -1)
570d7624
JB
2300 report_file_error ("Opening input file", Fcons (filename, Qnil));
2301 }
2302
2303 signal_after_change (point, 0, inserted);
2304
32f4334d
RS
2305 if (!NILP (val))
2306 RETURN_UNGCPRO (val);
9b7828a5
JB
2307 RETURN_UNGCPRO (Fcons (filename,
2308 Fcons (make_number (inserted),
2309 Qnil)));
570d7624
JB
2310}
2311
2312DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2313 "r\nFWrite region to file: ",
2314 "Write current region into specified file.\n\
2315When called from a program, takes three arguments:\n\
2316START, END and FILENAME. START and END are buffer positions.\n\
2317Optional fourth argument APPEND if non-nil means\n\
2318 append to existing file contents (if any).\n\
2319Optional fifth argument VISIT if t means\n\
2320 set the last-save-file-modtime of buffer to this file's modtime\n\
2321 and mark buffer not modified.\n\
2322If VISIT is neither t nor nil, it means do not print\n\
2323 the \"Wrote file\" message.\n\
2324Kludgy feature: if START is a string, then that string is written\n\
2325to the file, instead of any buffer contents, and END is ignored.")
2326 (start, end, filename, append, visit)
2327 Lisp_Object start, end, filename, append, visit;
2328{
2329 register int desc;
2330 int failure;
2331 int save_errno;
2332 unsigned char *fn;
2333 struct stat st;
2334 int tem;
2335 int count = specpdl_ptr - specpdl;
2336#ifdef VMS
2337 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
2338#endif /* VMS */
3eac9910 2339 Lisp_Object handler;
570d7624
JB
2340
2341 /* Special kludge to simplify auto-saving */
265a9e55 2342 if (NILP (start))
570d7624
JB
2343 {
2344 XFASTINT (start) = BEG;
2345 XFASTINT (end) = Z;
2346 }
2347 else if (XTYPE (start) != Lisp_String)
2348 validate_region (&start, &end);
2349
2350 filename = Fexpand_file_name (filename, Qnil);
2351 fn = XSTRING (filename)->data;
2352
32f4334d
RS
2353 /* If the file name has special constructs in it,
2354 call the corresponding file handler. */
2355 handler = find_file_handler (filename);
3eac9910 2356
32f4334d
RS
2357 if (!NILP (handler))
2358 {
2359 Lisp_Object args[7];
2360 Lisp_Object val;
2361 args[0] = handler;
2362 args[1] = Qwrite_region;
2363 args[2] = start;
2364 args[3] = end;
2365 args[4] = filename;
2366 args[5] = append;
2367 args[6] = visit;
2368 val = Ffuncall (7, args);
2369
2370 /* Do this before reporting IO error
2371 to avoid a "file has changed on disk" warning on
2372 next attempt to save. */
2373 if (EQ (visit, Qt))
2374 {
2375 current_buffer->modtime = 0;
2376 current_buffer->save_modified = MODIFF;
2377 XFASTINT (current_buffer->save_length) = Z - BEG;
2378 current_buffer->filename = filename;
2379 }
2380 return val;
2381 }
2382
570d7624
JB
2383#ifdef CLASH_DETECTION
2384 if (!auto_saving)
2385 lock_file (filename);
2386#endif /* CLASH_DETECTION */
2387
2388 desc = -1;
265a9e55 2389 if (!NILP (append))
570d7624
JB
2390 desc = open (fn, O_WRONLY);
2391
2392 if (desc < 0)
2393#ifdef VMS
2394 if (auto_saving) /* Overwrite any previous version of autosave file */
2395 {
2396 vms_truncate (fn); /* if fn exists, truncate to zero length */
2397 desc = open (fn, O_RDWR);
2398 if (desc < 0)
2399 desc = creat_copy_attrs (XTYPE (current_buffer->filename) == Lisp_String
b72dea2a
JB
2400 ? XSTRING (current_buffer->filename)->data : 0,
2401 fn);
570d7624
JB
2402 }
2403 else /* Write to temporary name and rename if no errors */
2404 {
2405 Lisp_Object temp_name;
2406 temp_name = Ffile_name_directory (filename);
2407
265a9e55 2408 if (!NILP (temp_name))
570d7624
JB
2409 {
2410 temp_name = Fmake_temp_name (concat2 (temp_name,
2411 build_string ("$$SAVE$$")));
2412 fname = XSTRING (filename)->data;
2413 fn = XSTRING (temp_name)->data;
2414 desc = creat_copy_attrs (fname, fn);
2415 if (desc < 0)
2416 {
2417 /* If we can't open the temporary file, try creating a new
2418 version of the original file. VMS "creat" creates a
2419 new version rather than truncating an existing file. */
2420 fn = fname;
2421 fname = 0;
2422 desc = creat (fn, 0666);
2423#if 0 /* This can clobber an existing file and fail to replace it,
2424 if the user runs out of space. */
2425 if (desc < 0)
2426 {
2427 /* We can't make a new version;
2428 try to truncate and rewrite existing version if any. */
2429 vms_truncate (fn);
2430 desc = open (fn, O_RDWR);
2431 }
2432#endif
2433 }
2434 }
2435 else
2436 desc = creat (fn, 0666);
2437 }
2438#else /* not VMS */
2439 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
2440#endif /* not VMS */
2441
2442 if (desc < 0)
2443 {
2444#ifdef CLASH_DETECTION
2445 save_errno = errno;
2446 if (!auto_saving) unlock_file (filename);
2447 errno = save_errno;
2448#endif /* CLASH_DETECTION */
2449 report_file_error ("Opening output file", Fcons (filename, Qnil));
2450 }
2451
2452 record_unwind_protect (close_file_unwind, make_number (desc));
2453
265a9e55 2454 if (!NILP (append))
570d7624
JB
2455 if (lseek (desc, 0, 2) < 0)
2456 {
2457#ifdef CLASH_DETECTION
2458 if (!auto_saving) unlock_file (filename);
2459#endif /* CLASH_DETECTION */
2460 report_file_error ("Lseek error", Fcons (filename, Qnil));
2461 }
2462
2463#ifdef VMS
2464/*
2465 * Kludge Warning: The VMS C RTL likes to insert carriage returns
2466 * if we do writes that don't end with a carriage return. Furthermore
2467 * it cannot handle writes of more then 16K. The modified
2468 * version of "sys_write" in SYSDEP.C (see comment there) copes with
2469 * this EXCEPT for the last record (iff it doesn't end with a carriage
2470 * return). This implies that if your buffer doesn't end with a carriage
2471 * return, you get one free... tough. However it also means that if
2472 * we make two calls to sys_write (a la the following code) you can
2473 * get one at the gap as well. The easiest way to fix this (honest)
2474 * is to move the gap to the next newline (or the end of the buffer).
2475 * Thus this change.
2476 *
2477 * Yech!
2478 */
2479 if (GPT > BEG && GPT_ADDR[-1] != '\n')
2480 move_gap (find_next_newline (GPT, 1));
2481#endif
2482
2483 failure = 0;
2484 immediate_quit = 1;
2485
2486 if (XTYPE (start) == Lisp_String)
2487 {
2488 failure = 0 > e_write (desc, XSTRING (start)->data,
2489 XSTRING (start)->size);
2490 save_errno = errno;
2491 }
2492 else if (XINT (start) != XINT (end))
2493 {
2494 if (XINT (start) < GPT)
2495 {
2496 register int end1 = XINT (end);
2497 tem = XINT (start);
2498 failure = 0 > e_write (desc, &FETCH_CHAR (tem),
2499 min (GPT, end1) - tem);
2500 save_errno = errno;
2501 }
2502
2503 if (XINT (end) > GPT && !failure)
2504 {
2505 tem = XINT (start);
2506 tem = max (tem, GPT);
2507 failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem);
2508 save_errno = errno;
2509 }
2510 }
2511
2512 immediate_quit = 0;
2513
2514#ifndef USG
2515#ifndef VMS
2516#ifndef BSD4_1
570d7624
JB
2517 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
2518 Disk full in NFS may be reported here. */
2519 if (fsync (desc) < 0)
2520 failure = 1, save_errno = errno;
2521#endif
2522#endif
570d7624
JB
2523#endif
2524
2525 /* Spurious "file has changed on disk" warnings have been
2526 observed on Suns as well.
2527 It seems that `close' can change the modtime, under nfs.
2528
2529 (This has supposedly been fixed in Sunos 4,
2530 but who knows about all the other machines with NFS?) */
2531#if 0
2532
2533 /* On VMS and APOLLO, must do the stat after the close
2534 since closing changes the modtime. */
2535#ifndef VMS
2536#ifndef APOLLO
2537 /* Recall that #if defined does not work on VMS. */
2538#define FOO
2539 fstat (desc, &st);
2540#endif
2541#endif
2542#endif
2543
2544 /* NFS can report a write failure now. */
2545 if (close (desc) < 0)
2546 failure = 1, save_errno = errno;
2547
2548#ifdef VMS
2549 /* If we wrote to a temporary name and had no errors, rename to real name. */
2550 if (fname)
2551 {
2552 if (!failure)
2553 failure = (rename (fn, fname) != 0), save_errno = errno;
2554 fn = fname;
2555 }
2556#endif /* VMS */
2557
2558#ifndef FOO
2559 stat (fn, &st);
2560#endif
2561 /* Discard the unwind protect */
2562 specpdl_ptr = specpdl + count;
2563
2564#ifdef CLASH_DETECTION
2565 if (!auto_saving)
2566 unlock_file (filename);
2567#endif /* CLASH_DETECTION */
2568
2569 /* Do this before reporting IO error
2570 to avoid a "file has changed on disk" warning on
2571 next attempt to save. */
2572 if (EQ (visit, Qt))
2573 current_buffer->modtime = st.st_mtime;
2574
2575 if (failure)
2576 error ("IO error writing %s: %s", fn, err_str (save_errno));
2577
2578 if (EQ (visit, Qt))
2579 {
2580 current_buffer->save_modified = MODIFF;
2581 XFASTINT (current_buffer->save_length) = Z - BEG;
2582 current_buffer->filename = filename;
2583 }
265a9e55 2584 else if (!NILP (visit))
570d7624
JB
2585 return Qnil;
2586
2587 if (!auto_saving)
2588 message ("Wrote %s", fn);
2589
2590 return Qnil;
2591}
2592
2593int
2594e_write (desc, addr, len)
2595 int desc;
2596 register char *addr;
2597 register int len;
2598{
2599 char buf[16 * 1024];
2600 register char *p, *end;
2601
2602 if (!EQ (current_buffer->selective_display, Qt))
2603 return write (desc, addr, len) - len;
2604 else
2605 {
2606 p = buf;
2607 end = p + sizeof buf;
2608 while (len--)
2609 {
2610 if (p == end)
2611 {
2612 if (write (desc, buf, sizeof buf) != sizeof buf)
2613 return -1;
2614 p = buf;
2615 }
2616 *p = *addr++;
2617 if (*p++ == '\015')
2618 p[-1] = '\n';
2619 }
2620 if (p != buf)
2621 if (write (desc, buf, p - buf) != p - buf)
2622 return -1;
2623 }
2624 return 0;
2625}
2626
2627DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
2628 Sverify_visited_file_modtime, 1, 1, 0,
2629 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
2630This means that the file has not been changed since it was visited or saved.")
2631 (buf)
2632 Lisp_Object buf;
2633{
2634 struct buffer *b;
2635 struct stat st;
32f4334d 2636 Lisp_Object handler;
570d7624
JB
2637
2638 CHECK_BUFFER (buf, 0);
2639 b = XBUFFER (buf);
2640
2641 if (XTYPE (b->filename) != Lisp_String) return Qt;
2642 if (b->modtime == 0) return Qt;
2643
32f4334d
RS
2644 /* If the file name has special constructs in it,
2645 call the corresponding file handler. */
3eac9910 2646 handler = find_file_handler (b->filename);
32f4334d 2647 if (!NILP (handler))
3eac9910 2648 return call2 (handler, Qverify_visited_file_modtime, b->filename);
32f4334d 2649
570d7624
JB
2650 if (stat (XSTRING (b->filename)->data, &st) < 0)
2651 {
2652 /* If the file doesn't exist now and didn't exist before,
2653 we say that it isn't modified, provided the error is a tame one. */
2654 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
2655 st.st_mtime = -1;
2656 else
2657 st.st_mtime = 0;
2658 }
2659 if (st.st_mtime == b->modtime
2660 /* If both are positive, accept them if they are off by one second. */
2661 || (st.st_mtime > 0 && b->modtime > 0
2662 && (st.st_mtime == b->modtime + 1
2663 || st.st_mtime == b->modtime - 1)))
2664 return Qt;
2665 return Qnil;
2666}
2667
2668DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
2669 Sclear_visited_file_modtime, 0, 0, 0,
2670 "Clear out records of last mod time of visited file.\n\
2671Next attempt to save will certainly not complain of a discrepancy.")
2672 ()
2673{
2674 current_buffer->modtime = 0;
2675 return Qnil;
2676}
2677
2678DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
2679 Sset_visited_file_modtime, 0, 0, 0,
2680 "Update buffer's recorded modification time from the visited file's time.\n\
2681Useful if the buffer was not read from the file normally\n\
2682or if the file itself has been changed for some known benign reason.")
2683 ()
2684{
2685 register Lisp_Object filename;
2686 struct stat st;
3eac9910 2687 Lisp_Object handler;
570d7624
JB
2688
2689 filename = Fexpand_file_name (current_buffer->filename, Qnil);
32f4334d
RS
2690
2691 /* If the file name has special constructs in it,
2692 call the corresponding file handler. */
2693 handler = find_file_handler (filename);
2694 if (!NILP (handler))
2695 current_buffer->modtime = 0;
570d7624 2696
32f4334d 2697 else if (stat (XSTRING (filename)->data, &st) >= 0)
570d7624
JB
2698 current_buffer->modtime = st.st_mtime;
2699
2700 return Qnil;
2701}
2702\f
2703Lisp_Object
2704auto_save_error ()
2705{
2706 unsigned char *name = XSTRING (current_buffer->name)->data;
2707
2708 ring_bell ();
2709 message ("Autosaving...error for %s", name);
de49a6d3 2710 Fsleep_for (make_number (1), Qnil);
570d7624 2711 message ("Autosaving...error!for %s", name);
de49a6d3 2712 Fsleep_for (make_number (1), Qnil);
570d7624 2713 message ("Autosaving...error for %s", name);
de49a6d3 2714 Fsleep_for (make_number (1), Qnil);
570d7624
JB
2715 return Qnil;
2716}
2717
2718Lisp_Object
2719auto_save_1 ()
2720{
2721 unsigned char *fn;
2722 struct stat st;
2723
2724 /* Get visited file's mode to become the auto save file's mode. */
2725 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
2726 /* But make sure we can overwrite it later! */
2727 auto_save_mode_bits = st.st_mode | 0600;
2728 else
2729 auto_save_mode_bits = 0666;
2730
2731 return
2732 Fwrite_region (Qnil, Qnil,
2733 current_buffer->auto_save_file_name,
2734 Qnil, Qlambda);
2735}
2736
2737DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
2738 "Auto-save all buffers that need it.\n\
2739This is all buffers that have auto-saving enabled\n\
2740and are changed since last auto-saved.\n\
2741Auto-saving writes the buffer into a file\n\
2742so that your editing is not lost if the system crashes.\n\
2743This file is not the file you visited; that changes only when you save.\n\n\
2744Non-nil first argument means do not print any message if successful.\n\
4746118a 2745Non-nil second argument means save only current buffer.")
570d7624
JB
2746 (nomsg)
2747 Lisp_Object nomsg;
2748{
2749 struct buffer *old = current_buffer, *b;
2750 Lisp_Object tail, buf;
2751 int auto_saved = 0;
2752 char *omessage = echo_area_glyphs;
2753 extern minibuf_level;
2754
2755 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
2756 point to non-strings reached from Vbuffer_alist. */
2757
2758 auto_saving = 1;
2759 if (minibuf_level)
2760 nomsg = Qt;
2761
2762 /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
2763 eventually call do-auto-save, so don't err here in that case. */
265a9e55 2764 if (!NILP (Vrun_hooks))
570d7624
JB
2765 call1 (Vrun_hooks, intern ("auto-save-hook"));
2766
2767 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
2768 tail = XCONS (tail)->cdr)
2769 {
2770 buf = XCONS (XCONS (tail)->car)->cdr;
2771 b = XBUFFER (buf);
2772 /* Check for auto save enabled
2773 and file changed since last auto save
2774 and file changed since last real save. */
2775 if (XTYPE (b->auto_save_file_name) == Lisp_String
2776 && b->save_modified < BUF_MODIFF (b)
2777 && b->auto_save_modified < BUF_MODIFF (b))
2778 {
2779 if ((XFASTINT (b->save_length) * 10
2780 > (BUF_Z (b) - BUF_BEG (b)) * 13)
2781 /* A short file is likely to change a large fraction;
2782 spare the user annoying messages. */
2783 && XFASTINT (b->save_length) > 5000
2784 /* These messages are frequent and annoying for `*mail*'. */
2785 && !EQ (b->filename, Qnil))
2786 {
2787 /* It has shrunk too much; turn off auto-saving here. */
2788 message ("Buffer %s has shrunk a lot; auto save turned off there",
2789 XSTRING (b->name)->data);
2790 /* User can reenable saving with M-x auto-save. */
2791 b->auto_save_file_name = Qnil;
2792 /* Prevent warning from repeating if user does so. */
2793 XFASTINT (b->save_length) = 0;
2794 Fsleep_for (make_number (1));
2795 continue;
2796 }
2797 set_buffer_internal (b);
265a9e55 2798 if (!auto_saved && NILP (nomsg))
570d7624
JB
2799 message1 ("Auto-saving...");
2800 internal_condition_case (auto_save_1, Qt, auto_save_error);
2801 auto_saved++;
2802 b->auto_save_modified = BUF_MODIFF (b);
2803 XFASTINT (current_buffer->save_length) = Z - BEG;
2804 set_buffer_internal (old);
2805 }
2806 }
2807
2808 if (auto_saved)
2809 record_auto_save ();
2810
265a9e55 2811 if (auto_saved && NILP (nomsg))
570d7624
JB
2812 message1 (omessage ? omessage : "Auto-saving...done");
2813
2814 auto_saving = 0;
2815 return Qnil;
2816}
2817
2818DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
2819 Sset_buffer_auto_saved, 0, 0, 0,
2820 "Mark current buffer as auto-saved with its current text.\n\
2821No auto-save file will be written until the buffer changes again.")
2822 ()
2823{
2824 current_buffer->auto_save_modified = MODIFF;
2825 XFASTINT (current_buffer->save_length) = Z - BEG;
2826 return Qnil;
2827}
2828
2829DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
2830 0, 0, 0,
2831 "Return t if buffer has been auto-saved since last read in or saved.")
2832 ()
2833{
2834 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
2835}
2836\f
2837/* Reading and completing file names */
2838extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
2839
2840DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
2841 3, 3, 0,
2842 "Internal subroutine for read-file-name. Do not call this.")
2843 (string, dir, action)
2844 Lisp_Object string, dir, action;
2845 /* action is nil for complete, t for return list of completions,
2846 lambda for verify final value */
2847{
2848 Lisp_Object name, specdir, realdir, val, orig_string;
2849
2850 if (XSTRING (string)->size == 0)
2851 {
2852 orig_string = Qnil;
2853 name = string;
2854 realdir = dir;
2855 if (EQ (action, Qlambda))
2856 return Qnil;
2857 }
2858 else
2859 {
2860 orig_string = string;
2861 string = Fsubstitute_in_file_name (string);
2862 name = Ffile_name_nondirectory (string);
2863 realdir = Ffile_name_directory (string);
265a9e55 2864 if (NILP (realdir))
570d7624
JB
2865 realdir = dir;
2866 else
2867 realdir = Fexpand_file_name (realdir, dir);
2868 }
2869
265a9e55 2870 if (NILP (action))
570d7624
JB
2871 {
2872 specdir = Ffile_name_directory (string);
2873 val = Ffile_name_completion (name, realdir);
2874 if (XTYPE (val) != Lisp_String)
2875 {
265a9e55 2876 if (NILP (Fstring_equal (string, orig_string)))
570d7624
JB
2877 return string;
2878 return (val);
2879 }
2880
265a9e55 2881 if (!NILP (specdir))
570d7624
JB
2882 val = concat2 (specdir, val);
2883#ifndef VMS
2884 {
2885 register unsigned char *old, *new;
2886 register int n;
2887 int osize, count;
2888
2889 osize = XSTRING (val)->size;
2890 /* Quote "$" as "$$" to get it past substitute-in-file-name */
2891 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
2892 if (*old++ == '$') count++;
2893 if (count > 0)
2894 {
2895 old = XSTRING (val)->data;
2896 val = Fmake_string (make_number (osize + count), make_number (0));
2897 new = XSTRING (val)->data;
2898 for (n = osize; n > 0; n--)
2899 if (*old != '$')
2900 *new++ = *old++;
2901 else
2902 {
2903 *new++ = '$';
2904 *new++ = '$';
2905 old++;
2906 }
2907 }
2908 }
2909#endif /* Not VMS */
2910 return (val);
2911 }
2912
2913 if (EQ (action, Qt))
2914 return Ffile_name_all_completions (name, realdir);
2915 /* Only other case actually used is ACTION = lambda */
2916#ifdef VMS
2917 /* Supposedly this helps commands such as `cd' that read directory names,
2918 but can someone explain how it helps them? -- RMS */
2919 if (XSTRING (name)->size == 0)
2920 return Qt;
2921#endif /* VMS */
2922 return Ffile_exists_p (string);
2923}
2924
2925DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
2926 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
2927Value is not expanded---you must call `expand-file-name' yourself.\n\
2928Default name to DEFAULT if user enters a null string.\n\
2929 (If DEFAULT is omitted, the visited file name is used.)\n\
2930Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
2931 Non-nil and non-t means also require confirmation after completion.\n\
2932Fifth arg INITIAL specifies text to start with.\n\
2933DIR defaults to current buffer's directory default.")
2934 (prompt, dir, defalt, mustmatch, initial)
2935 Lisp_Object prompt, dir, defalt, mustmatch, initial;
2936{
2937 Lisp_Object val, insdef, tem, backup_n;
2938 struct gcpro gcpro1, gcpro2;
2939 register char *homedir;
2940 int count;
2941
265a9e55 2942 if (NILP (dir))
570d7624 2943 dir = current_buffer->directory;
265a9e55 2944 if (NILP (defalt))
570d7624
JB
2945 defalt = current_buffer->filename;
2946
2947 /* If dir starts with user's homedir, change that to ~. */
2948 homedir = (char *) egetenv ("HOME");
2949 if (homedir != 0
2950 && XTYPE (dir) == Lisp_String
2951 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
2952 && XSTRING (dir)->data[strlen (homedir)] == '/')
2953 {
2954 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
2955 XSTRING (dir)->size - strlen (homedir) + 1);
2956 XSTRING (dir)->data[0] = '~';
2957 }
2958
2959 if (insert_default_directory)
2960 {
2961 insdef = dir;
265a9e55 2962 if (!NILP (initial))
570d7624
JB
2963 {
2964 Lisp_Object args[2];
2965
2966 args[0] = insdef;
2967 args[1] = initial;
2968 insdef = Fconcat (2, args);
2969 backup_n = make_number (- (XSTRING (initial)->size));
2970 }
2971 else
2972 backup_n = Qnil;
2973 }
2974 else
2975 {
2976 insdef = build_string ("");
2977 backup_n = Qnil;
2978 }
2979
2980#ifdef VMS
2981 count = specpdl_ptr - specpdl;
2982 specbind (intern ("completion-ignore-case"), Qt);
2983#endif
2984
2985 GCPRO2 (insdef, defalt);
2986 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
2987 dir, mustmatch,
2988 insert_default_directory ? insdef : Qnil, backup_n);
2989
2990#ifdef VMS
2991 unbind_to (count, Qnil);
2992#endif
2993
2994 UNGCPRO;
265a9e55 2995 if (NILP (val))
570d7624
JB
2996 error ("No file name specified");
2997 tem = Fstring_equal (val, insdef);
265a9e55 2998 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
2999 return defalt;
3000 return Fsubstitute_in_file_name (val);
3001}
3002
3003#if 0 /* Old version */
3004DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3005 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3006Value is not expanded---you must call `expand-file-name' yourself.\n\
3007Default name to DEFAULT if user enters a null string.\n\
3008 (If DEFAULT is omitted, the visited file name is used.)\n\
3009Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3010 Non-nil and non-t means also require confirmation after completion.\n\
3011Fifth arg INITIAL specifies text to start with.\n\
3012DIR defaults to current buffer's directory default.")
3013 (prompt, dir, defalt, mustmatch, initial)
3014 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3015{
3016 Lisp_Object val, insdef, tem;
3017 struct gcpro gcpro1, gcpro2;
3018 register char *homedir;
3019 int count;
3020
265a9e55 3021 if (NILP (dir))
570d7624 3022 dir = current_buffer->directory;
265a9e55 3023 if (NILP (defalt))
570d7624
JB
3024 defalt = current_buffer->filename;
3025
3026 /* If dir starts with user's homedir, change that to ~. */
3027 homedir = (char *) egetenv ("HOME");
3028 if (homedir != 0
3029 && XTYPE (dir) == Lisp_String
3030 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3031 && XSTRING (dir)->data[strlen (homedir)] == '/')
3032 {
3033 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3034 XSTRING (dir)->size - strlen (homedir) + 1);
3035 XSTRING (dir)->data[0] = '~';
3036 }
3037
265a9e55 3038 if (!NILP (initial))
570d7624
JB
3039 insdef = initial;
3040 else if (insert_default_directory)
3041 insdef = dir;
3042 else
3043 insdef = build_string ("");
3044
3045#ifdef VMS
3046 count = specpdl_ptr - specpdl;
3047 specbind (intern ("completion-ignore-case"), Qt);
3048#endif
3049
3050 GCPRO2 (insdef, defalt);
3051 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3052 dir, mustmatch,
3053 insert_default_directory ? insdef : Qnil, Qnil);
3054
3055#ifdef VMS
3056 unbind_to (count, Qnil);
3057#endif
3058
3059 UNGCPRO;
265a9e55 3060 if (NILP (val))
570d7624
JB
3061 error ("No file name specified");
3062 tem = Fstring_equal (val, insdef);
265a9e55 3063 if (!NILP (tem) && !NILP (defalt))
570d7624
JB
3064 return defalt;
3065 return Fsubstitute_in_file_name (val);
3066}
3067#endif /* Old version */
3068\f
3069syms_of_fileio ()
3070{
32f4334d
RS
3071 Qcopy_file = intern ("copy-file");
3072 Qmake_directory = intern ("make-directory");
3073 Qdelete_directory = intern ("delete-directory");
3074 Qdelete_file = intern ("delete-file");
3075 Qrename_file = intern ("rename-file");
3076 Qadd_name_to_file = intern ("add-name-to-file");
3077 Qmake_symbolic_link = intern ("make-symbolic-link");
3078 Qfile_exists_p = intern ("file-exists-p");
3079 Qfile_executable_p = intern ("file-executable-p");
3080 Qfile_readable_p = intern ("file-readable-p");
3081 Qfile_symlink_p = intern ("file-symlink-p");
3082 Qfile_writable_p = intern ("file-writable-p");
3083 Qfile_directory_p = intern ("file-directory-p");
3084 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
3085 Qfile_modes = intern ("file-modes");
3086 Qset_file_modes = intern ("set-file-modes");
3087 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
3088 Qinsert_file_contents = intern ("insert-file-contents");
3089 Qwrite_region = intern ("write-region");
3090 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3091
570d7624
JB
3092 Qfile_error = intern ("file-error");
3093 staticpro (&Qfile_error);
3094 Qfile_already_exists = intern("file-already-exists");
3095 staticpro (&Qfile_already_exists);
3096
3097 Fput (Qfile_error, Qerror_conditions,
3098 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
3099 Fput (Qfile_error, Qerror_message,
3100 build_string ("File error"));
3101
3102 Fput (Qfile_already_exists, Qerror_conditions,
3103 Fcons (Qfile_already_exists,
3104 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
3105 Fput (Qfile_already_exists, Qerror_message,
3106 build_string ("File already exists"));
3107
3108 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
3109 "*Non-nil means when reading a filename start with default dir in minibuffer.");
3110 insert_default_directory = 1;
3111
3112 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
3113 "*Non-nil means write new files with record format `stmlf'.\n\
3114nil means use format `var'. This variable is meaningful only on VMS.");
3115 vms_stmlf_recfm = 0;
3116
3117 defsubr (&Sfile_name_directory);
3118 defsubr (&Sfile_name_nondirectory);
3119 defsubr (&Sfile_name_as_directory);
3120 defsubr (&Sdirectory_file_name);
3121 defsubr (&Smake_temp_name);
3122 defsubr (&Sexpand_file_name);
3123 defsubr (&Ssubstitute_in_file_name);
3124 defsubr (&Scopy_file);
3125 defsubr (&Smake_directory);
aa734e17 3126 defsubr (&Sdelete_directory);
570d7624
JB
3127 defsubr (&Sdelete_file);
3128 defsubr (&Srename_file);
3129 defsubr (&Sadd_name_to_file);
3130#ifdef S_IFLNK
3131 defsubr (&Smake_symbolic_link);
3132#endif /* S_IFLNK */
3133#ifdef VMS
3134 defsubr (&Sdefine_logical_name);
3135#endif /* VMS */
3136#ifdef HPUX_NET
3137 defsubr (&Ssysnetunam);
3138#endif /* HPUX_NET */
3139 defsubr (&Sfile_name_absolute_p);
3140 defsubr (&Sfile_exists_p);
3141 defsubr (&Sfile_executable_p);
3142 defsubr (&Sfile_readable_p);
3143 defsubr (&Sfile_writable_p);
3144 defsubr (&Sfile_symlink_p);
3145 defsubr (&Sfile_directory_p);
b72dea2a 3146 defsubr (&Sfile_accessible_directory_p);
570d7624
JB
3147 defsubr (&Sfile_modes);
3148 defsubr (&Sset_file_modes);
36a8c287
JB
3149 defsubr (&Sset_umask);
3150 defsubr (&Sumask);
570d7624
JB
3151 defsubr (&Sfile_newer_than_file_p);
3152 defsubr (&Sinsert_file_contents);
3153 defsubr (&Swrite_region);
3154 defsubr (&Sverify_visited_file_modtime);
3155 defsubr (&Sclear_visited_file_modtime);
3156 defsubr (&Sset_visited_file_modtime);
3157 defsubr (&Sdo_auto_save);
3158 defsubr (&Sset_buffer_auto_saved);
3159 defsubr (&Srecent_auto_save_p);
3160
3161 defsubr (&Sread_file_name_internal);
3162 defsubr (&Sread_file_name);
85ffea93
RS
3163
3164 defsubr (&Sunix_sync);
570d7624 3165}