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