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