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