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