]> code.delx.au - gnu-emacs/blob - src/fileio.c
(Fset_default_file_mode, Fdefault_file_mode):
[gnu-emacs] / 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-default-file-mode", Fset_default_file_mode, Sset_default_file_mode, 1, 1, 0,
2182 "Set the file permission bits for newly created files.\n\
2183 The argument MODE should be an integer; only the low 9 bits are used.\n\
2184 This setting is inherited by subprocesses.")
2185 (mode)
2186 Lisp_Object mode;
2187 {
2188 CHECK_NUMBER (mode, 0);
2189
2190 umask ((~ XINT (mode)) & 0777);
2191
2192 return Qnil;
2193 }
2194
2195 DEFUN ("default-file-mode", Fdefault_file_mode, Sdefault_file_mode, 0, 0, 0,
2196 "Return the default file protection for created files.\n\
2197 The value is an integer.")
2198 ()
2199 {
2200 int realmask;
2201 Lisp_Object value;
2202
2203 realmask = umask (0);
2204 umask (realmask);
2205
2206 XSET (value, Lisp_Int, (~ realmask) & 0777);
2207 return value;
2208 }
2209
2210 #ifdef unix
2211
2212 DEFUN ("unix-sync", Funix_sync, Sunix_sync, 0, 0, "",
2213 "Tell Unix to finish all pending disk updates.")
2214 ()
2215 {
2216 sync ();
2217 return Qnil;
2218 }
2219
2220 #endif /* unix */
2221
2222 DEFUN ("file-newer-than-file-p", Ffile_newer_than_file_p, Sfile_newer_than_file_p, 2, 2, 0,
2223 "Return t if file FILE1 is newer than file FILE2.\n\
2224 If FILE1 does not exist, the answer is nil;\n\
2225 otherwise, if FILE2 does not exist, the answer is t.")
2226 (file1, file2)
2227 Lisp_Object file1, file2;
2228 {
2229 Lisp_Object abspath1, abspath2;
2230 struct stat st;
2231 int mtime1;
2232 Lisp_Object handler;
2233 struct gcpro gcpro1, gcpro2;
2234
2235 CHECK_STRING (file1, 0);
2236 CHECK_STRING (file2, 0);
2237
2238 abspath1 = Qnil;
2239 GCPRO2 (abspath1, file2);
2240 abspath1 = expand_and_dir_to_file (file1, current_buffer->directory);
2241 abspath2 = expand_and_dir_to_file (file2, current_buffer->directory);
2242 UNGCPRO;
2243
2244 /* If the file name has special constructs in it,
2245 call the corresponding file handler. */
2246 handler = Ffind_file_name_handler (abspath1);
2247 if (!NILP (handler))
2248 return call3 (handler, Qfile_newer_than_file_p, abspath1, abspath2);
2249
2250 if (stat (XSTRING (abspath1)->data, &st) < 0)
2251 return Qnil;
2252
2253 mtime1 = st.st_mtime;
2254
2255 if (stat (XSTRING (abspath2)->data, &st) < 0)
2256 return Qt;
2257
2258 return (mtime1 > st.st_mtime) ? Qt : Qnil;
2259 }
2260 \f
2261 DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents,
2262 1, 2, 0,
2263 "Insert contents of file FILENAME after point.\n\
2264 Returns list of absolute pathname and length of data inserted.\n\
2265 If second argument VISIT is non-nil, the buffer's visited filename\n\
2266 and last save file modtime are set, and it is marked unmodified.\n\
2267 If visiting and the file does not exist, visiting is completed\n\
2268 before the error is signaled.")
2269 (filename, visit)
2270 Lisp_Object filename, visit;
2271 {
2272 struct stat st;
2273 register int fd;
2274 register int inserted = 0;
2275 register int how_much;
2276 int count = specpdl_ptr - specpdl;
2277 struct gcpro gcpro1;
2278 Lisp_Object handler, val;
2279
2280 val = Qnil;
2281
2282 GCPRO1 (filename);
2283 if (!NILP (current_buffer->read_only))
2284 Fbarf_if_buffer_read_only();
2285
2286 CHECK_STRING (filename, 0);
2287 filename = Fexpand_file_name (filename, Qnil);
2288
2289 /* If the file name has special constructs in it,
2290 call the corresponding file handler. */
2291 handler = Ffind_file_name_handler (filename);
2292 if (!NILP (handler))
2293 {
2294 val = call3 (handler, Qinsert_file_contents, filename, visit);
2295 st.st_mtime = 0;
2296 goto handled;
2297 }
2298
2299 fd = -1;
2300
2301 #ifndef APOLLO
2302 if (stat (XSTRING (filename)->data, &st) < 0
2303 || (fd = open (XSTRING (filename)->data, 0)) < 0)
2304 #else
2305 if ((fd = open (XSTRING (filename)->data, 0)) < 0
2306 || fstat (fd, &st) < 0)
2307 #endif /* not APOLLO */
2308 {
2309 if (fd >= 0) close (fd);
2310 if (NILP (visit))
2311 report_file_error ("Opening input file", Fcons (filename, Qnil));
2312 st.st_mtime = -1;
2313 how_much = 0;
2314 goto notfound;
2315 }
2316
2317 record_unwind_protect (close_file_unwind, make_number (fd));
2318
2319 #ifdef S_IFSOCK
2320 /* This code will need to be changed in order to work on named
2321 pipes, and it's probably just not worth it. So we should at
2322 least signal an error. */
2323 if ((st.st_mode & S_IFMT) == S_IFSOCK)
2324 Fsignal (Qfile_error,
2325 Fcons (build_string ("reading from named pipe"),
2326 Fcons (filename, Qnil)));
2327 #endif
2328
2329 /* Supposedly happens on VMS. */
2330 if (st.st_size < 0)
2331 error ("File size is negative");
2332
2333 {
2334 register Lisp_Object temp;
2335
2336 /* Make sure point-max won't overflow after this insertion. */
2337 XSET (temp, Lisp_Int, st.st_size + Z);
2338 if (st.st_size + Z != XINT (temp))
2339 error ("maximum buffer size exceeded");
2340 }
2341
2342 if (NILP (visit))
2343 prepare_to_modify_buffer (point, point);
2344
2345 move_gap (point);
2346 if (GAP_SIZE < st.st_size)
2347 make_gap (st.st_size - GAP_SIZE);
2348
2349 while (1)
2350 {
2351 int try = min (st.st_size - inserted, 64 << 10);
2352 int this;
2353
2354 /* Allow quitting out of the actual I/O. */
2355 immediate_quit = 1;
2356 QUIT;
2357 this = read (fd, &FETCH_CHAR (point + inserted - 1) + 1, try);
2358 immediate_quit = 0;
2359
2360 if (this <= 0)
2361 {
2362 how_much = this;
2363 break;
2364 }
2365
2366 GPT += this;
2367 GAP_SIZE -= this;
2368 ZV += this;
2369 Z += this;
2370 inserted += this;
2371 }
2372
2373 if (inserted > 0)
2374 {
2375 record_insert (point, inserted);
2376
2377 /* Only defined if Emacs is compiled with USE_TEXT_PROPERTIES */
2378 offset_intervals (current_buffer, point, inserted);
2379 MODIFF++;
2380 }
2381
2382 close (fd);
2383
2384 /* Discard the unwind protect */
2385 specpdl_ptr = specpdl + count;
2386
2387 if (how_much < 0)
2388 error ("IO error reading %s: %s",
2389 XSTRING (filename)->data, err_str (errno));
2390
2391 notfound:
2392 handled:
2393
2394 if (!NILP (visit))
2395 {
2396 current_buffer->undo_list = Qnil;
2397 #ifdef APOLLO
2398 stat (XSTRING (filename)->data, &st);
2399 #endif
2400 current_buffer->modtime = st.st_mtime;
2401 current_buffer->save_modified = MODIFF;
2402 current_buffer->auto_save_modified = MODIFF;
2403 XFASTINT (current_buffer->save_length) = Z - BEG;
2404 #ifdef CLASH_DETECTION
2405 if (NILP (handler))
2406 {
2407 if (!NILP (current_buffer->filename))
2408 unlock_file (current_buffer->filename);
2409 unlock_file (filename);
2410 }
2411 #endif /* CLASH_DETECTION */
2412 current_buffer->filename = filename;
2413 /* If visiting nonexistent file, return nil. */
2414 if (current_buffer->modtime == -1)
2415 report_file_error ("Opening input file", Fcons (filename, Qnil));
2416 }
2417
2418 signal_after_change (point, 0, inserted);
2419
2420 if (!NILP (val))
2421 RETURN_UNGCPRO (val);
2422 RETURN_UNGCPRO (Fcons (filename,
2423 Fcons (make_number (inserted),
2424 Qnil)));
2425 }
2426
2427 DEFUN ("write-region", Fwrite_region, Swrite_region, 3, 5,
2428 "r\nFWrite region to file: ",
2429 "Write current region into specified file.\n\
2430 When called from a program, takes three arguments:\n\
2431 START, END and FILENAME. START and END are buffer positions.\n\
2432 Optional fourth argument APPEND if non-nil means\n\
2433 append to existing file contents (if any).\n\
2434 Optional fifth argument VISIT if t means\n\
2435 set the last-save-file-modtime of buffer to this file's modtime\n\
2436 and mark buffer not modified.\n\
2437 If VISIT is a string, it is a second file name;\n\
2438 the output goes to FILENAME, but the buffer is marked as visiting VISIT.\n\
2439 VISIT is also the file name to lock and unlock for clash detection.\n\
2440 If VISIT is neither t nor nil nor a string,\n\
2441 that means do not print the \"Wrote file\" message.\n\
2442 Kludgy feature: if START is a string, then that string is written\n\
2443 to the file, instead of any buffer contents, and END is ignored.")
2444 (start, end, filename, append, visit)
2445 Lisp_Object start, end, filename, append, visit;
2446 {
2447 register int desc;
2448 int failure;
2449 int save_errno;
2450 unsigned char *fn;
2451 struct stat st;
2452 int tem;
2453 int count = specpdl_ptr - specpdl;
2454 #ifdef VMS
2455 unsigned char *fname = 0; /* If non-0, original filename (must rename) */
2456 #endif /* VMS */
2457 Lisp_Object handler;
2458 Lisp_Object visit_file = XTYPE (visit) == Lisp_String ? visit : filename;
2459 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2460
2461 /* Special kludge to simplify auto-saving */
2462 if (NILP (start))
2463 {
2464 XFASTINT (start) = BEG;
2465 XFASTINT (end) = Z;
2466 }
2467 else if (XTYPE (start) != Lisp_String)
2468 validate_region (&start, &end);
2469
2470 GCPRO4 (start, filename, visit, visit_file);
2471 filename = Fexpand_file_name (filename, Qnil);
2472
2473 /* If the file name has special constructs in it,
2474 call the corresponding file handler. */
2475 handler = Ffind_file_name_handler (filename);
2476
2477 if (!NILP (handler))
2478 {
2479 Lisp_Object args[7];
2480 Lisp_Object val;
2481 args[0] = handler;
2482 args[1] = Qwrite_region;
2483 args[2] = start;
2484 args[3] = end;
2485 args[4] = filename;
2486 args[5] = append;
2487 args[6] = visit;
2488 val = Ffuncall (7, args);
2489
2490 /* Do this before reporting IO error
2491 to avoid a "file has changed on disk" warning on
2492 next attempt to save. */
2493 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
2494 {
2495 current_buffer->modtime = 0;
2496 current_buffer->save_modified = MODIFF;
2497 XFASTINT (current_buffer->save_length) = Z - BEG;
2498 current_buffer->filename = visit_file;
2499 }
2500 UNGCPRO;
2501 return val;
2502 }
2503
2504 #ifdef CLASH_DETECTION
2505 if (!auto_saving)
2506 lock_file (visit_file);
2507 #endif /* CLASH_DETECTION */
2508
2509 fn = XSTRING (filename)->data;
2510 desc = -1;
2511 if (!NILP (append))
2512 desc = open (fn, O_WRONLY);
2513
2514 if (desc < 0)
2515 #ifdef VMS
2516 if (auto_saving) /* Overwrite any previous version of autosave file */
2517 {
2518 vms_truncate (fn); /* if fn exists, truncate to zero length */
2519 desc = open (fn, O_RDWR);
2520 if (desc < 0)
2521 desc = creat_copy_attrs (XTYPE (current_buffer->filename) == Lisp_String
2522 ? XSTRING (current_buffer->filename)->data : 0,
2523 fn);
2524 }
2525 else /* Write to temporary name and rename if no errors */
2526 {
2527 Lisp_Object temp_name;
2528 temp_name = Ffile_name_directory (filename);
2529
2530 if (!NILP (temp_name))
2531 {
2532 temp_name = Fmake_temp_name (concat2 (temp_name,
2533 build_string ("$$SAVE$$")));
2534 fname = XSTRING (filename)->data;
2535 fn = XSTRING (temp_name)->data;
2536 desc = creat_copy_attrs (fname, fn);
2537 if (desc < 0)
2538 {
2539 /* If we can't open the temporary file, try creating a new
2540 version of the original file. VMS "creat" creates a
2541 new version rather than truncating an existing file. */
2542 fn = fname;
2543 fname = 0;
2544 desc = creat (fn, 0666);
2545 #if 0 /* This can clobber an existing file and fail to replace it,
2546 if the user runs out of space. */
2547 if (desc < 0)
2548 {
2549 /* We can't make a new version;
2550 try to truncate and rewrite existing version if any. */
2551 vms_truncate (fn);
2552 desc = open (fn, O_RDWR);
2553 }
2554 #endif
2555 }
2556 }
2557 else
2558 desc = creat (fn, 0666);
2559 }
2560 #else /* not VMS */
2561 desc = creat (fn, auto_saving ? auto_save_mode_bits : 0666);
2562 #endif /* not VMS */
2563
2564 UNGCPRO;
2565
2566 if (desc < 0)
2567 {
2568 #ifdef CLASH_DETECTION
2569 save_errno = errno;
2570 if (!auto_saving) unlock_file (visit_file);
2571 errno = save_errno;
2572 #endif /* CLASH_DETECTION */
2573 report_file_error ("Opening output file", Fcons (filename, Qnil));
2574 }
2575
2576 record_unwind_protect (close_file_unwind, make_number (desc));
2577
2578 if (!NILP (append))
2579 if (lseek (desc, 0, 2) < 0)
2580 {
2581 #ifdef CLASH_DETECTION
2582 if (!auto_saving) unlock_file (visit_file);
2583 #endif /* CLASH_DETECTION */
2584 report_file_error ("Lseek error", Fcons (filename, Qnil));
2585 }
2586
2587 #ifdef VMS
2588 /*
2589 * Kludge Warning: The VMS C RTL likes to insert carriage returns
2590 * if we do writes that don't end with a carriage return. Furthermore
2591 * it cannot handle writes of more then 16K. The modified
2592 * version of "sys_write" in SYSDEP.C (see comment there) copes with
2593 * this EXCEPT for the last record (iff it doesn't end with a carriage
2594 * return). This implies that if your buffer doesn't end with a carriage
2595 * return, you get one free... tough. However it also means that if
2596 * we make two calls to sys_write (a la the following code) you can
2597 * get one at the gap as well. The easiest way to fix this (honest)
2598 * is to move the gap to the next newline (or the end of the buffer).
2599 * Thus this change.
2600 *
2601 * Yech!
2602 */
2603 if (GPT > BEG && GPT_ADDR[-1] != '\n')
2604 move_gap (find_next_newline (GPT, 1));
2605 #endif
2606
2607 failure = 0;
2608 immediate_quit = 1;
2609
2610 if (XTYPE (start) == Lisp_String)
2611 {
2612 failure = 0 > e_write (desc, XSTRING (start)->data,
2613 XSTRING (start)->size);
2614 save_errno = errno;
2615 }
2616 else if (XINT (start) != XINT (end))
2617 {
2618 if (XINT (start) < GPT)
2619 {
2620 register int end1 = XINT (end);
2621 tem = XINT (start);
2622 failure = 0 > e_write (desc, &FETCH_CHAR (tem),
2623 min (GPT, end1) - tem);
2624 save_errno = errno;
2625 }
2626
2627 if (XINT (end) > GPT && !failure)
2628 {
2629 tem = XINT (start);
2630 tem = max (tem, GPT);
2631 failure = 0 > e_write (desc, &FETCH_CHAR (tem), XINT (end) - tem);
2632 save_errno = errno;
2633 }
2634 }
2635
2636 immediate_quit = 0;
2637
2638 #ifndef USG
2639 #ifndef VMS
2640 #ifndef BSD4_1
2641 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
2642 Disk full in NFS may be reported here. */
2643 if (fsync (desc) < 0)
2644 failure = 1, save_errno = errno;
2645 #endif
2646 #endif
2647 #endif
2648
2649 /* Spurious "file has changed on disk" warnings have been
2650 observed on Suns as well.
2651 It seems that `close' can change the modtime, under nfs.
2652
2653 (This has supposedly been fixed in Sunos 4,
2654 but who knows about all the other machines with NFS?) */
2655 #if 0
2656
2657 /* On VMS and APOLLO, must do the stat after the close
2658 since closing changes the modtime. */
2659 #ifndef VMS
2660 #ifndef APOLLO
2661 /* Recall that #if defined does not work on VMS. */
2662 #define FOO
2663 fstat (desc, &st);
2664 #endif
2665 #endif
2666 #endif
2667
2668 /* NFS can report a write failure now. */
2669 if (close (desc) < 0)
2670 failure = 1, save_errno = errno;
2671
2672 #ifdef VMS
2673 /* If we wrote to a temporary name and had no errors, rename to real name. */
2674 if (fname)
2675 {
2676 if (!failure)
2677 failure = (rename (fn, fname) != 0), save_errno = errno;
2678 fn = fname;
2679 }
2680 #endif /* VMS */
2681
2682 #ifndef FOO
2683 stat (fn, &st);
2684 #endif
2685 /* Discard the unwind protect */
2686 specpdl_ptr = specpdl + count;
2687
2688 #ifdef CLASH_DETECTION
2689 if (!auto_saving)
2690 unlock_file (visit_file);
2691 #endif /* CLASH_DETECTION */
2692
2693 /* Do this before reporting IO error
2694 to avoid a "file has changed on disk" warning on
2695 next attempt to save. */
2696 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
2697 current_buffer->modtime = st.st_mtime;
2698
2699 if (failure)
2700 error ("IO error writing %s: %s", fn, err_str (save_errno));
2701
2702 if (EQ (visit, Qt) || XTYPE (visit) == Lisp_String)
2703 {
2704 current_buffer->save_modified = MODIFF;
2705 XFASTINT (current_buffer->save_length) = Z - BEG;
2706 current_buffer->filename = visit_file;
2707 }
2708 else if (!NILP (visit))
2709 return Qnil;
2710
2711 if (!auto_saving)
2712 message ("Wrote %s", XSTRING (visit_file)->data);
2713
2714 return Qnil;
2715 }
2716
2717 int
2718 e_write (desc, addr, len)
2719 int desc;
2720 register char *addr;
2721 register int len;
2722 {
2723 char buf[16 * 1024];
2724 register char *p, *end;
2725
2726 if (!EQ (current_buffer->selective_display, Qt))
2727 return write (desc, addr, len) - len;
2728 else
2729 {
2730 p = buf;
2731 end = p + sizeof buf;
2732 while (len--)
2733 {
2734 if (p == end)
2735 {
2736 if (write (desc, buf, sizeof buf) != sizeof buf)
2737 return -1;
2738 p = buf;
2739 }
2740 *p = *addr++;
2741 if (*p++ == '\015')
2742 p[-1] = '\n';
2743 }
2744 if (p != buf)
2745 if (write (desc, buf, p - buf) != p - buf)
2746 return -1;
2747 }
2748 return 0;
2749 }
2750
2751 DEFUN ("verify-visited-file-modtime", Fverify_visited_file_modtime,
2752 Sverify_visited_file_modtime, 1, 1, 0,
2753 "Return t if last mod time of BUF's visited file matches what BUF records.\n\
2754 This means that the file has not been changed since it was visited or saved.")
2755 (buf)
2756 Lisp_Object buf;
2757 {
2758 struct buffer *b;
2759 struct stat st;
2760 Lisp_Object handler;
2761
2762 CHECK_BUFFER (buf, 0);
2763 b = XBUFFER (buf);
2764
2765 if (XTYPE (b->filename) != Lisp_String) return Qt;
2766 if (b->modtime == 0) return Qt;
2767
2768 /* If the file name has special constructs in it,
2769 call the corresponding file handler. */
2770 handler = Ffind_file_name_handler (b->filename);
2771 if (!NILP (handler))
2772 return call2 (handler, Qverify_visited_file_modtime, buf);
2773
2774 if (stat (XSTRING (b->filename)->data, &st) < 0)
2775 {
2776 /* If the file doesn't exist now and didn't exist before,
2777 we say that it isn't modified, provided the error is a tame one. */
2778 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
2779 st.st_mtime = -1;
2780 else
2781 st.st_mtime = 0;
2782 }
2783 if (st.st_mtime == b->modtime
2784 /* If both are positive, accept them if they are off by one second. */
2785 || (st.st_mtime > 0 && b->modtime > 0
2786 && (st.st_mtime == b->modtime + 1
2787 || st.st_mtime == b->modtime - 1)))
2788 return Qt;
2789 return Qnil;
2790 }
2791
2792 DEFUN ("clear-visited-file-modtime", Fclear_visited_file_modtime,
2793 Sclear_visited_file_modtime, 0, 0, 0,
2794 "Clear out records of last mod time of visited file.\n\
2795 Next attempt to save will certainly not complain of a discrepancy.")
2796 ()
2797 {
2798 current_buffer->modtime = 0;
2799 return Qnil;
2800 }
2801
2802 DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
2803 Sset_visited_file_modtime, 0, 0, 0,
2804 "Update buffer's recorded modification time from the visited file's time.\n\
2805 Useful if the buffer was not read from the file normally\n\
2806 or if the file itself has been changed for some known benign reason.")
2807 ()
2808 {
2809 register Lisp_Object filename;
2810 struct stat st;
2811 Lisp_Object handler;
2812
2813 filename = Fexpand_file_name (current_buffer->filename, Qnil);
2814
2815 /* If the file name has special constructs in it,
2816 call the corresponding file handler. */
2817 handler = Ffind_file_name_handler (filename);
2818 if (!NILP (handler))
2819 current_buffer->modtime = 0;
2820
2821 else if (stat (XSTRING (filename)->data, &st) >= 0)
2822 current_buffer->modtime = st.st_mtime;
2823
2824 return Qnil;
2825 }
2826 \f
2827 Lisp_Object
2828 auto_save_error ()
2829 {
2830 unsigned char *name = XSTRING (current_buffer->name)->data;
2831
2832 ring_bell ();
2833 message ("Autosaving...error for %s", name);
2834 Fsleep_for (make_number (1), Qnil);
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 return Qnil;
2840 }
2841
2842 Lisp_Object
2843 auto_save_1 ()
2844 {
2845 unsigned char *fn;
2846 struct stat st;
2847
2848 /* Get visited file's mode to become the auto save file's mode. */
2849 if (stat (XSTRING (current_buffer->filename)->data, &st) >= 0)
2850 /* But make sure we can overwrite it later! */
2851 auto_save_mode_bits = st.st_mode | 0600;
2852 else
2853 auto_save_mode_bits = 0666;
2854
2855 return
2856 Fwrite_region (Qnil, Qnil,
2857 current_buffer->auto_save_file_name,
2858 Qnil, Qlambda);
2859 }
2860
2861 DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
2862 "Auto-save all buffers that need it.\n\
2863 This is all buffers that have auto-saving enabled\n\
2864 and are changed since last auto-saved.\n\
2865 Auto-saving writes the buffer into a file\n\
2866 so that your editing is not lost if the system crashes.\n\
2867 This file is not the file you visited; that changes only when you save.\n\n\
2868 Non-nil first argument means do not print any message if successful.\n\
2869 Non-nil second argument means save only current buffer.")
2870 (nomsg)
2871 Lisp_Object nomsg;
2872 {
2873 struct buffer *old = current_buffer, *b;
2874 Lisp_Object tail, buf;
2875 int auto_saved = 0;
2876 char *omessage = echo_area_glyphs;
2877 extern minibuf_level;
2878
2879 /* No GCPRO needed, because (when it matters) all Lisp_Object variables
2880 point to non-strings reached from Vbuffer_alist. */
2881
2882 auto_saving = 1;
2883 if (minibuf_level)
2884 nomsg = Qt;
2885
2886 /* Vrun_hooks is nil before emacs is dumped, and inc-vers.el will
2887 eventually call do-auto-save, so don't err here in that case. */
2888 if (!NILP (Vrun_hooks))
2889 call1 (Vrun_hooks, intern ("auto-save-hook"));
2890
2891 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
2892 tail = XCONS (tail)->cdr)
2893 {
2894 buf = XCONS (XCONS (tail)->car)->cdr;
2895 b = XBUFFER (buf);
2896 /* Check for auto save enabled
2897 and file changed since last auto save
2898 and file changed since last real save. */
2899 if (XTYPE (b->auto_save_file_name) == Lisp_String
2900 && b->save_modified < BUF_MODIFF (b)
2901 && b->auto_save_modified < BUF_MODIFF (b))
2902 {
2903 if ((XFASTINT (b->save_length) * 10
2904 > (BUF_Z (b) - BUF_BEG (b)) * 13)
2905 /* A short file is likely to change a large fraction;
2906 spare the user annoying messages. */
2907 && XFASTINT (b->save_length) > 5000
2908 /* These messages are frequent and annoying for `*mail*'. */
2909 && !EQ (b->filename, Qnil))
2910 {
2911 /* It has shrunk too much; turn off auto-saving here. */
2912 message ("Buffer %s has shrunk a lot; auto save turned off there",
2913 XSTRING (b->name)->data);
2914 /* User can reenable saving with M-x auto-save. */
2915 b->auto_save_file_name = Qnil;
2916 /* Prevent warning from repeating if user does so. */
2917 XFASTINT (b->save_length) = 0;
2918 Fsleep_for (make_number (1), Qnil);
2919 continue;
2920 }
2921 set_buffer_internal (b);
2922 if (!auto_saved && NILP (nomsg))
2923 message1 ("Auto-saving...");
2924 internal_condition_case (auto_save_1, Qt, auto_save_error);
2925 auto_saved++;
2926 b->auto_save_modified = BUF_MODIFF (b);
2927 XFASTINT (current_buffer->save_length) = Z - BEG;
2928 set_buffer_internal (old);
2929 }
2930 }
2931
2932 /* Prevent another auto save till enough input events come in. */
2933 record_auto_save ();
2934
2935 if (auto_saved && NILP (nomsg))
2936 message1 (omessage ? omessage : "Auto-saving...done");
2937
2938 auto_saving = 0;
2939 return Qnil;
2940 }
2941
2942 DEFUN ("set-buffer-auto-saved", Fset_buffer_auto_saved,
2943 Sset_buffer_auto_saved, 0, 0, 0,
2944 "Mark current buffer as auto-saved with its current text.\n\
2945 No auto-save file will be written until the buffer changes again.")
2946 ()
2947 {
2948 current_buffer->auto_save_modified = MODIFF;
2949 XFASTINT (current_buffer->save_length) = Z - BEG;
2950 return Qnil;
2951 }
2952
2953 DEFUN ("recent-auto-save-p", Frecent_auto_save_p, Srecent_auto_save_p,
2954 0, 0, 0,
2955 "Return t if buffer has been auto-saved since last read in or saved.")
2956 ()
2957 {
2958 return (current_buffer->save_modified < current_buffer->auto_save_modified) ? Qt : Qnil;
2959 }
2960 \f
2961 /* Reading and completing file names */
2962 extern Lisp_Object Ffile_name_completion (), Ffile_name_all_completions ();
2963
2964 DEFUN ("read-file-name-internal", Fread_file_name_internal, Sread_file_name_internal,
2965 3, 3, 0,
2966 "Internal subroutine for read-file-name. Do not call this.")
2967 (string, dir, action)
2968 Lisp_Object string, dir, action;
2969 /* action is nil for complete, t for return list of completions,
2970 lambda for verify final value */
2971 {
2972 Lisp_Object name, specdir, realdir, val, orig_string;
2973 int changed;
2974 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
2975
2976 realdir = dir;
2977 name = string;
2978 orig_string = Qnil;
2979 specdir = Qnil;
2980 changed = 0;
2981 /* No need to protect ACTION--we only compare it with t and nil. */
2982 GCPRO4 (string, realdir, name, specdir);
2983
2984 if (XSTRING (string)->size == 0)
2985 {
2986 if (EQ (action, Qlambda))
2987 {
2988 UNGCPRO;
2989 return Qnil;
2990 }
2991 }
2992 else
2993 {
2994 orig_string = string;
2995 string = Fsubstitute_in_file_name (string);
2996 changed = NILP (Fstring_equal (string, orig_string));
2997 name = Ffile_name_nondirectory (string);
2998 val = Ffile_name_directory (string);
2999 if (! NILP (val))
3000 realdir = Fexpand_file_name (val, realdir);
3001 }
3002
3003 if (NILP (action))
3004 {
3005 specdir = Ffile_name_directory (string);
3006 val = Ffile_name_completion (name, realdir);
3007 UNGCPRO;
3008 if (XTYPE (val) != Lisp_String)
3009 {
3010 if (changed)
3011 return string;
3012 return val;
3013 }
3014
3015 if (!NILP (specdir))
3016 val = concat2 (specdir, val);
3017 #ifndef VMS
3018 {
3019 register unsigned char *old, *new;
3020 register int n;
3021 int osize, count;
3022
3023 osize = XSTRING (val)->size;
3024 /* Quote "$" as "$$" to get it past substitute-in-file-name */
3025 for (n = osize, count = 0, old = XSTRING (val)->data; n > 0; n--)
3026 if (*old++ == '$') count++;
3027 if (count > 0)
3028 {
3029 old = XSTRING (val)->data;
3030 val = Fmake_string (make_number (osize + count), make_number (0));
3031 new = XSTRING (val)->data;
3032 for (n = osize; n > 0; n--)
3033 if (*old != '$')
3034 *new++ = *old++;
3035 else
3036 {
3037 *new++ = '$';
3038 *new++ = '$';
3039 old++;
3040 }
3041 }
3042 }
3043 #endif /* Not VMS */
3044 return val;
3045 }
3046 UNGCPRO;
3047
3048 if (EQ (action, Qt))
3049 return Ffile_name_all_completions (name, realdir);
3050 /* Only other case actually used is ACTION = lambda */
3051 #ifdef VMS
3052 /* Supposedly this helps commands such as `cd' that read directory names,
3053 but can someone explain how it helps them? -- RMS */
3054 if (XSTRING (name)->size == 0)
3055 return Qt;
3056 #endif /* VMS */
3057 return Ffile_exists_p (string);
3058 }
3059
3060 DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3061 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3062 Value is not expanded---you must call `expand-file-name' yourself.\n\
3063 Default name to DEFAULT if user enters a null string.\n\
3064 (If DEFAULT is omitted, the visited file name is used.)\n\
3065 Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3066 Non-nil and non-t means also require confirmation after completion.\n\
3067 Fifth arg INITIAL specifies text to start with.\n\
3068 DIR defaults to current buffer's directory default.")
3069 (prompt, dir, defalt, mustmatch, initial)
3070 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3071 {
3072 Lisp_Object val, insdef, insdef1, tem;
3073 struct gcpro gcpro1, gcpro2;
3074 register char *homedir;
3075 int count;
3076
3077 if (NILP (dir))
3078 dir = current_buffer->directory;
3079 if (NILP (defalt))
3080 defalt = current_buffer->filename;
3081
3082 /* If dir starts with user's homedir, change that to ~. */
3083 homedir = (char *) egetenv ("HOME");
3084 if (homedir != 0
3085 && XTYPE (dir) == Lisp_String
3086 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3087 && XSTRING (dir)->data[strlen (homedir)] == '/')
3088 {
3089 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3090 XSTRING (dir)->size - strlen (homedir) + 1);
3091 XSTRING (dir)->data[0] = '~';
3092 }
3093
3094 if (insert_default_directory)
3095 {
3096 insdef = dir;
3097 insdef1 = dir;
3098 if (!NILP (initial))
3099 {
3100 Lisp_Object args[2], pos;
3101
3102 args[0] = insdef;
3103 args[1] = initial;
3104 insdef = Fconcat (2, args);
3105 pos = make_number (XSTRING (dir)->size);
3106 insdef1 = Fcons (insdef, pos);
3107 }
3108 }
3109 else
3110 insdef = Qnil, insdef1 = Qnil;
3111
3112 #ifdef VMS
3113 count = specpdl_ptr - specpdl;
3114 specbind (intern ("completion-ignore-case"), Qt);
3115 #endif
3116
3117 GCPRO2 (insdef, defalt);
3118 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3119 dir, mustmatch, insdef1,
3120 Qfile_name_history);
3121
3122 #ifdef VMS
3123 unbind_to (count, Qnil);
3124 #endif
3125
3126 UNGCPRO;
3127 if (NILP (val))
3128 error ("No file name specified");
3129 tem = Fstring_equal (val, insdef);
3130 if (!NILP (tem) && !NILP (defalt))
3131 return defalt;
3132 return Fsubstitute_in_file_name (val);
3133 }
3134
3135 #if 0 /* Old version */
3136 DEFUN ("read-file-name", Fread_file_name, Sread_file_name, 1, 5, 0,
3137 "Read file name, prompting with PROMPT and completing in directory DIR.\n\
3138 Value is not expanded---you must call `expand-file-name' yourself.\n\
3139 Default name to DEFAULT if user enters a null string.\n\
3140 (If DEFAULT is omitted, the visited file name is used.)\n\
3141 Fourth arg MUSTMATCH non-nil means require existing file's name.\n\
3142 Non-nil and non-t means also require confirmation after completion.\n\
3143 Fifth arg INITIAL specifies text to start with.\n\
3144 DIR defaults to current buffer's directory default.")
3145 (prompt, dir, defalt, mustmatch, initial)
3146 Lisp_Object prompt, dir, defalt, mustmatch, initial;
3147 {
3148 Lisp_Object val, insdef, tem;
3149 struct gcpro gcpro1, gcpro2;
3150 register char *homedir;
3151 int count;
3152
3153 if (NILP (dir))
3154 dir = current_buffer->directory;
3155 if (NILP (defalt))
3156 defalt = current_buffer->filename;
3157
3158 /* If dir starts with user's homedir, change that to ~. */
3159 homedir = (char *) egetenv ("HOME");
3160 if (homedir != 0
3161 && XTYPE (dir) == Lisp_String
3162 && !strncmp (homedir, XSTRING (dir)->data, strlen (homedir))
3163 && XSTRING (dir)->data[strlen (homedir)] == '/')
3164 {
3165 dir = make_string (XSTRING (dir)->data + strlen (homedir) - 1,
3166 XSTRING (dir)->size - strlen (homedir) + 1);
3167 XSTRING (dir)->data[0] = '~';
3168 }
3169
3170 if (!NILP (initial))
3171 insdef = initial;
3172 else if (insert_default_directory)
3173 insdef = dir;
3174 else
3175 insdef = build_string ("");
3176
3177 #ifdef VMS
3178 count = specpdl_ptr - specpdl;
3179 specbind (intern ("completion-ignore-case"), Qt);
3180 #endif
3181
3182 GCPRO2 (insdef, defalt);
3183 val = Fcompleting_read (prompt, intern ("read-file-name-internal"),
3184 dir, mustmatch,
3185 insert_default_directory ? insdef : Qnil,
3186 Qfile_name_history);
3187
3188 #ifdef VMS
3189 unbind_to (count, Qnil);
3190 #endif
3191
3192 UNGCPRO;
3193 if (NILP (val))
3194 error ("No file name specified");
3195 tem = Fstring_equal (val, insdef);
3196 if (!NILP (tem) && !NILP (defalt))
3197 return defalt;
3198 return Fsubstitute_in_file_name (val);
3199 }
3200 #endif /* Old version */
3201 \f
3202 syms_of_fileio ()
3203 {
3204 Qexpand_file_name = intern ("expand-file-name");
3205 Qdirectory_file_name = intern ("directory-file-name");
3206 Qfile_name_directory = intern ("file-name-directory");
3207 Qfile_name_nondirectory = intern ("file-name-nondirectory");
3208 Qunhandled_file_name_directory = intern ("unhandled-file-name-directory");
3209 Qfile_name_as_directory = intern ("file-name-as-directory");
3210 Qcopy_file = intern ("copy-file");
3211 Qmake_directory = intern ("make-directory");
3212 Qdelete_directory = intern ("delete-directory");
3213 Qdelete_file = intern ("delete-file");
3214 Qrename_file = intern ("rename-file");
3215 Qadd_name_to_file = intern ("add-name-to-file");
3216 Qmake_symbolic_link = intern ("make-symbolic-link");
3217 Qfile_exists_p = intern ("file-exists-p");
3218 Qfile_executable_p = intern ("file-executable-p");
3219 Qfile_readable_p = intern ("file-readable-p");
3220 Qfile_symlink_p = intern ("file-symlink-p");
3221 Qfile_writable_p = intern ("file-writable-p");
3222 Qfile_directory_p = intern ("file-directory-p");
3223 Qfile_accessible_directory_p = intern ("file-accessible-directory-p");
3224 Qfile_modes = intern ("file-modes");
3225 Qset_file_modes = intern ("set-file-modes");
3226 Qfile_newer_than_file_p = intern ("file-newer-than-file-p");
3227 Qinsert_file_contents = intern ("insert-file-contents");
3228 Qwrite_region = intern ("write-region");
3229 Qverify_visited_file_modtime = intern ("verify-visited-file-modtime");
3230
3231 staticpro (&Qexpand_file_name);
3232 staticpro (&Qdirectory_file_name);
3233 staticpro (&Qfile_name_directory);
3234 staticpro (&Qfile_name_nondirectory);
3235 staticpro (&Qunhandled_file_name_directory);
3236 staticpro (&Qfile_name_as_directory);
3237 staticpro (&Qcopy_file);
3238 staticpro (&Qmake_directory);
3239 staticpro (&Qdelete_directory);
3240 staticpro (&Qdelete_file);
3241 staticpro (&Qrename_file);
3242 staticpro (&Qadd_name_to_file);
3243 staticpro (&Qmake_symbolic_link);
3244 staticpro (&Qfile_exists_p);
3245 staticpro (&Qfile_executable_p);
3246 staticpro (&Qfile_readable_p);
3247 staticpro (&Qfile_symlink_p);
3248 staticpro (&Qfile_writable_p);
3249 staticpro (&Qfile_directory_p);
3250 staticpro (&Qfile_accessible_directory_p);
3251 staticpro (&Qfile_modes);
3252 staticpro (&Qset_file_modes);
3253 staticpro (&Qfile_newer_than_file_p);
3254 staticpro (&Qinsert_file_contents);
3255 staticpro (&Qwrite_region);
3256 staticpro (&Qverify_visited_file_modtime);
3257
3258 Qfile_name_history = intern ("file-name-history");
3259 Fset (Qfile_name_history, Qnil);
3260 staticpro (&Qfile_name_history);
3261
3262 Qfile_error = intern ("file-error");
3263 staticpro (&Qfile_error);
3264 Qfile_already_exists = intern("file-already-exists");
3265 staticpro (&Qfile_already_exists);
3266
3267 Fput (Qfile_error, Qerror_conditions,
3268 Fcons (Qfile_error, Fcons (Qerror, Qnil)));
3269 Fput (Qfile_error, Qerror_message,
3270 build_string ("File error"));
3271
3272 Fput (Qfile_already_exists, Qerror_conditions,
3273 Fcons (Qfile_already_exists,
3274 Fcons (Qfile_error, Fcons (Qerror, Qnil))));
3275 Fput (Qfile_already_exists, Qerror_message,
3276 build_string ("File already exists"));
3277
3278 DEFVAR_BOOL ("insert-default-directory", &insert_default_directory,
3279 "*Non-nil means when reading a filename start with default dir in minibuffer.");
3280 insert_default_directory = 1;
3281
3282 DEFVAR_BOOL ("vms-stmlf-recfm", &vms_stmlf_recfm,
3283 "*Non-nil means write new files with record format `stmlf'.\n\
3284 nil means use format `var'. This variable is meaningful only on VMS.");
3285 vms_stmlf_recfm = 0;
3286
3287 DEFVAR_LISP ("file-name-handler-alist", &Vfile_name_handler_alist,
3288 "*Alist of elements (REGEXP . HANDLER) for file names handled specially.\n\
3289 If a file name matches REGEXP, then all I/O on that file is done by calling\n\
3290 HANDLER.\n\
3291 \n\
3292 The first argument given to HANDLER is the name of the I/O primitive\n\
3293 to be handled; the remaining arguments are the arguments that were\n\
3294 passed to that primitive. For example, if you do\n\
3295 (file-exists-p FILENAME)\n\
3296 and FILENAME is handled by HANDLER, then HANDLER is called like this:\n\
3297 (funcall HANDLER 'file-exists-p FILENAME)\n\
3298 The function `find-file-name-handler' checks this list for a handler\n\
3299 for its argument.");
3300 Vfile_name_handler_alist = Qnil;
3301
3302 defsubr (&Sfind_file_name_handler);
3303 defsubr (&Sfile_name_directory);
3304 defsubr (&Sfile_name_nondirectory);
3305 defsubr (&Sunhandled_file_name_directory);
3306 defsubr (&Sfile_name_as_directory);
3307 defsubr (&Sdirectory_file_name);
3308 defsubr (&Smake_temp_name);
3309 defsubr (&Sexpand_file_name);
3310 defsubr (&Ssubstitute_in_file_name);
3311 defsubr (&Scopy_file);
3312 defsubr (&Smake_directory_internal);
3313 defsubr (&Sdelete_directory);
3314 defsubr (&Sdelete_file);
3315 defsubr (&Srename_file);
3316 defsubr (&Sadd_name_to_file);
3317 #ifdef S_IFLNK
3318 defsubr (&Smake_symbolic_link);
3319 #endif /* S_IFLNK */
3320 #ifdef VMS
3321 defsubr (&Sdefine_logical_name);
3322 #endif /* VMS */
3323 #ifdef HPUX_NET
3324 defsubr (&Ssysnetunam);
3325 #endif /* HPUX_NET */
3326 defsubr (&Sfile_name_absolute_p);
3327 defsubr (&Sfile_exists_p);
3328 defsubr (&Sfile_executable_p);
3329 defsubr (&Sfile_readable_p);
3330 defsubr (&Sfile_writable_p);
3331 defsubr (&Sfile_symlink_p);
3332 defsubr (&Sfile_directory_p);
3333 defsubr (&Sfile_accessible_directory_p);
3334 defsubr (&Sfile_modes);
3335 defsubr (&Sset_file_modes);
3336 defsubr (&Sset_default_file_mode);
3337 defsubr (&Sdefault_file_mode);
3338 defsubr (&Sfile_newer_than_file_p);
3339 defsubr (&Sinsert_file_contents);
3340 defsubr (&Swrite_region);
3341 defsubr (&Sverify_visited_file_modtime);
3342 defsubr (&Sclear_visited_file_modtime);
3343 defsubr (&Sset_visited_file_modtime);
3344 defsubr (&Sdo_auto_save);
3345 defsubr (&Sset_buffer_auto_saved);
3346 defsubr (&Srecent_auto_save_p);
3347
3348 defsubr (&Sread_file_name_internal);
3349 defsubr (&Sread_file_name);
3350
3351 #ifdef unix
3352 defsubr (&Sunix_sync);
3353 #endif
3354 }