Merge remote-tracking branch 'origin/master' into for-steve
[sxemacs] / src / fileio.c
1 /* File IO for SXEmacs.
2    Copyright (C) 1985-1988, 1992-1995 Free Software Foundation, Inc.
3    Copyright (C) 1996 Ben Wing.
4
5 This file is part of SXEmacs
6
7 SXEmacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 SXEmacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
19
20
21 /* Synched up with: Mule 2.0, FSF 19.30. */
22 /* More syncing: FSF Emacs 19.34.6 by Marc Paquette <marcpa@cam.org> */
23
24 #include <config.h>
25 #include "lisp.h"
26
27 #include "buffer.h"
28 #include "events/events.h"
29 #include "ui/frame.h"
30 #include "ui/insdel.h"
31 #include "lstream.h"
32 #include "ui/redisplay.h"
33 #include "sysdep.h"
34 #include "ui/window.h"          /* minibuf_level */
35 #ifdef FILE_CODING
36 #include "mule/file-coding.h"
37 #endif
38
39 #ifdef HAVE_LIBGEN_H            /* Must come before sysfile.h */
40 #include <libgen.h>
41 #endif
42 #include "sysfile.h"
43 #include "sysproc.h"
44 #include "syspwd.h"
45 #include "systime.h"
46 #include "sysdir.h"
47
48 #ifdef HPUX
49 #include <netio.h>
50 #ifdef HPUX_PRE_8_0
51 #include <errnet.h>
52 #endif                          /* HPUX_PRE_8_0 */
53 #endif                          /* HPUX */
54
55 int lisp_to_time(Lisp_Object, time_t *);
56 Lisp_Object time_to_lisp(time_t);
57
58 /* Nonzero during writing of auto-save files */
59 static int auto_saving;
60
61 /* Set by auto_save_1 to mode of original file so Fwrite_region_internal
62    will create a new file with the same mode as the original */
63 static int auto_save_mode_bits;
64
65 /* Alist of elements (REGEXP . HANDLER) for file names
66    whose I/O is done with a special handler.  */
67 Lisp_Object Vfile_name_handler_alist;
68
69 /* Format for auto-save files */
70 Lisp_Object Vauto_save_file_format;
71
72 /* Lisp functions for translating file formats */
73 Lisp_Object Qformat_decode, Qformat_annotate_function;
74
75 /* Functions to be called to process text properties in inserted file.  */
76 Lisp_Object Vafter_insert_file_functions;
77
78 /* Functions to be called to create text property annotations for file.  */
79 Lisp_Object Vwrite_region_annotate_functions;
80
81 /* During build_annotations, each time an annotation function is called,
82    this holds the annotations made by the previous functions.  */
83 Lisp_Object Vwrite_region_annotations_so_far;
84
85 /* File name in which we write a list of all our auto save files.  */
86 Lisp_Object Vauto_save_list_file_name;
87
88 /* Prefix used to construct Vauto_save_list_file_name. */
89 Lisp_Object Vauto_save_list_file_prefix;
90
91 /* When non-nil, it prevents auto-save list file creation. */
92 int inhibit_auto_save_session;
93
94 int disable_auto_save_when_buffer_shrinks;
95
96 Lisp_Object Vdirectory_sep_char;
97
98 /* These variables describe handlers that have "already" had a chance
99    to handle the current operation.
100
101    Vinhibit_file_name_handlers is a list of file name handlers.
102    Vinhibit_file_name_operation is the operation being handled.
103    If we try to handle that operation, we ignore those handlers.  */
104
105 static Lisp_Object Vinhibit_file_name_handlers;
106 static Lisp_Object Vinhibit_file_name_operation;
107
108 Lisp_Object Qfile_error, Qfile_already_exists;
109
110 Lisp_Object Qauto_save_hook;
111 Lisp_Object Qauto_save_error;
112 Lisp_Object Qauto_saving;
113
114 Lisp_Object Qcar_less_than_car;
115
116 Lisp_Object Qcompute_buffer_file_truename;
117
118 EXFUN(Frunning_temacs_p, 0);
119
120 /* signal a file error when errno contains a meaningful value. */
121
122 DOESNT_RETURN report_file_error(const char *string, Lisp_Object data)
123 {
124         /* #### dmoore - This uses current_buffer, better make sure no one
125            has GC'd the current buffer.  File handlers are giving me a headache
126            maybe I'll just always protect current_buffer around all of those
127            calls. */
128
129         signal_error(Qfile_error,
130                      Fcons(build_translated_string(string),
131                            Fcons(lisp_strerror(errno), data)));
132 }
133
134 void
135 maybe_report_file_error(const char *string, Lisp_Object data,
136                         Lisp_Object class, Error_behavior errb)
137 {
138         /* Optimization: */
139         if (ERRB_EQ(errb, ERROR_ME_NOT))
140                 return;
141
142         maybe_signal_error(Qfile_error,
143                            Fcons(build_translated_string(string),
144                                  Fcons(lisp_strerror(errno), data)),
145                            class, errb);
146 }
147
148 /* signal a file error when errno does not contain a meaningful value. */
149
150 DOESNT_RETURN signal_file_error(const char *string, Lisp_Object data)
151 {
152         signal_error(Qfile_error, list2(build_translated_string(string), data));
153 }
154
155 void
156 maybe_signal_file_error(const char *string, Lisp_Object data,
157                         Lisp_Object class, Error_behavior errb)
158 {
159         /* Optimization: */
160         if (ERRB_EQ(errb, ERROR_ME_NOT))
161                 return;
162         maybe_signal_error(Qfile_error,
163                            list2(build_translated_string(string), data),
164                            class, errb);
165 }
166
167 DOESNT_RETURN
168 signal_double_file_error(const char *string1, const char *string2,
169                          Lisp_Object data)
170 {
171         signal_error(Qfile_error,
172                      list3(build_translated_string(string1),
173                            build_translated_string(string2), data));
174 }
175
176 void
177 maybe_signal_double_file_error(const char *string1, const char *string2,
178                                Lisp_Object data, Lisp_Object class,
179                                Error_behavior errb)
180 {
181         /* Optimization: */
182         if (ERRB_EQ(errb, ERROR_ME_NOT))
183                 return;
184         maybe_signal_error(Qfile_error,
185                            list3(build_translated_string(string1),
186                                  build_translated_string(string2),
187                                  data), class, errb);
188 }
189
190 DOESNT_RETURN
191 signal_double_file_error_2(const char *string1, const char *string2,
192                            Lisp_Object data1, Lisp_Object data2)
193 {
194         signal_error(Qfile_error,
195                      list4(build_translated_string(string1),
196                            build_translated_string(string2), data1, data2));
197 }
198
199 void
200 maybe_signal_double_file_error_2(const char *string1, const char *string2,
201                                  Lisp_Object data1, Lisp_Object data2,
202                                  Lisp_Object class, Error_behavior errb)
203 {
204         /* Optimization: */
205         if (ERRB_EQ(errb, ERROR_ME_NOT))
206                 return;
207         maybe_signal_error(Qfile_error,
208                            list4(build_translated_string(string1),
209                                  build_translated_string(string2),
210                                  data1, data2), class, errb);
211 }
212 \f
213 /* Just like strerror(3), except return a lisp string instead of char *.
214    The string needs to be converted since it may be localized.
215    Perhaps this should use strerror-coding-system instead? */
216 Lisp_Object lisp_strerror(int errnum)
217 {
218         return build_ext_string(strerror(errnum), Qnative);
219 }
220
221 static Lisp_Object close_file_unwind(Lisp_Object fd)
222 {
223         if (CONSP(fd)) {
224                 if (INTP(XCAR(fd)))
225                         close(XINT(XCAR(fd)));
226
227                 free_cons(XCONS(fd));
228         } else
229                 close(XINT(fd));
230
231         return Qnil;
232 }
233
234 static Lisp_Object delete_stream_unwind(Lisp_Object stream)
235 {
236         Lstream_delete(XLSTREAM(stream));
237         return Qnil;
238 }
239
240 /* Restore point, having saved it as a marker.  */
241
242 static Lisp_Object restore_point_unwind(Lisp_Object point_marker)
243 {
244         BUF_SET_PT(current_buffer, marker_position(point_marker));
245         return Fset_marker(point_marker, Qnil, Qnil);
246 }
247
248 /* Versions of read() and write() that allow quitting out of the actual
249    I/O.  We don't use immediate_quit (i.e. direct longjmp() out of the
250    signal handler) because that's way too losing.
251
252    (#### Actually, longjmp()ing out of the signal handler may not be
253    as losing as I thought.  See sys_do_signal() in sysdep.c.) */
254
255 ssize_t read_allowing_quit(int fildes, void *buf, size_t size)
256 {
257         QUIT;
258         return sys_read_1(fildes, buf, size, 1);
259 }
260
261 ssize_t write_allowing_quit(int fildes, const void *buf, size_t size)
262 {
263         QUIT;
264         return sys_write_1(fildes, buf, size, 1);
265 }
266 \f
267 Lisp_Object Qexpand_file_name;
268 Lisp_Object Qfile_truename;
269 Lisp_Object Qsubstitute_in_file_name;
270 Lisp_Object Qdirectory_file_name;
271 Lisp_Object Qfile_dirname;
272 Lisp_Object Qfile_basename;
273 Lisp_Object Qfile_name_directory;
274 Lisp_Object Qfile_name_nondirectory;
275 Lisp_Object Qunhandled_file_name_directory;
276 Lisp_Object Qfile_name_as_directory;
277 Lisp_Object Qcopy_file;
278 Lisp_Object Qmake_directory_internal;
279 Lisp_Object Qdelete_directory;
280 Lisp_Object Qdelete_file;
281 Lisp_Object Qrename_file;
282 Lisp_Object Qadd_name_to_file;
283 Lisp_Object Qmake_symbolic_link;
284 Lisp_Object Qfile_exists_p;
285 Lisp_Object Qfile_executable_p;
286 Lisp_Object Qfile_readable_p;
287 Lisp_Object Qfile_symlink_p;
288 Lisp_Object Qfile_writable_p;
289 Lisp_Object Qfile_directory_p;
290 Lisp_Object Qfile_regular_p;
291 Lisp_Object Qfile_accessible_directory_p;
292 Lisp_Object Qfile_modes;
293 Lisp_Object Qset_file_modes;
294 Lisp_Object Qfile_newer_than_file_p;
295 Lisp_Object Qinsert_file_contents;
296 Lisp_Object Qwrite_region;
297 Lisp_Object Qverify_visited_file_modtime;
298 Lisp_Object Qset_visited_file_modtime;
299
300 /* If FILENAME is handled specially on account of its syntax,
301    return its handler function.  Otherwise, return nil.  */
302
303 DEFUN("find-file-name-handler", Ffind_file_name_handler, 1, 2, 0,       /*
304 Return FILENAME's handler function for OPERATION, if it has one.
305 Otherwise, return nil.
306 A file name is handled if one of the regular expressions in
307 `file-name-handler-alist' matches it.
308
309 If OPERATION equals `inhibit-file-name-operation', then we ignore
310 any handlers that are members of `inhibit-file-name-handlers',
311 but we still do run any other handlers.  This lets handlers
312 use the standard functions without calling themselves recursively.
313
314 Otherwise, OPERATION is the name of a funcall'able function.
315 */
316       (filename, operation))
317 {
318         /* This function does not GC */
319         /* This function can be called during GC */
320         /* This function must not munge the match data.  */
321         Lisp_Object chain, inhibited_handlers;
322
323         CHECK_STRING(filename);
324
325         if (EQ(operation, Vinhibit_file_name_operation))
326                 inhibited_handlers = Vinhibit_file_name_handlers;
327         else
328                 inhibited_handlers = Qnil;
329
330         EXTERNAL_LIST_LOOP(chain, Vfile_name_handler_alist) {
331                 Lisp_Object elt = XCAR(chain);
332                 if (CONSP(elt)) {
333                         Lisp_Object string = XCAR(elt);
334                         if (STRINGP(string)
335                             && (fast_lisp_string_match(string, filename) >= 0)) {
336                                 Lisp_Object handler = XCDR(elt);
337                                 if (NILP(Fmemq(handler, inhibited_handlers)))
338                                         return handler;
339                         }
340                 }
341                 QUIT;
342         }
343         return Qnil;
344 }
345
346 static Lisp_Object
347 call2_check_string(Lisp_Object fn, Lisp_Object arg0, Lisp_Object arg1)
348 {
349         /* This function can call lisp */
350         Lisp_Object result = call2(fn, arg0, arg1);
351         CHECK_STRING(result);
352         return result;
353 }
354
355 static Lisp_Object
356 call2_check_string_or_nil(Lisp_Object fn, Lisp_Object arg0, Lisp_Object arg1)
357 {
358         /* This function can call lisp */
359         Lisp_Object result = call2(fn, arg0, arg1);
360         if (!NILP(result))
361                 CHECK_STRING(result);
362         return result;
363 }
364
365 static Lisp_Object
366 call3_check_string(Lisp_Object fn, Lisp_Object arg0,
367                    Lisp_Object arg1, Lisp_Object arg2)
368 {
369         /* This function can call lisp */
370         Lisp_Object result = call3(fn, arg0, arg1, arg2);
371         CHECK_STRING(result);
372         return result;
373 }
374 \f
375 DEFUN("file-name-directory", Ffile_name_directory, 1, 1, 0,     /*
376 Return the directory component in file name FILENAME.
377 Return nil if FILENAME does not include a directory.
378 Otherwise return a directory spec.
379 Given a Unix syntax file name, returns a string ending in slash.
380 */
381       (filename))
382 {
383         /* This function can GC.  GC checked 2000-07-28 ben */
384         Bufbyte *beg;
385         Bufbyte *p;
386         Lisp_Object handler;
387
388         CHECK_STRING(filename);
389
390         /* If the file name has special constructs in it,
391            call the corresponding file handler.  */
392         handler = Ffind_file_name_handler(filename, Qfile_name_directory);
393         if (!NILP(handler))
394                 return call2_check_string_or_nil(handler, Qfile_name_directory,
395                                                  filename);
396
397 #ifdef FILE_SYSTEM_CASE
398         filename = FILE_SYSTEM_CASE(filename);
399 #endif
400         beg = XSTRING_DATA(filename);
401         p = beg + XSTRING_LENGTH(filename);
402
403         while (p != beg && !IS_ANY_SEP(p[-1])
404             )
405                 p--;
406
407         if (p == beg)
408                 return Qnil;
409         return make_string(beg, p - beg);
410 }
411
412 DEFUN("file-name-nondirectory", Ffile_name_nondirectory, 1, 1, 0,       /*
413 Return file name FILENAME sans its directory.
414 For example, in a Unix-syntax file name,
415 this is everything after the last slash,
416 or the entire name if it contains no slash.
417 */
418       (filename))
419 {
420         /* This function can GC.  GC checked 2000-07-28 ben */
421         Bufbyte *beg, *p, *end;
422         Lisp_Object handler;
423
424         CHECK_STRING(filename);
425
426         /* If the file name has special constructs in it,
427            call the corresponding file handler.  */
428         handler = Ffind_file_name_handler(filename, Qfile_name_nondirectory);
429         if (!NILP(handler))
430                 return call2_check_string(handler, Qfile_name_nondirectory,
431                                           filename);
432
433         beg = XSTRING_DATA(filename);
434         end = p = beg + XSTRING_LENGTH(filename);
435
436         while (p != beg && !IS_ANY_SEP(p[-1])
437             )
438                 p--;
439
440         return make_string(p, end - p);
441 }
442
443
444 static
445 Bytecount file_basename_match_extension(Lisp_Object filename,
446                                         Lisp_Object extension)
447 {
448         Bytecount match = -1;
449         Bytecount len = XSTRING_LENGTH( extension );
450         if ( len > 0 ) {
451                 char     re[len+6],
452                         *rep = re;
453                 Bufbyte *ext = XSTRING_DATA(extension);
454                 Lisp_Object regexp;
455
456                 memset(re,0,len+6);
457                 if ( strncmp( (char*)ext, "\\.", 2 ) != 0 ) {
458                         strncpy(rep, "\\.", 3);
459                         rep += 2;
460                 }
461                 memcpy(rep,ext,len);
462                 /* Note that we advance by len-1 to be positioned at
463                    the last char of extension so that we can check it
464                    for '$' on the if statement and advance to the
465                    terminator if need to append...
466                 */
467                 rep += len-1;
468                 if ( *rep++ != '$' )
469                         *rep++ = '$';
470                 *rep = '\0';
471                 regexp = make_string( (Bufbyte*)re, strlen(re));
472                 match = fast_lisp_string_match( regexp, filename );
473         }
474         return match;
475 }
476
477 DEFUN("file-basename", Ffile_basename, 1, 2, 0, /*
478 Return the basename of FILENAME sans its base directory.
479 If EXTENSION is non-nil the extension is also removed if it matches the regexp.
480 EXTENSION can be a list of regexps.
481 For example, in a Unix-syntax file name,
482 this is everything after the last slash,
483 or the entire name if it contains no slash.
484 It ignores trailing slash.
485 */
486       (filename, extension))
487 {
488         /* This function can GC.  GC checked 2000-07-28 ben */
489         Bufbyte *beg, *p, *end;
490         Lisp_Object handler;
491         Lisp_Object rest;
492         Lisp_Object ext;
493         Lisp_Object res;
494         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
495
496         CHECK_STRING(filename);
497         if ( ! NILP(extension) && ! STRINGP(extension) &&
498              ! LISTP(extension) )
499                 dead_wrong_type_argument(Qstringp, extension);
500
501         GCPRO4(handler,res,rest,ext);
502
503         /* If the file name has special constructs in it,
504            call the corresponding file handler.  */
505         handler = Ffind_file_name_handler(filename, Qfile_basename);
506         if (!NILP(handler))
507                 return call2_check_string(handler, Qfile_basename,
508                                           filename);
509
510         beg = XSTRING_DATA(filename);
511         end = p = beg + XSTRING_LENGTH(filename);
512         if ( IS_ANY_SEP(p[-1]) ) {
513           p--;
514           end--;
515         }
516         while (p != beg && !IS_ANY_SEP(p[-1]))
517                 p--;
518
519         res = make_string(p, end - p);
520         if ( STRINGP( extension ) ) {
521                 Bytecount match;
522                 match = file_basename_match_extension(res,
523                                                       extension);
524                 if ( match >= 0 )
525                         RETURN_UNGCPRO(make_string(p, match));
526         } else if ( ! NILP(extension) && LISTP( extension ) ) {
527                 rest = extension;
528                 do {
529                         ext = XCAR(rest);
530                         Bytecount match;
531                         match = file_basename_match_extension(res,
532                                                               ext);
533                         if ( match >= 0 )
534                                 RETURN_UNGCPRO(make_string(p, match));
535                         rest = XCDR(rest);
536                 } while( ! NILP(rest) );
537         }
538         RETURN_UNGCPRO(res);
539 }
540
541
542 DEFUN("file-dirname", Ffile_dirname, 1, 1, 0,   /*
543 Return the directory component in file name FILENAME.
544 Return nil if FILENAME does not include a directory.
545 Otherwise return a directory spec.
546 Given a Unix syntax file name, returns a string ending in slash.
547 It ignores the trailing slash in FILENAME.
548 */
549       (filename))
550 {
551         /* This function can GC.  GC checked 2000-07-28 ben */
552         Bufbyte *beg, *p, *end;
553         Lisp_Object handler;
554
555         CHECK_STRING(filename);
556
557         /* If the file name has special constructs in it,
558            call the corresponding file handler.  */
559         handler = Ffind_file_name_handler(filename, Qfile_dirname);
560         if (!NILP(handler))
561                 return call2_check_string_or_nil(handler, Qfile_dirname,
562                                                  filename);
563
564         beg = XSTRING_DATA(filename);
565         end = p = beg + XSTRING_LENGTH(filename);
566         if ( IS_ANY_SEP(p[-1]) ) {
567           p--;
568           end--;
569         }
570         while (p != beg && !IS_ANY_SEP(p[-1])
571                )
572                 p--;
573
574         if ( beg == p )
575           return Qnil;
576         return make_string(beg, p-beg);
577 }
578
579
580 DEFUN("unhandled-file-name-directory", Funhandled_file_name_directory, 1, 1, 0, /*
581 Return a directly usable directory name somehow associated with FILENAME.
582 A `directly usable' directory name is one that may be used without the
583 intervention of any file handler.
584 If FILENAME is a directly usable file itself, return
585 \(file-name-directory FILENAME).
586 The `call-process' and `start-process' functions use this function to
587 get a current directory to run processes in.
588 */
589       (filename))
590 {
591         /* This function can GC.  GC checked 2000-07-28 ben */
592         Lisp_Object handler;
593
594         /* If the file name has special constructs in it,
595            call the corresponding file handler.  */
596         handler =
597             Ffind_file_name_handler(filename, Qunhandled_file_name_directory);
598         if (!NILP(handler))
599                 return call2(handler, Qunhandled_file_name_directory, filename);
600
601         return Ffile_name_directory(filename);
602 }
603 \f
604 static char *file_name_as_directory(char *out, char *in)
605 {
606         /* This function cannot GC */
607         int size = strlen(in);
608
609         if (size == 0) {
610                 out[0] = '.';
611                 out[1] = DIRECTORY_SEP;
612                 out[2] = '\0';
613         } else {
614                 strcpy(out, in);
615                 /* Append a slash if necessary */
616                 if (!IS_ANY_SEP(out[size - 1])) {
617                         out[size] = DIRECTORY_SEP;
618                         out[size + 1] = '\0';
619                 }
620         }
621         return out;
622 }
623
624 DEFUN("file-name-as-directory", Ffile_name_as_directory, 1, 1, 0,       /*
625 Return a string representing file FILENAME interpreted as a directory.
626 This operation exists because a directory is also a file, but its name as
627 a directory is different from its name as a file.
628 The result can be used as the value of `default-directory'
629 or passed as second argument to `expand-file-name'.
630 For a Unix-syntax file name, just appends a slash,
631 except for (file-name-as-directory \"\") => \"./\".
632 */
633       (filename))
634 {
635         /* This function can GC.  GC checked 2000-07-28 ben */
636         char *buf;
637         Lisp_Object handler;
638
639         CHECK_STRING(filename);
640
641         /* If the file name has special constructs in it,
642            call the corresponding file handler.  */
643         handler = Ffind_file_name_handler(filename, Qfile_name_as_directory);
644         if (!NILP(handler))
645                 return call2_check_string(handler, Qfile_name_as_directory,
646                                           filename);
647
648         buf = (char *)alloca(XSTRING_LENGTH(filename) + 10);
649         return build_string(file_name_as_directory
650                             (buf, (char *)XSTRING_DATA(filename)));
651 }
652 \f
653 /*
654  * Convert from directory name to filename.
655  * On UNIX, it's simple: just make sure there isn't a terminating /
656  *
657  * Value is nonzero if the string output is different from the input.
658  */
659
660 static int directory_file_name(const char *src, char *dst)
661 {
662         /* This function cannot GC */
663         long slen = strlen(src);
664         /* Process as Unix format: just remove any final slash.
665            But leave "/" unchanged; do not change it to "".  */
666         strcpy(dst, src);
667         if (slen > 1 && IS_DIRECTORY_SEP(dst[slen - 1])
668             )
669                 dst[slen - 1] = 0;
670         return 1;
671 }
672
673 DEFUN("directory-file-name", Fdirectory_file_name, 1, 1, 0,     /*
674 Return the file name of the directory named DIRECTORY.
675 This is the name of the file that holds the data for the directory.
676 This operation exists because a directory is also a file, but its name as
677 a directory is different from its name as a file.
678 In Unix-syntax, this function just removes the final slash.
679 */
680       (directory))
681 {
682         /* This function can GC.  GC checked 2000-07-28 ben */
683         char *buf;
684         Lisp_Object handler;
685
686         CHECK_STRING(directory);
687
688 #if 0                           /* #### WTF? */
689         if (NILP(directory))
690                 return Qnil;
691 #endif
692
693         /* If the file name has special constructs in it,
694            call the corresponding file handler.  */
695         handler = Ffind_file_name_handler(directory, Qdirectory_file_name);
696         if (!NILP(handler))
697                 return call2_check_string(handler, Qdirectory_file_name,
698                                           directory);
699         buf = (char *)alloca(XSTRING_LENGTH(directory) + 20);
700         directory_file_name((char *)XSTRING_DATA(directory), buf);
701         return build_string(buf);
702 }
703 \f
704 /* Fmake_temp_name used to be a simple wrapper around mktemp(), but it
705    proved too broken for our purposes (it supported only 26 or 62
706    unique names under some implementations).  For example, this
707    arbitrary limit broke generation of Gnus Incoming* files.
708
709    This implementation is better than what one usually finds in libc.
710    --hniksic */
711
712 static unsigned int temp_name_rand;
713
714 DEFUN("make-temp-name", Fmake_temp_name, 1, 1, 0,       /*
715 Generate a temporary file name starting with PREFIX.
716 The Emacs process number forms part of the result, so there is no
717 danger of generating a name being used by another process.
718
719 In addition, this function makes an attempt to choose a name that
720 does not specify an existing file.  To make this work, PREFIX should
721 be an absolute file name.
722 */
723       (prefix))
724 {
725         static const char tbl[64] = {
726                 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
727                 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
728                 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
729                 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
730                 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
731                 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
732                 'w', 'x', 'y', 'z', '0', '1', '2', '3',
733                 '4', '5', '6', '7', '8', '9', '-', '_'
734         };
735
736         Lisp_Object val;
737         Bytecount len;
738         Bufbyte *p, *data;
739
740         CHECK_STRING(prefix);
741
742         /* I was tempted to apply Fexpand_file_name on PREFIX here, but it's
743            a bad idea because:
744
745            1) It might change the prefix, so the resulting string might not
746            begin with PREFIX.  This violates the principle of least
747            surprise.
748
749            2) It breaks under many unforeseeable circumstances, such as with
750            the code that uses (make-temp-name "") instead of
751            (make-temp-name "./").
752
753            3) It might yield unexpected (to stat(2)) results in the presence
754            of EFS and file name handlers.  */
755
756         len = XSTRING_LENGTH(prefix);
757         val = make_uninit_string(len + 6);
758         data = XSTRING_DATA(val);
759         memcpy(data, XSTRING_DATA(prefix), len);
760         p = data + len;
761
762         /* VAL is created by adding 6 characters to PREFIX.  The first three
763            are the PID of this process, in base 64, and the second three are
764            a pseudo-random number seeded from process startup time.  This
765            ensures 262144 unique file names per PID per PREFIX per machine.  */
766
767         {
768                 unsigned int pid = (unsigned int)getpid();
769                 *p++ = tbl[(pid >> 0) & 63];
770                 *p++ = tbl[(pid >> 6) & 63];
771                 *p++ = tbl[(pid >> 12) & 63];
772         }
773
774         /* Here we try to minimize useless stat'ing when this function is
775            invoked many times successively with the same PREFIX.  We achieve
776            this by using a very pseudo-random number generator to generate
777            file names unique to this process, with a very long cycle. */
778
779         while (1) {
780                 struct stat ignored;
781
782                 p[0] = tbl[(temp_name_rand >> 0) & 63];
783                 p[1] = tbl[(temp_name_rand >> 6) & 63];
784                 p[2] = tbl[(temp_name_rand >> 12) & 63];
785
786                 /* Poor man's congruential RN generator.  Replace with ++count
787                    for debugging.  */
788                 temp_name_rand += 25229;
789                 temp_name_rand %= 225307;
790
791                 QUIT;
792
793                 if (sxemacs_stat((const char *)data, &ignored) < 0) {
794                         /* We want to return only if errno is ENOENT.  */
795                         if (errno == ENOENT)
796                                 return val;
797
798                         /* The error here is dubious, but there is little else we
799                            can do.  The alternatives are to return nil, which is
800                            as bad as (and in many cases worse than) throwing the
801                            error, or to ignore the error, which will likely result
802                            in inflooping.  */
803                         report_file_error
804                             ("Cannot create temporary name for prefix",
805                              list1(prefix));
806                         return Qnil;    /* not reached */
807                 }
808         }
809 }
810 \f
811 DEFUN("expand-file-name", Fexpand_file_name, 1, 2, 0,   /*
812 Convert filename NAME to absolute, and canonicalize it.
813 Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative
814 (does not start with slash); if DEFAULT-DIRECTORY is nil or missing,
815 the current buffer's value of `default-directory' is used.
816 File name components that are `.' are removed, and
817 so are file name components followed by `..', along with the `..' itself;
818 note that these simplifications are done without checking the resulting
819 file names in the file system.
820 An initial `~/' expands to your home directory.
821 An initial `~USER/' expands to USER's home directory.
822 See also the function `substitute-in-file-name'.
823 */
824       (name, default_directory))
825 {
826         /* This function can GC.  GC-checked 2000-11-18 */
827         Bufbyte *nm;
828
829         Bufbyte *newdir, *p, *o;
830         int tlen;
831         Bufbyte *target;
832         struct passwd *pw;
833         int length;
834         Lisp_Object handler = Qnil;
835         struct gcpro gcpro1, gcpro2, gcpro3;
836
837         /* both of these get set below */
838         GCPRO3(name, default_directory, handler);
839
840         CHECK_STRING(name);
841
842         /* If the file name has special constructs in it,
843            call the corresponding file handler.  */
844         handler = Ffind_file_name_handler(name, Qexpand_file_name);
845         if (!NILP(handler))
846                 RETURN_UNGCPRO(call3_check_string(handler, Qexpand_file_name,
847                                                   name, default_directory));
848
849         /* Use the buffer's default-directory if DEFAULT_DIRECTORY is omitted.  */
850         if (NILP(default_directory))
851                 default_directory = current_buffer->directory;
852         if (!STRINGP(default_directory))
853                 default_directory = build_string("/");
854
855         if (!NILP(default_directory)) {
856                 handler =
857                     Ffind_file_name_handler(default_directory,
858                                             Qexpand_file_name);
859                 if (!NILP(handler))
860                         RETURN_UNGCPRO(call3(handler, Qexpand_file_name,
861                                              name, default_directory));
862         }
863
864         o = XSTRING_DATA(default_directory);
865
866         /* Make sure DEFAULT_DIRECTORY is properly expanded.
867            It would be better to do this down below where we actually use
868            default_directory.  Unfortunately, calling Fexpand_file_name recursively
869            could invoke GC, and the strings might be relocated.  This would
870            be annoying because we have pointers into strings lying around
871            that would need adjusting, and people would add new pointers to
872            the code and forget to adjust them, resulting in intermittent bugs.
873            Putting this call here avoids all that crud.
874
875            The EQ test avoids infinite recursion.  */
876         if (!NILP(default_directory) && !EQ(default_directory, name)
877             /* Save time in some common cases - as long as default_directory
878                is not relative, it can be canonicalized with name below (if it
879                is needed at all) without requiring it to be expanded now.  */
880             /* Detect Unix absolute file names (/... alone is not absolute on
881                Windows).  */
882             && !(IS_DIRECTORY_SEP(o[0]))
883             )
884
885                 default_directory = Fexpand_file_name(default_directory, Qnil);
886
887 #ifdef FILE_SYSTEM_CASE
888         name = FILE_SYSTEM_CASE(name);
889 #endif
890
891         /* #### dmoore - this is ugly, clean this up.  Looks like nm pointing
892            into name should be safe during all of this, though. */
893         nm = XSTRING_DATA(name);
894
895         /* If nm is absolute, look for /./ or /../ sequences; if none are
896            found, we can probably return right away.  We will avoid allocating
897            a new string if name is already fully expanded.  */
898         if (IS_DIRECTORY_SEP(nm[0])) {
899                 /* If it turns out that the filename we want to return is just a
900                    suffix of FILENAME, we don't need to go through and edit
901                    things; we just need to construct a new string using data
902                    starting at the middle of FILENAME.  If we set lose to a
903                    non-zero value, that means we've discovered that we can't do
904                    that cool trick.  */
905                 int lose = 0;
906
907                 p = nm;
908                 while (*p) {
909                         /* Since we know the name is absolute, we can assume
910                            that each element starts with a "/".  */
911
912                         /* "." and ".." are hairy.  */
913                         if (IS_DIRECTORY_SEP(p[0])
914                             && p[1] == '.' && (IS_DIRECTORY_SEP(p[2])
915                                                || p[2] == 0
916                                                || (p[2] == '.'
917                                                    && (IS_DIRECTORY_SEP(p[3])
918                                                        || p[3] == 0)))) {
919                                 lose = 1;
920                         }
921                         p++;
922                 }
923                 if (!lose) {
924                         if (nm == XSTRING_DATA(name)) {
925                                 RETURN_UNGCPRO(name);
926                         }
927                         RETURN_UNGCPRO(build_string((char*)nm));
928                 }
929         }
930
931         /* At this point, nm might or might not be an absolute file name.  We
932            need to expand ~ or ~user if present, otherwise prefix nm with
933            default_directory if nm is not absolute, and finally collapse /./
934            and /foo/../ sequences.
935
936            We set newdir to be the appropriate prefix if one is needed:
937            - the relevant user directory if nm starts with ~ or ~user
938            - the specified drive's working dir (DOS/NT only) if nm does not
939            start with /
940            - the value of default_directory.
941
942            Note that these prefixes are not guaranteed to be absolute (except
943            for the working dir of a drive).  Therefore, to ensure we always
944            return an absolute name, if the final prefix is not absolute we
945            append it to the current working directory.  */
946
947         newdir = 0;
948
949         if (nm[0] == '~') {     /* prefix ~ */
950                 if (IS_DIRECTORY_SEP(nm[1]) || nm[1] == 0) {
951                         /* ~ by itself */
952                         Extbyte *newdir_external = get_home_directory();
953
954                         if (newdir_external == NULL) {
955                                 newdir = (Bufbyte *) "";
956                         } else {
957                                 /* aint that a bit weird just to get the
958                                  * signedness correct? */
959                                 Extbyte *newdir_cpy = (Extbyte*)newdir;
960                                 TO_INTERNAL_FORMAT(
961                                         C_STRING, newdir_external,
962                                         C_STRING_ALLOCA,
963                                         newdir_cpy,
964                                         Qfile_name);
965                                 newdir = (Bufbyte*)newdir_cpy;
966                         }
967                         nm++;
968                 } else {        /* ~user/filename */
969
970                         for (p = nm; *p && (!IS_DIRECTORY_SEP(*p)); p++)
971                                 DO_NOTHING;
972                         o = (Bufbyte *) alloca(p - nm + 1);
973                         memcpy(o, (char *)nm, p - nm);
974                         o[p - nm] = 0;
975
976                         /* #### While NT is single-user (for the moment) you still
977                            can have multiple user profiles users defined, each with
978                            its HOME.  So maybe possibly we should think about handling
979                            ~user. --ben */
980                                 /* Jamie reports that getpwnam() can get wedged
981                                    by SIGIO/SIGALARM occurring in it. (It can call
982                                    select()). */
983                                 slow_down_interrupts();
984                                 pw = (struct passwd *)getpwnam((char *)o + 1);
985                                 speed_up_interrupts();
986                                 if (pw) {
987                                         newdir = (Bufbyte *) pw->pw_dir;
988                                         nm = p;
989                                 }
990
991                         /* If we don't find a user of that name, leave the name
992                            unchanged; don't move nm forward to p.  */
993                 }
994         }
995
996         /* Finally, if no prefix has been specified and nm is not absolute,
997            then it must be expanded relative to default_directory. */
998
999         if (1
1000             /* /... alone is not absolute on DOS and Windows. */
1001             && !IS_DIRECTORY_SEP(nm[0])
1002             && !newdir) {
1003                 newdir = XSTRING_DATA(default_directory);
1004         }
1005
1006         if (newdir) {
1007                 /* Get rid of any slash at the end of newdir, unless newdir is
1008                    just // (an incomplete UNC name).  */
1009                 length = strlen((char *)newdir);
1010                 if (length > 1 && IS_DIRECTORY_SEP(newdir[length - 1])) {
1011                         Bufbyte *temp = (Bufbyte *) alloca(length);
1012                         memcpy(temp, newdir, length - 1);
1013                         temp[length - 1] = 0;
1014                         newdir = temp;
1015                 }
1016                 tlen = length + 1;
1017         } else
1018                 tlen = 0;
1019
1020         /* Now concatenate the directory and name to new space in the stack frame */
1021         tlen += strlen((char *)nm) + 1;
1022         target = (Bufbyte *) alloca(tlen);
1023         *target = 0;
1024
1025         if (newdir) {
1026                 if (nm[0] == 0 || IS_DIRECTORY_SEP(nm[0]))
1027                         strcpy((char *)target, (char *)newdir);
1028                 else
1029                         file_name_as_directory((char *)target, (char *)newdir);
1030         }
1031
1032         strcat((char *)target, (char *)nm);
1033
1034         /* ASSERT (IS_DIRECTORY_SEP (target[0])) if not VMS */
1035
1036         /* Now canonicalize by removing /. and /foo/.. if they appear.  */
1037
1038         p = target;
1039         o = target;
1040
1041         while (*p) {
1042                 if (!IS_DIRECTORY_SEP(*p)) {
1043                         *o++ = *p++;
1044                 } else if (IS_DIRECTORY_SEP(p[0])
1045                            && p[1] == '.' && (IS_DIRECTORY_SEP(p[2])
1046                                               || p[2] == 0)) {
1047                         /* If "/." is the entire filename, keep the "/".  Otherwise,
1048                            just delete the whole "/.".  */
1049                         if (o == target && p[2] == '\0')
1050                                 *o++ = *p;
1051                         p += 2;
1052                 } else if (IS_DIRECTORY_SEP(p[0]) && p[1] == '.' && p[2] == '.'
1053                            /* `/../' is the "superroot" on certain file systems.  */
1054                            && o != target
1055                            && (IS_DIRECTORY_SEP(p[3]) || p[3] == 0)) {
1056                         while (o != target && (--o) && !IS_DIRECTORY_SEP(*o)) ;
1057                         /* Keep initial / only if this is the whole name.  */
1058                         if (o == target && IS_ANY_SEP(*o) && p[3] == 0)
1059                                 ++o;
1060                         p += 3;
1061                 }
1062                 else {
1063                         *o++ = *p++;
1064                 }
1065         }
1066
1067         RETURN_UNGCPRO(make_string(target, o - target));
1068 }
1069
1070 DEFUN("file-truename", Ffile_truename, 1, 2, 0, /*
1071 Return the canonical name of FILENAME.
1072 Second arg DEFAULT is directory to start with if FILENAME is relative
1073 (does not start with slash); if DEFAULT is nil or missing,
1074 the current buffer's value of `default-directory' is used.
1075 No component of the resulting pathname will be a symbolic link, as
1076 in the realpath() function.
1077 */
1078       (filename, default_))
1079 {
1080         /* This function can GC.  GC checked 2000-07-28 ben. */
1081         Lisp_Object expanded_name;
1082         struct gcpro gcpro1;
1083
1084         CHECK_STRING(filename);
1085
1086         expanded_name = Fexpand_file_name(filename, default_);
1087
1088         if (!STRINGP(expanded_name))
1089                 return Qnil;
1090
1091         GCPRO1(expanded_name);
1092
1093         {
1094                 Lisp_Object handler =
1095                         Ffind_file_name_handler(expanded_name, Qfile_truename);
1096
1097                 if (!NILP(handler))
1098                         RETURN_UNGCPRO
1099                                 (call2_check_string
1100                                  (handler, Qfile_truename, expanded_name));
1101         }
1102
1103         {
1104                 char resolved_path[MAXPATHLEN];
1105                 Extbyte *path = NULL;
1106                 Extbyte *p = NULL;
1107                 Extcount elen;
1108
1109                 TO_EXTERNAL_FORMAT(LISP_STRING, expanded_name,
1110                                    ALLOCA, (path, elen), Qfile_name);
1111                 p = path;
1112
1113                 if (elen > MAXPATHLEN)
1114                         goto toolong;
1115
1116                 /* Try doing it all at once. */
1117                 /* !! Does realpath() Mule-encapsulate?  Answer: Nope!
1118                    So we do it above */
1119                 if (path != NULL && !xrealpath((char *)path, resolved_path)) {
1120                         /* Didn't resolve it -- have to do it one
1121                            component at a time.
1122
1123                            "realpath" is a typically useless, stupid
1124                            un*x piece of crap.  It claims to return a
1125                            useful value in the "error" case, but since
1126                            there is no indication provided of how far
1127                            along the pathname the function went before
1128                            erring, there is no way to use the partial
1129                            result returned.  What a piece of junk.
1130
1131                            The above comment refers to historical
1132                            versions of realpath().  The Unix98 specs
1133                            state:
1134
1135                            "On successful completion, realpath()
1136                            returns a pointer to the resolved
1137                            name. Otherwise, realpath() returns a null
1138                            pointer and sets errno to indicate the
1139                            error, and the contents of the buffer
1140                            pointed to by resolved_name are undefined."
1141
1142                            Since we depend on undocumented semantics
1143                            of various system realpath()s, we just use
1144                            our own version in realpath.c.
1145                         */
1146                         for (;;) {
1147                                 Extbyte *pos = NULL;
1148
1149                                 for (pos = p + 1; pos < path + elen; pos++) {
1150                                         if (IS_DIRECTORY_SEP(*pos)) {
1151                                                 *(p = pos) = 0;
1152                                                 break;
1153                                         }
1154                                 }
1155                                 if (p != pos)
1156                                         p = 0;
1157
1158                                 if (xrealpath((char *)path, resolved_path)) {
1159                                         if (p)
1160                                                 *p = DIRECTORY_SEP;
1161                                         else
1162                                                 break;
1163
1164                                 } else if (errno == ENOENT || errno == EACCES) {
1165                                         /* Failed on this component.
1166                                            Just tack on the rest of
1167                                            the string and we are
1168                                            done. */
1169                                         int rlen = strlen(resolved_path);
1170
1171                                         /* "On failure, it returns
1172                                            NULL, sets errno to
1173                                            indicate the error, and
1174                                            places in resolved_path the
1175                                            absolute pathname of the
1176                                            path component which could
1177                                            not be resolved."
1178                                         */
1179                                         if (p == NULL ) {
1180                                                 break;
1181                                         }
1182                                         int plen = elen - (p - path);
1183
1184                                         if (rlen > 1 &&
1185                                             IS_DIRECTORY_SEP
1186                                             (resolved_path[rlen - 1]))
1187                                                 rlen = rlen - 1;
1188
1189                                         if ((plen + rlen + 1) >
1190                                             countof(resolved_path))
1191                                                 goto toolong;
1192
1193                                         resolved_path[rlen] = DIRECTORY_SEP;
1194                                         memcpy(resolved_path + rlen + 1,
1195                                                p + 1, plen + 1 - 1);
1196                                         break;
1197                                 } else
1198                                         goto lose;
1199                         }
1200                 }
1201
1202                 {
1203                         Lisp_Object resolved_name;
1204                         int rlen = strlen(resolved_path);
1205
1206                         if (elen > 0
1207                             && IS_DIRECTORY_SEP(
1208                                     XSTRING_BYTE(expanded_name, elen-1))
1209                             && !(rlen > 0 &&
1210                                  IS_DIRECTORY_SEP(resolved_path[rlen-1]))) {
1211                                 if (rlen + 1 > countof(resolved_path))
1212                                         goto toolong;
1213                                 resolved_path[rlen++] = DIRECTORY_SEP;
1214                                 resolved_path[rlen] = '\0';
1215                         }
1216                         TO_INTERNAL_FORMAT(DATA, (resolved_path, rlen),
1217                                            LISP_STRING, resolved_name,
1218                                            Qfile_name);
1219                         RETURN_UNGCPRO(resolved_name);
1220                 }
1221
1222         toolong:
1223                 errno = ENAMETOOLONG;
1224                 goto lose;
1225         lose:
1226                 report_file_error("Finding truename", list1(expanded_name));
1227         }
1228         RETURN_UNGCPRO(Qnil);
1229 }
1230 \f
1231 DEFUN("substitute-in-file-name", Fsubstitute_in_file_name, 1, 1, 0,     /*
1232 Substitute environment variables referred to in FILENAME.
1233 `$FOO' where FOO is an environment variable name means to substitute
1234 the value of that variable.  The variable name should be terminated
1235 with a character, not a letter, digit or underscore; otherwise, enclose
1236 the entire variable name in braces.
1237 If `/~' appears, all of FILENAME through that `/' is discarded.
1238 */
1239       (filename))
1240 {
1241         /* This function can GC.  GC checked 2000-07-28 ben. */
1242         Bufbyte *nm;
1243
1244         Bufbyte *s, *p, *o, *x, *endp;
1245         Bufbyte *target = 0;
1246         int total = 0;
1247         int substituted = 0;
1248         Bufbyte *xnm;
1249         Lisp_Object handler;
1250
1251         CHECK_STRING(filename);
1252
1253         /* If the file name has special constructs in it,
1254            call the corresponding file handler.  */
1255         handler = Ffind_file_name_handler(filename, Qsubstitute_in_file_name);
1256         if (!NILP(handler))
1257                 return call2_check_string_or_nil(handler,
1258                                                  Qsubstitute_in_file_name,
1259                                                  filename);
1260
1261         nm = XSTRING_DATA(filename);
1262         endp = nm + XSTRING_LENGTH(filename);
1263
1264         /* If /~ or // appears, discard everything through first slash. */
1265
1266         for (p = nm; p != endp; p++) {
1267                 if ((p[0] == '~'
1268                      || IS_DIRECTORY_SEP(p[0])
1269                     )
1270                     && p != nm && (IS_DIRECTORY_SEP(p[-1]))) {
1271                         nm = p;
1272                         substituted = 1;
1273                 }
1274         }
1275
1276         /* See if any variables are substituted into the string
1277            and find the total length of their values in `total' */
1278
1279         for (p = nm; p != endp;)
1280                 if (*p != '$')
1281                         p++;
1282                 else {
1283                         p++;
1284                         if (p == endp)
1285                                 goto badsubst;
1286                         else if (*p == '$') {
1287                                 /* "$$" means a single "$" */
1288                                 p++;
1289                                 total -= 1;
1290                                 substituted = 1;
1291                                 continue;
1292                         } else if (*p == '{') {
1293                                 o = ++p;
1294                                 while (p != endp && *p != '}')
1295                                         p++;
1296                                 if (*p != '}')
1297                                         goto missingclose;
1298                                 s = p;
1299                         } else {
1300                                 o = p;
1301                                 while (p != endp && (isalnum(*p) || *p == '_'))
1302                                         p++;
1303                                 s = p;
1304                         }
1305
1306                         /* Copy out the variable name */
1307                         target = (Bufbyte *) alloca(s - o + 1);
1308                         strncpy((char *)target, (char *)o, s - o);
1309                         target[s - o] = '\0';
1310
1311                         /* Get variable value */
1312                         o = (Bufbyte *) egetenv((char *)target);
1313                         if (!o)
1314                                 goto badvar;
1315                         total += strlen((char *)o);
1316                         substituted = 1;
1317                 }
1318
1319         if (!substituted)
1320                 return filename;
1321
1322         /* If substitution required, recopy the filename and do it */
1323         /* Make space in stack frame for the new copy */
1324         xnm = (Bufbyte *) alloca(XSTRING_LENGTH(filename) + total + 1);
1325         x = xnm;
1326
1327         /* Copy the rest of the name through, replacing $ constructs with values */
1328         for (p = nm; *p;)
1329                 if (*p != '$')
1330                         *x++ = *p++;
1331                 else {
1332                         p++;
1333                         if (p == endp)
1334                                 goto badsubst;
1335                         else if (*p == '$') {
1336                                 *x++ = *p++;
1337                                 continue;
1338                         } else if (*p == '{') {
1339                                 o = ++p;
1340                                 while (p != endp && *p != '}')
1341                                         p++;
1342                                 if (*p != '}')
1343                                         goto missingclose;
1344                                 s = p++;
1345                         } else {
1346                                 o = p;
1347                                 while (p != endp && (isalnum(*p) || *p == '_'))
1348                                         p++;
1349                                 s = p;
1350                         }
1351
1352                         /* Copy out the variable name */
1353                         target = (Bufbyte *) alloca(s - o + 1);
1354                         strncpy((char *)target, (char *)o, s - o);
1355                         target[s - o] = '\0';
1356
1357                         /* Get variable value */
1358                         o = (Bufbyte *) egetenv((char *)target);
1359                         if (!o)
1360                                 goto badvar;
1361
1362                         strcpy((char *)x, (char *)o);
1363                         x += strlen((char *)o);
1364                 }
1365
1366         *x = 0;
1367
1368         /* If /~ or // appears, discard everything through first slash. */
1369
1370         for (p = xnm; p != x; p++)
1371                 if ((p[0] == '~'
1372                      || IS_DIRECTORY_SEP(p[0])
1373                     )
1374                     /* don't do p[-1] if that would go off the beginning --jwz */
1375                     && p != nm && p > xnm && IS_DIRECTORY_SEP(p[-1]))
1376                         xnm = p;
1377
1378         return make_string(xnm, x - xnm);
1379
1380       badsubst:
1381         syntax_error("Bad format environment-variable substitution", filename);
1382       missingclose:
1383         syntax_error("Missing \"}\" in environment-variable substitution",
1384                      filename);
1385       badvar:
1386         syntax_error_2("Substituting nonexistent environment variable",
1387                        filename, build_string((char *)target));
1388
1389         /* NOTREACHED */
1390         return Qnil;            /* suppress compiler warning */
1391 }
1392 \f
1393 /* A slightly faster and more convenient way to get
1394    (directory-file-name (expand-file-name FOO)).  */
1395
1396 Lisp_Object expand_and_dir_to_file(Lisp_Object filename, Lisp_Object defdir)
1397 {
1398         /* This function can call Lisp.  GC checked 2000-07-28 ben */
1399         Lisp_Object abspath;
1400         struct gcpro gcpro1;
1401
1402         abspath = Fexpand_file_name(filename, defdir);
1403         GCPRO1(abspath);
1404         /* Remove final slash, if any (unless path is root).
1405            stat behaves differently depending!  */
1406         if (XSTRING_LENGTH(abspath) > 1
1407             &&
1408             IS_DIRECTORY_SEP(XSTRING_BYTE(abspath, XSTRING_LENGTH(abspath) - 1))
1409             &&
1410             !IS_DEVICE_SEP(XSTRING_BYTE(abspath, XSTRING_LENGTH(abspath) - 2)))
1411                 /* We cannot take shortcuts; they might be wrong for magic file names.  */
1412                 abspath = Fdirectory_file_name(abspath);
1413         UNGCPRO;
1414         return abspath;
1415 }
1416 \f
1417 /* Signal an error if the file ABSNAME already exists.
1418    If INTERACTIVE is nonzero, ask the user whether to proceed,
1419    and bypass the error if the user says to go ahead.
1420    QUERYSTRING is a name for the action that is being considered
1421    to alter the file.
1422    *STATPTR is used to store the stat information if the file exists.
1423    If the file does not exist, STATPTR->st_mode is set to 0.  */
1424
1425 static void
1426 barf_or_query_if_file_exists(Lisp_Object absname, const char *querystring,
1427                              int interactive, struct stat *statptr)
1428 {
1429         /* This function can call Lisp.  GC checked 2000-07-28 ben */
1430         struct stat statbuf;
1431
1432         /* stat is a good way to tell whether the file exists,
1433            regardless of what access permissions it has.  */
1434         if (sxemacs_stat((char *)XSTRING_DATA(absname), &statbuf) >= 0) {
1435                 Lisp_Object tem;
1436
1437                 if (interactive) {
1438                         Lisp_Object prompt;
1439                         struct gcpro gcpro1;
1440
1441                         prompt = emacs_doprnt_string_c
1442                             ((const Bufbyte *)
1443                              GETTEXT("File %s already exists; %s anyway? "),
1444                              Qnil, -1, XSTRING_DATA(absname),
1445                              GETTEXT(querystring));
1446
1447                         GCPRO1(prompt);
1448                         tem = call1(Qyes_or_no_p, prompt);
1449                         UNGCPRO;
1450                 } else
1451                         tem = Qnil;
1452
1453                 if (NILP(tem))
1454                         Fsignal(Qfile_already_exists,
1455                                 list2(build_translated_string
1456                                       ("File already exists"), absname));
1457                 if (statptr)
1458                         *statptr = statbuf;
1459         } else {
1460                 if (statptr)
1461                         statptr->st_mode = 0;
1462         }
1463         return;
1464 }
1465
1466 DEFUN("copy-file", Fcopy_file, 2, 4, "fCopy file: \nFCopy %s to file: \np\nP",  /*
1467 Copy FILENAME to NEWNAME.  Both args must be strings.
1468 Signals a `file-already-exists' error if file NEWNAME already exists,
1469 unless a third argument OK-IF-ALREADY-EXISTS is supplied and non-nil.
1470 A number as third arg means request confirmation if NEWNAME already exists.
1471 This is what happens in interactive use with M-x.
1472 Fourth arg KEEP-TIME non-nil means give the new file the same
1473 last-modified time as the old one.  (This works on only some systems.)
1474 A prefix arg makes KEEP-TIME non-nil.
1475 */
1476       (filename, newname, ok_if_already_exists, keep_time))
1477 {
1478         /* This function can call Lisp.  GC checked 2000-07-28 ben */
1479         int ifd, ofd, n;
1480         char buf[16 * 1024];
1481         struct stat st, out_st;
1482         Lisp_Object handler;
1483         int speccount = specpdl_depth();
1484         struct gcpro gcpro1, gcpro2;
1485         /* Lisp_Object args[6]; */
1486         int input_file_statable_p;
1487
1488         GCPRO2(filename, newname);
1489         CHECK_STRING(filename);
1490         CHECK_STRING(newname);
1491         filename = Fexpand_file_name(filename, Qnil);
1492         newname = Fexpand_file_name(newname, Qnil);
1493
1494         /* If the input file name has special constructs in it,
1495            call the corresponding file handler.  */
1496         handler = Ffind_file_name_handler(filename, Qcopy_file);
1497         /* Likewise for output file name.  */
1498         if (NILP(handler))
1499                 handler = Ffind_file_name_handler(newname, Qcopy_file);
1500         if (!NILP(handler)) {
1501                 UNGCPRO;
1502                 return call5(handler, Qcopy_file, filename, newname,
1503                              ok_if_already_exists, keep_time);
1504         }
1505
1506         /* When second argument is a directory, copy the file into it.
1507            (copy-file "foo" "bar/") == (copy-file "foo" "bar/foo")
1508          */
1509         if (!NILP(Ffile_directory_p(newname))) {
1510                 Lisp_Object args[3] = {newname, Qnil, Qnil};
1511                 struct gcpro ngcpro1;
1512                 int i = 1;
1513
1514                 NGCPROn(args, countof(args));
1515                 if (!IS_DIRECTORY_SEP(
1516                             XSTRING_BYTE(newname,
1517                                          XSTRING_LENGTH(newname) - 1))) {
1518                         args[i++] = Fchar_to_string(Vdirectory_sep_char);
1519                 }
1520                 args[i++] = Ffile_name_nondirectory(filename);
1521                 newname = Fconcat(i, args);
1522                 NUNGCPRO;
1523         }
1524
1525         if (NILP(ok_if_already_exists)
1526             || INTP(ok_if_already_exists))
1527                 barf_or_query_if_file_exists(newname, "copy to it",
1528                                              INTP(ok_if_already_exists),
1529                                              &out_st);
1530         else if (sxemacs_stat((const char *)XSTRING_DATA(newname), &out_st) < 0)
1531                 out_st.st_mode = 0;
1532
1533         ifd = interruptible_open((char *)XSTRING_DATA(filename),
1534                                  O_RDONLY | OPEN_BINARY, 0);
1535         if (ifd < 0) {
1536                 report_file_error("Opening input file", list1(filename));
1537         }
1538         record_unwind_protect(close_file_unwind, make_int(ifd));
1539
1540         /* We can only copy regular files and symbolic links.  Other files are not
1541            copyable by us. */
1542         input_file_statable_p = (fstat(ifd, &st) >= 0);
1543
1544         if (out_st.st_mode != 0
1545             && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) {
1546                 errno = 0;
1547                 report_file_error("Input and output files are the same",
1548                                   list2(filename, newname));
1549         }
1550
1551 #if defined (S_ISREG) && defined (S_ISLNK)
1552         if (input_file_statable_p) {
1553                 if (!(S_ISREG(st.st_mode))
1554                     /* XEmacs: have to allow S_ISCHR in order to copy /dev/null */
1555 #ifdef S_ISCHR
1556                     && !(S_ISCHR(st.st_mode))
1557 #endif
1558                     && !(S_ISLNK(st.st_mode))) {
1559 #if defined (EISDIR)
1560                         /* Get a better looking error message. */
1561                         errno = EISDIR;
1562 #endif                          /* EISDIR */
1563                         report_file_error("Non-regular file", list1(filename));
1564                 }
1565         }
1566 #endif                          /* S_ISREG && S_ISLNK */
1567
1568         ofd = open((char *)XSTRING_DATA(newname),
1569                    O_WRONLY | O_CREAT | O_TRUNC | OPEN_BINARY, CREAT_MODE);
1570         if (ofd < 0)
1571                 report_file_error("Opening output file", list1(newname));
1572
1573         {
1574                 Lisp_Object ofd_locative = noseeum_cons(make_int(ofd), Qnil);
1575
1576                 record_unwind_protect(close_file_unwind, ofd_locative);
1577
1578                 while ((n = read_allowing_quit(ifd, buf, sizeof(buf))) > 0) {
1579                         if (write_allowing_quit(ofd, buf, n) != n)
1580                                 report_file_error("I/O error", list1(newname));
1581                 }
1582
1583                 /* Closing the output clobbers the file times on some systems.  */
1584                 if (close(ofd) < 0)
1585                         report_file_error("I/O error", list1(newname));
1586
1587                 if (input_file_statable_p) {
1588                         if (!NILP(keep_time)) {
1589                                 EMACS_TIME atime, mtime;
1590                                 EMACS_SET_SECS_USECS(atime, st.st_atime, 0);
1591                                 EMACS_SET_SECS_USECS(mtime, st.st_mtime, 0);
1592                                 if (set_file_times(newname, atime, mtime))
1593                                         report_file_error("I/O error",
1594                                                           list1(newname));
1595                         }
1596                         chmod((const char *)XSTRING_DATA(newname),
1597                               st.st_mode & 07777);
1598                 }
1599
1600                 /* We'll close it by hand */
1601                 XCAR(ofd_locative) = Qnil;
1602
1603                 /* Close ifd */
1604                 unbind_to(speccount, Qnil);
1605         }
1606
1607         UNGCPRO;
1608         return Qnil;
1609 }
1610 \f
1611 DEFUN("make-directory-internal", Fmake_directory_internal, 1, 1, 0,     /*
1612 Create a directory.  One argument, a file name string.
1613 */
1614       (dirname_))
1615 {
1616         /* This function can GC.  GC checked 1997.04.06. */
1617         char dir[MAXPATHLEN];
1618         Lisp_Object handler;
1619         struct gcpro gcpro1;
1620
1621         CHECK_STRING(dirname_);
1622         dirname_ = Fexpand_file_name(dirname_, Qnil);
1623
1624         GCPRO1(dirname_);
1625         handler = Ffind_file_name_handler(dirname_, Qmake_directory_internal);
1626         UNGCPRO;
1627         if (!NILP(handler))
1628                 return (call2(handler, Qmake_directory_internal, dirname_));
1629
1630         if (XSTRING_LENGTH(dirname_) > (Bytecount) (sizeof(dir) - 1)) {
1631                 return Fsignal(Qfile_error,
1632                                list3(build_translated_string
1633                                      ("Creating directory"),
1634                                      build_translated_string
1635                                      ("pathname too long"), dirname_));
1636         }
1637         strncpy(dir, (char *)XSTRING_DATA(dirname_),
1638                 XSTRING_LENGTH(dirname_) + 1);
1639         dir[XSTRING_LENGTH(dirname_)]='\0';
1640         if (dir[XSTRING_LENGTH(dirname_) - 1] == '/')
1641                 dir[XSTRING_LENGTH(dirname_) - 1] = '\0';
1642
1643         if (mkdir(dir, 0777) != 0)
1644                 report_file_error("Creating directory", list1(dirname_));
1645
1646         return Qnil;
1647 }
1648
1649 DEFUN("delete-directory", Fdelete_directory, 1, 1, "FDelete directory: ",       /*
1650 Delete a directory.  One argument, a file name or directory name string.
1651 */
1652       (dirname_))
1653 {
1654         /* This function can GC.  GC checked 1997.04.06. */
1655         Lisp_Object handler;
1656         struct gcpro gcpro1;
1657
1658         CHECK_STRING(dirname_);
1659
1660         GCPRO1(dirname_);
1661         dirname_ = Fexpand_file_name(dirname_, Qnil);
1662         dirname_ = Fdirectory_file_name(dirname_);
1663
1664         handler = Ffind_file_name_handler(dirname_, Qdelete_directory);
1665         UNGCPRO;
1666         if (!NILP(handler))
1667                 return (call2(handler, Qdelete_directory, dirname_));
1668
1669         if (rmdir((char *)XSTRING_DATA(dirname_)) != 0)
1670                 report_file_error("Removing directory", list1(dirname_));
1671
1672         return Qnil;
1673 }
1674
1675 DEFUN("delete-file", Fdelete_file, 1, 1, "fDelete file: ",      /*
1676 Delete the file named FILENAME (a string).
1677 If FILENAME has multiple names, it continues to exist with the other names.
1678 */
1679       (filename))
1680 {
1681         /* This function can GC.  GC checked 1997.04.06. */
1682         Lisp_Object handler;
1683         struct gcpro gcpro1;
1684
1685         CHECK_STRING(filename);
1686         filename = Fexpand_file_name(filename, Qnil);
1687
1688         GCPRO1(filename);
1689         handler = Ffind_file_name_handler(filename, Qdelete_file);
1690         UNGCPRO;
1691         if (!NILP(handler))
1692                 return call2(handler, Qdelete_file, filename);
1693
1694         if (0 > unlink((char *)XSTRING_DATA(filename)))
1695                 report_file_error("Removing old name", list1(filename));
1696         return Qnil;
1697 }
1698
1699 static Lisp_Object
1700 internal_delete_file_1(Lisp_Object ignore, Lisp_Object ignore2)
1701 {
1702         return Qt;
1703 }
1704
1705 /* Delete file FILENAME, returning 1 if successful and 0 if failed.  */
1706
1707 int internal_delete_file(Lisp_Object filename)
1708 {
1709         /* This function can GC.  GC checked 1997.04.06. */
1710         return NILP(condition_case_1(Qt, Fdelete_file, filename,
1711                                      internal_delete_file_1, Qnil));
1712 }
1713 \f
1714 DEFUN("rename-file", Frename_file, 2, 3, "fRename file: \nFRename %s to file: \np",     /*
1715 Rename FILENAME as NEWNAME.  Both args must be strings.
1716 If file has names other than FILENAME, it continues to have those names.
1717 Signals a `file-already-exists' error if a file NEWNAME already exists
1718 unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.
1719 A number as third arg means request confirmation if NEWNAME already exists.
1720 This is what happens in interactive use with M-x.
1721 */
1722       (filename, newname, ok_if_already_exists))
1723 {
1724         /* This function can GC.  GC checked 1997.04.06. */
1725         Lisp_Object handler;
1726         struct gcpro gcpro1, gcpro2;
1727
1728         GCPRO2(filename, newname);
1729         CHECK_STRING(filename);
1730         CHECK_STRING(newname);
1731         filename = Fexpand_file_name(filename, Qnil);
1732         newname = Fexpand_file_name(newname, Qnil);
1733
1734         /* If the file name has special constructs in it,
1735            call the corresponding file handler.  */
1736         handler = Ffind_file_name_handler(filename, Qrename_file);
1737         if (NILP(handler))
1738                 handler = Ffind_file_name_handler(newname, Qrename_file);
1739         if (!NILP(handler)) {
1740                 UNGCPRO;
1741                 return call4(handler, Qrename_file,
1742                              filename, newname, ok_if_already_exists);
1743         }
1744
1745         /* When second argument is a directory, rename the file into it.
1746            (rename-file "foo" "bar/") == (rename-file "foo" "bar/foo")
1747          */
1748         if (!NILP(Ffile_directory_p(newname))) {
1749                 Lisp_Object args[3] = {newname, Qnil, Qnil};
1750                 struct gcpro ngcpro1;
1751                 int i = 1;
1752
1753                 NGCPROn(args, countof(args));
1754                 if (XSTRING_BYTE(newname, XSTRING_LENGTH(newname) - 1) != '/') {
1755                         args[i++] = build_string("/");
1756                 }
1757                 args[i++] = Ffile_name_nondirectory(filename);
1758                 newname = Fconcat(i, args);
1759                 NUNGCPRO;
1760         }
1761
1762         if (NILP(ok_if_already_exists)
1763             || INTP(ok_if_already_exists))
1764                 barf_or_query_if_file_exists(newname, "rename to it",
1765                                              INTP(ok_if_already_exists), 0);
1766
1767 /* Syncing with FSF 19.34.6 note: FSF does not have conditional code for
1768    WIN32_NATIVE here; I've removed it.  --marcpa */
1769
1770         /* We have configure check for rename() and emulate using
1771            link()/unlink() if necessary. */
1772         if (0 > rename((char *)XSTRING_DATA(filename),
1773                        (char *)XSTRING_DATA(newname))) {
1774                 if (errno == EXDEV) {
1775                         Fcopy_file(filename, newname,
1776                                    /* We have already prompted if it was an integer,
1777                                       so don't have copy-file prompt again.  */
1778                                    (NILP(ok_if_already_exists) ? Qnil : Qt),
1779                                    Qt);
1780                         Fdelete_file(filename);
1781                 } else {
1782                         report_file_error("Renaming", list2(filename, newname));
1783                 }
1784         }
1785         UNGCPRO;
1786         return Qnil;
1787 }
1788
1789 DEFUN("add-name-to-file", Fadd_name_to_file, 2, 3, "fAdd name to file: \nFName to add to %s: \np",      /*
1790 Give FILENAME additional name NEWNAME.  Both args must be strings.
1791 Signals a `file-already-exists' error if a file NEWNAME already exists
1792 unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.
1793 A number as third arg means request confirmation if NEWNAME already exists.
1794 This is what happens in interactive use with M-x.
1795 */
1796       (filename, newname, ok_if_already_exists))
1797 {
1798         /* This function can GC.  GC checked 1997.04.06. */
1799         Lisp_Object handler;
1800         struct gcpro gcpro1, gcpro2;
1801
1802         GCPRO2(filename, newname);
1803         CHECK_STRING(filename);
1804         CHECK_STRING(newname);
1805         filename = Fexpand_file_name(filename, Qnil);
1806         newname = Fexpand_file_name(newname, Qnil);
1807
1808         /* If the file name has special constructs in it,
1809            call the corresponding file handler.  */
1810         handler = Ffind_file_name_handler(filename, Qadd_name_to_file);
1811         if (!NILP(handler))
1812                 RETURN_UNGCPRO(call4(handler, Qadd_name_to_file, filename,
1813                                      newname, ok_if_already_exists));
1814
1815         /* If the new name has special constructs in it,
1816            call the corresponding file handler.  */
1817         handler = Ffind_file_name_handler(newname, Qadd_name_to_file);
1818         if (!NILP(handler))
1819                 RETURN_UNGCPRO(call4(handler, Qadd_name_to_file, filename,
1820                                      newname, ok_if_already_exists));
1821
1822         if (NILP(ok_if_already_exists)
1823             || INTP(ok_if_already_exists))
1824                 barf_or_query_if_file_exists(newname, "make it a new name",
1825                                              INTP(ok_if_already_exists), 0);
1826 /* Syncing with FSF 19.34.6 note: FSF does not report a file error
1827    on NT here. --marcpa */
1828 /* But FSF #defines link as sys_link which is supplied in nt.c. We can't do
1829    that because sysfile.h defines sys_link depending on ENCAPSULATE_LINK.
1830    Reverted to previous behavior pending a working fix. (jhar) */
1831
1832         unlink((char *)XSTRING_DATA(newname));
1833         if (0 > link((char *)XSTRING_DATA(filename),
1834                      (char *)XSTRING_DATA(newname))) {
1835                 report_file_error("Adding new name", list2(filename, newname));
1836         }
1837
1838         UNGCPRO;
1839         return Qnil;
1840 }
1841
1842 DEFUN("make-symbolic-link", Fmake_symbolic_link, 2, 3, "FMake symbolic link to file: \nFMake symbolic link to file %s: \np",    /*
1843 Make a symbolic link to FILENAME, named LINKNAME.  Both args strings.
1844 Signals a `file-already-exists' error if a file LINKNAME already exists
1845 unless optional third argument OK-IF-ALREADY-EXISTS is non-nil.
1846 A number as third arg means request confirmation if LINKNAME already exists.
1847 This happens for interactive use with M-x.
1848 */
1849       (filename, linkname, ok_if_already_exists))
1850 {
1851         /* This function can GC.  GC checked 1997.06.04. */
1852         /* XEmacs change: run handlers even if local machine doesn't have symlinks */
1853         Lisp_Object handler;
1854         struct gcpro gcpro1, gcpro2;
1855
1856         GCPRO2(filename, linkname);
1857         CHECK_STRING(filename);
1858         CHECK_STRING(linkname);
1859         /* If the link target has a ~, we must expand it to get
1860            a truly valid file name.  Otherwise, do not expand;
1861            we want to permit links to relative file names.  */
1862         if (XSTRING_BYTE(filename, 0) == '~')
1863                 filename = Fexpand_file_name(filename, Qnil);
1864         linkname = Fexpand_file_name(linkname, Qnil);
1865
1866         /* If the file name has special constructs in it,
1867            call the corresponding file handler.  */
1868         handler = Ffind_file_name_handler(filename, Qmake_symbolic_link);
1869         if (!NILP(handler))
1870                 RETURN_UNGCPRO(call4
1871                                (handler, Qmake_symbolic_link, filename,
1872                                 linkname, ok_if_already_exists));
1873
1874         /* If the new link name has special constructs in it,
1875            call the corresponding file handler.  */
1876         handler = Ffind_file_name_handler(linkname, Qmake_symbolic_link);
1877         if (!NILP(handler))
1878                 RETURN_UNGCPRO(call4(handler, Qmake_symbolic_link, filename,
1879                                      linkname, ok_if_already_exists));
1880
1881 #ifdef S_IFLNK
1882         if (NILP(ok_if_already_exists)
1883             || INTP(ok_if_already_exists))
1884                 barf_or_query_if_file_exists(linkname, "make it a link",
1885                                              INTP(ok_if_already_exists), 0);
1886
1887         unlink((char *)XSTRING_DATA(linkname));
1888         if (0 > symlink((char *)XSTRING_DATA(filename),
1889                         (char *)XSTRING_DATA(linkname))) {
1890                 report_file_error("Making symbolic link",
1891                                   list2(filename, linkname));
1892         }
1893 #endif                          /* S_IFLNK */
1894
1895         UNGCPRO;
1896         return Qnil;
1897 }
1898
1899 #ifdef HPUX_NET
1900
1901 DEFUN("sysnetunam", Fsysnetunam, 2, 2, 0,       /*
1902 Open a network connection to PATH using LOGIN as the login string.
1903 */
1904       (path, login))
1905 {
1906         int netresult;
1907         const char *path_ext;
1908         const char *login_ext;
1909
1910         CHECK_STRING(path);
1911         CHECK_STRING(login);
1912
1913         /* netunam, being a strange-o system call only used once, is not
1914            encapsulated. */
1915
1916         LISP_STRING_TO_EXTERNAL(path, path_ext, Qfile_name);
1917         LISP_STRING_TO_EXTERNAL(login, login_ext, Qnative);
1918
1919         netresult = netunam(path_ext, login_ext);
1920
1921         return netresult == -1 ? Qnil : Qt;
1922 }
1923 #endif                          /* HPUX_NET */
1924 \f
1925 DEFUN("file-name-absolute-p", Ffile_name_absolute_p, 1, 1, 0,   /*
1926 Return t if file FILENAME specifies an absolute path name.
1927 On Unix, this is a name starting with a `/' or a `~'.
1928 */
1929       (filename))
1930 {
1931         /* This function does not GC */
1932         Bufbyte *ptr;
1933
1934         CHECK_STRING(filename);
1935         ptr = XSTRING_DATA(filename);
1936         return (IS_DIRECTORY_SEP(*ptr) || *ptr == '~'
1937             )? Qt : Qnil;
1938 }
1939 \f
1940 /* Return nonzero if file FILENAME exists and can be executed.  */
1941
1942 static int check_executable(char *filename)
1943 {
1944 #ifdef HAVE_EACCESS
1945         return eaccess(filename, X_OK) >= 0;
1946 #else
1947         /* Access isn't quite right because it uses the real uid
1948            and we really want to test with the effective uid.
1949            But Unix doesn't give us a right way to do it.  */
1950         return access(filename, X_OK) >= 0;
1951 #endif                          /* HAVE_EACCESS */
1952 }
1953
1954 /* Return nonzero if file FILENAME exists and can be written.  */
1955
1956 static int check_writable(const char *filename)
1957 {
1958 #ifdef HAVE_EACCESS
1959         return (eaccess(filename, W_OK) >= 0);
1960 #else
1961         /* Access isn't quite right because it uses the real uid
1962            and we really want to test with the effective uid.
1963            But Unix doesn't give us a right way to do it.
1964            Opening with O_WRONLY could work for an ordinary file,
1965            but would lose for directories.  */
1966         return (access(filename, W_OK) >= 0);
1967 #endif
1968 }
1969
1970 DEFUN("file-exists-p", Ffile_exists_p, 1, 1, 0, /*
1971 Return t if file FILENAME exists.  (This does not mean you can read it.)
1972 See also `file-readable-p' and `file-attributes'.
1973 */
1974       (filename))
1975 {
1976         /* This function can call lisp; GC checked 2000-07-11 ben */
1977         Lisp_Object abspath;
1978         Lisp_Object handler;
1979         struct stat statbuf;
1980         struct gcpro gcpro1;
1981
1982         CHECK_STRING(filename);
1983         abspath = Fexpand_file_name(filename, Qnil);
1984
1985         /* If the file name has special constructs in it,
1986            call the corresponding file handler.  */
1987         GCPRO1(abspath);
1988         handler = Ffind_file_name_handler(abspath, Qfile_exists_p);
1989         UNGCPRO;
1990         if (!NILP(handler))
1991                 return call2(handler, Qfile_exists_p, abspath);
1992
1993         return sxemacs_stat((char *)XSTRING_DATA(abspath),
1994                            &statbuf) >= 0 ? Qt : Qnil;
1995 }
1996
1997 DEFUN("file-executable-p", Ffile_executable_p, 1, 1, 0, /*
1998 Return t if FILENAME can be executed by you.
1999 For a directory, this means you can access files in that directory.
2000 */
2001       (filename))
2002 {
2003         /* This function can GC.  GC checked 07-11-2000 ben. */
2004         Lisp_Object abspath;
2005         Lisp_Object handler;
2006         struct gcpro gcpro1;
2007
2008         CHECK_STRING(filename);
2009         abspath = Fexpand_file_name(filename, Qnil);
2010
2011         /* If the file name has special constructs in it,
2012            call the corresponding file handler.  */
2013         GCPRO1(abspath);
2014         handler = Ffind_file_name_handler(abspath, Qfile_executable_p);
2015         UNGCPRO;
2016         if (!NILP(handler))
2017                 return call2(handler, Qfile_executable_p, abspath);
2018
2019         return check_executable((char *)XSTRING_DATA(abspath)) ? Qt : Qnil;
2020 }
2021
2022 DEFUN("file-readable-p", Ffile_readable_p, 1, 1, 0,     /*
2023 Return t if file FILENAME exists and you can read it.
2024 See also `file-exists-p' and `file-attributes'.
2025 */
2026       (filename))
2027 {
2028         /* This function can GC */
2029         Lisp_Object abspath = Qnil;
2030         Lisp_Object handler;
2031         struct gcpro gcpro1;
2032         GCPRO1(abspath);
2033
2034         CHECK_STRING(filename);
2035         abspath = Fexpand_file_name(filename, Qnil);
2036
2037         /* If the file name has special constructs in it,
2038            call the corresponding file handler.  */
2039         handler = Ffind_file_name_handler(abspath, Qfile_readable_p);
2040         if (!NILP(handler))
2041                 RETURN_UNGCPRO(call2(handler, Qfile_readable_p, abspath));
2042
2043         {
2044                 int desc =
2045                     interruptible_open((char *)XSTRING_DATA(abspath),
2046                                        O_RDONLY | OPEN_BINARY, 0);
2047                 UNGCPRO;
2048                 if (desc < 0)
2049                         return Qnil;
2050                 close(desc);
2051                 return Qt;
2052         }
2053 }
2054
2055 /* Having this before file-symlink-p mysteriously caused it to be forgotten
2056    on the RT/PC.  */
2057 DEFUN("file-writable-p", Ffile_writable_p, 1, 1, 0,     /*
2058 Return t if file FILENAME can be written or created by you.
2059 */
2060       (filename))
2061 {
2062         /* This function can GC.  GC checked 1997.04.10. */
2063         Lisp_Object abspath, dir;
2064         Lisp_Object handler;
2065         struct stat statbuf;
2066         struct gcpro gcpro1;
2067
2068         CHECK_STRING(filename);
2069         abspath = Fexpand_file_name(filename, Qnil);
2070
2071         /* If the file name has special constructs in it,
2072            call the corresponding file handler.  */
2073         GCPRO1(abspath);
2074         handler = Ffind_file_name_handler(abspath, Qfile_writable_p);
2075         UNGCPRO;
2076         if (!NILP(handler))
2077                 return call2(handler, Qfile_writable_p, abspath);
2078
2079         if (sxemacs_stat((char *)XSTRING_DATA(abspath), &statbuf) >= 0)
2080                 return (check_writable((char *)XSTRING_DATA(abspath))
2081                         ? Qt : Qnil);
2082
2083         GCPRO1(abspath);
2084         dir = Ffile_name_directory(abspath);
2085         UNGCPRO;
2086         return (check_writable(!NILP(dir) ? (char *)XSTRING_DATA(dir)
2087                                : "")
2088                 ? Qt : Qnil);
2089 }
2090
2091 DEFUN("file-symlink-p", Ffile_symlink_p, 1, 1, 0,       /*
2092 Return non-nil if file FILENAME is the name of a symbolic link.
2093 The value is the name of the file to which it is linked.
2094 Otherwise returns nil.
2095 */
2096       (filename))
2097 {
2098         /* This function can GC.  GC checked 1997.04.10. */
2099         /* XEmacs change: run handlers even if local machine doesn't have symlinks */
2100 #ifdef S_IFLNK
2101         char *buf;
2102         int bufsize;
2103         int valsize;
2104         Lisp_Object val;
2105 #endif
2106         Lisp_Object handler;
2107         struct gcpro gcpro1;
2108
2109         CHECK_STRING(filename);
2110         filename = Fexpand_file_name(filename, Qnil);
2111
2112         /* If the file name has special constructs in it,
2113            call the corresponding file handler.  */
2114         GCPRO1(filename);
2115         handler = Ffind_file_name_handler(filename, Qfile_symlink_p);
2116         UNGCPRO;
2117         if (!NILP(handler)) {
2118                 return call2(handler, Qfile_symlink_p, filename);
2119         }
2120 #ifdef S_IFLNK
2121         bufsize = 100;
2122         while (1) {
2123                 buf = ynew_array_and_zero(char, bufsize);
2124                 valsize = readlink((char *)XSTRING_DATA(filename),
2125                                    buf, bufsize);
2126                 if (valsize < bufsize) {
2127                         break;
2128                 }
2129                 /* Buffer was not long enough */
2130                 yfree(buf);
2131                 bufsize *= 2;
2132         }
2133         if (valsize == -1) {
2134                 yfree(buf);
2135                 return Qnil;
2136         }
2137         val = make_string((Bufbyte*)buf, valsize);
2138         yfree(buf);
2139         return val;
2140 #else                           /* not S_IFLNK */
2141         return Qnil;
2142 #endif                          /* not S_IFLNK */
2143 }
2144
2145 DEFUN("file-directory-p", Ffile_directory_p, 1, 1, 0,   /*
2146 Return t if file FILENAME is the name of a directory as a file.
2147 A directory name spec may be given instead; then the value is t
2148 if the directory so specified exists and really is a directory.
2149 */
2150       (filename))
2151 {
2152         /* This function can GC.  GC checked 1997.04.10. */
2153         Lisp_Object abspath;
2154         struct stat st;
2155         Lisp_Object handler;
2156         struct gcpro gcpro1;
2157
2158         GCPRO1(current_buffer->directory);
2159         abspath = expand_and_dir_to_file(filename, current_buffer->directory);
2160         UNGCPRO;
2161
2162         /* If the file name has special constructs in it,
2163            call the corresponding file handler.  */
2164         GCPRO1(abspath);
2165         handler = Ffind_file_name_handler(abspath, Qfile_directory_p);
2166         UNGCPRO;
2167         if (!NILP(handler))
2168                 return call2(handler, Qfile_directory_p, abspath);
2169
2170         if (sxemacs_stat((char *)XSTRING_DATA(abspath), &st) < 0)
2171                 return Qnil;
2172         return (st.st_mode & S_IFMT) == S_IFDIR ? Qt : Qnil;
2173 }
2174
2175 DEFUN("file-accessible-directory-p", Ffile_accessible_directory_p, 1, 1, 0,     /*
2176 Return t if file FILENAME is the name of a directory as a file,
2177 and files in that directory can be opened by you.  In order to use a
2178 directory as a buffer's current directory, this predicate must return true.
2179 A directory name spec may be given instead; then the value is t
2180 if the directory so specified exists and really is a readable and
2181 searchable directory.
2182 */
2183       (filename))
2184 {
2185         /* This function can GC.  GC checked 1997.04.10. */
2186         Lisp_Object handler;
2187
2188         /* If the file name has special constructs in it,
2189            call the corresponding file handler.  */
2190         handler =
2191             Ffind_file_name_handler(filename, Qfile_accessible_directory_p);
2192         if (!NILP(handler))
2193                 return call2(handler, Qfile_accessible_directory_p, filename);
2194
2195         if (NILP(Ffile_directory_p(filename)))
2196                 return (Qnil);
2197         else
2198                 return Ffile_executable_p(filename);
2199 }
2200
2201 DEFUN("file-regular-p", Ffile_regular_p, 1, 1, 0,       /*
2202 Return t if file FILENAME is the name of a regular file.
2203 This is the sort of file that holds an ordinary stream of data bytes.
2204 */
2205       (filename))
2206 {
2207         /* This function can GC.  GC checked 1997.04.10. */
2208         Lisp_Object abspath;
2209         struct stat st;
2210         Lisp_Object handler;
2211         struct gcpro gcpro1;
2212
2213         GCPRO1(current_buffer->directory);
2214         abspath = expand_and_dir_to_file(filename, current_buffer->directory);
2215         UNGCPRO;
2216
2217         /* If the file name has special constructs in it,
2218            call the corresponding file handler.  */
2219         GCPRO1(abspath);
2220         handler = Ffind_file_name_handler(abspath, Qfile_regular_p);
2221         UNGCPRO;
2222         if (!NILP(handler))
2223                 return call2(handler, Qfile_regular_p, abspath);
2224
2225         if (sxemacs_stat((char *)XSTRING_DATA(abspath), &st) < 0)
2226                 return Qnil;
2227         return (st.st_mode & S_IFMT) == S_IFREG ? Qt : Qnil;
2228 }
2229 \f
2230 DEFUN("file-modes", Ffile_modes, 1, 1, 0,       /*
2231 Return mode bits of file named FILENAME, as an integer.
2232 */
2233       (filename))
2234 {
2235         /* This function can GC.  GC checked 1997.04.10. */
2236         Lisp_Object abspath;
2237         struct stat st;
2238         Lisp_Object handler;
2239         struct gcpro gcpro1;
2240
2241         GCPRO1(current_buffer->directory);
2242         abspath = expand_and_dir_to_file(filename, current_buffer->directory);
2243         UNGCPRO;
2244
2245         /* If the file name has special constructs in it,
2246            call the corresponding file handler.  */
2247         GCPRO1(abspath);
2248         handler = Ffind_file_name_handler(abspath, Qfile_modes);
2249         UNGCPRO;
2250         if (!NILP(handler))
2251                 return call2(handler, Qfile_modes, abspath);
2252
2253         if (sxemacs_stat((char *)XSTRING_DATA(abspath), &st) < 0)
2254                 return Qnil;
2255         /* Syncing with FSF 19.34.6 note: not in FSF, #if 0'ed out here. */
2256
2257         return make_int(st.st_mode & 07777);
2258 }
2259
2260 DEFUN("set-file-modes", Fset_file_modes, 2, 2, 0,       /*
2261 Set mode bits of file named FILENAME to MODE (an integer).
2262 Only the 12 low bits of MODE are used.
2263 */
2264       (filename, mode))
2265 {
2266         /* This function can GC.  GC checked 1997.04.10. */
2267         Lisp_Object abspath;
2268         Lisp_Object handler;
2269         struct gcpro gcpro1;
2270
2271         GCPRO1(current_buffer->directory);
2272         abspath = Fexpand_file_name(filename, current_buffer->directory);
2273         UNGCPRO;
2274
2275         CHECK_INT(mode);
2276
2277         /* If the file name has special constructs in it,
2278            call the corresponding file handler.  */
2279         GCPRO1(abspath);
2280         handler = Ffind_file_name_handler(abspath, Qset_file_modes);
2281         UNGCPRO;
2282         if (!NILP(handler))
2283                 return call3(handler, Qset_file_modes, abspath, mode);
2284
2285         if (chmod((char *)XSTRING_DATA(abspath), XINT(mode)) < 0)
2286                 report_file_error("Doing chmod", list1(abspath));
2287
2288         return Qnil;
2289 }
2290
2291 DEFUN("set-default-file-modes", Fset_default_file_modes, 1, 1, 0,       /*
2292 Set the file permission bits for newly created files.
2293 The argument MODE should be an integer; if a bit in MODE is 1,
2294 subsequently created files will not have the permission corresponding
2295 to that bit enabled.  Only the low 9 bits are used.
2296 This setting is inherited by subprocesses.
2297 */
2298       (mode))
2299 {
2300         CHECK_INT(mode);
2301
2302         umask((~XINT(mode)) & 0777);
2303
2304         return Qnil;
2305 }
2306
2307 DEFUN("default-file-modes", Fdefault_file_modes, 0, 0, 0,       /*
2308 Return the default file protection for created files.
2309 The umask value determines which permissions are enabled in newly
2310 created files.  If a permission's bit in the umask is 1, subsequently
2311 created files will not have that permission enabled.
2312 */
2313       ())
2314 {
2315         int mode;
2316
2317         mode = umask(0);
2318         umask(mode);
2319
2320         return make_int((~mode) & 0777);
2321 }
2322 \f
2323 DEFUN("unix-sync", Funix_sync, 0, 0, "",        /*
2324 Tell Unix to finish all pending disk updates.
2325 */
2326       ())
2327 {
2328         sync();
2329         return Qnil;
2330 }
2331 \f
2332 DEFUN("file-newer-than-file-p", Ffile_newer_than_file_p, 2, 2, 0,       /*
2333 Return t if file FILE1 is newer than file FILE2.
2334 If FILE1 does not exist, the answer is nil;
2335 otherwise, if FILE2 does not exist, the answer is t.
2336 */
2337       (file1, file2))
2338 {
2339         /* This function can GC.  GC checked 1997.04.10. */
2340         Lisp_Object abspath1, abspath2;
2341         struct stat st;
2342         int mtime1;
2343         Lisp_Object handler;
2344         struct gcpro gcpro1, gcpro2, gcpro3;
2345
2346         CHECK_STRING(file1);
2347         CHECK_STRING(file2);
2348
2349         abspath1 = Qnil;
2350         abspath2 = Qnil;
2351
2352         GCPRO3(abspath1, abspath2, current_buffer->directory);
2353         abspath1 = expand_and_dir_to_file(file1, current_buffer->directory);
2354         abspath2 = expand_and_dir_to_file(file2, current_buffer->directory);
2355
2356         /* If the file name has special constructs in it,
2357            call the corresponding file handler.  */
2358         handler = Ffind_file_name_handler(abspath1, Qfile_newer_than_file_p);
2359         if (NILP(handler))
2360                 handler =
2361                     Ffind_file_name_handler(abspath2, Qfile_newer_than_file_p);
2362         UNGCPRO;
2363         if (!NILP(handler))
2364                 return call3(handler, Qfile_newer_than_file_p, abspath1,
2365                              abspath2);
2366
2367         if (sxemacs_stat((char *)XSTRING_DATA(abspath1), &st) < 0)
2368                 return Qnil;
2369
2370         mtime1 = st.st_mtime;
2371
2372         if (sxemacs_stat((char *)XSTRING_DATA(abspath2), &st) < 0)
2373                 return Qt;
2374
2375         return (mtime1 > st.st_mtime) ? Qt : Qnil;
2376 }
2377 \f
2378 /* Stack sizes > 2**16 is a good way to elicit compiler bugs */
2379 /* #define READ_BUF_SIZE (2 << 16) */
2380 #define READ_BUF_SIZE (1 << 15)
2381
2382 DEFUN("insert-file-contents-internal", Finsert_file_contents_internal, 1, 7, 0, /*
2383 Insert contents of file FILENAME after point; no coding-system frobbing.
2384 This function is identical to `insert-file-contents' except for the
2385 handling of the CODESYS and USED-CODESYS arguments under
2386 SXEmacs/Mule. (When Mule support is not present, both functions are
2387 identical and ignore the CODESYS and USED-CODESYS arguments.)
2388
2389 If support for Mule exists in this Emacs, the file is decoded according
2390 to CODESYS; if omitted, no conversion happens.  If USED-CODESYS is non-nil,
2391 it should be a symbol, and the actual coding system that was used for the
2392 decoding is stored into it.  It will in general be different from CODESYS
2393 if CODESYS specifies automatic encoding detection or end-of-line detection.
2394
2395 Currently START and END refer to byte positions (as opposed to character
2396 positions), even in Mule. (Fixing this is very difficult.)
2397 */
2398       (filename, visit, start, end, replace, codesys, used_codesys))
2399 {
2400         /* This function can call lisp */
2401         struct stat st;
2402         int fd;
2403         int saverrno = 0;
2404         Charcount inserted = 0;
2405         int speccount;
2406         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
2407         Lisp_Object handler = Qnil, val = Qnil;
2408         int total;
2409         Bufbyte read_buf[READ_BUF_SIZE];
2410         int mc_count;
2411         struct buffer *buf = current_buffer;
2412         Lisp_Object curbuf;
2413         int not_regular = 0;
2414
2415         if (UNLIKELY(buf->base_buffer && !NILP(visit))) {
2416                 error("Cannot do file visiting in an indirect buffer");
2417         }
2418
2419         /* No need to call Fbarf_if_buffer_read_only() here.
2420            That's called in begin_multiple_change() or wherever. */
2421         /* #### dmoore - should probably check in various places to see if
2422            curbuf was killed and if so signal an error? */
2423         XSETBUFFER(curbuf, buf);
2424
2425         GCPRO5(filename, val, visit, handler, curbuf);
2426
2427         if (LIKELY(NILP(replace))) {
2428                 mc_count = begin_multiple_change(buf, BUF_PT(buf), BUF_PT(buf));
2429         } else {
2430                 mc_count = begin_multiple_change(buf, BUF_BEG(buf), BUF_Z(buf));
2431         }
2432
2433         /* begin_multiple_change also adds an unwind_protect */
2434         speccount = specpdl_depth();
2435
2436         filename = Fexpand_file_name(filename, Qnil);
2437
2438         /* If the file name has special constructs in it,
2439            call the corresponding file handler.  */
2440         handler = Ffind_file_name_handler(filename, Qinsert_file_contents);
2441         if (!NILP(handler)) {
2442                 val = call6(handler, Qinsert_file_contents, filename,
2443                             visit, start, end, replace);
2444                 goto handled;
2445         }
2446 #ifdef FILE_CODING
2447         if (!NILP(used_codesys))
2448                 CHECK_SYMBOL(used_codesys);
2449 #endif
2450
2451         if ((!NILP(start) || !NILP(end)) && !NILP(visit))
2452                 error("Attempt to visit less than an entire file");
2453
2454         fd = -1;
2455
2456         if (sxemacs_stat((char *)XSTRING_DATA(filename), &st) < 0) {
2457                 if (fd >= 0)
2458                         close(fd);
2459               badopen:
2460                 if (NILP(visit))
2461                         report_file_error("Opening input file",
2462                                           list1(filename));
2463                 st.st_mtime = -1;
2464                 goto notfound;
2465         }
2466 #ifdef S_IFREG
2467         /* Signal an error if we are accessing a non-regular file, with
2468            REPLACE, START or END being non-nil.  */
2469         if (!S_ISREG(st.st_mode)) {
2470                 not_regular = 1;
2471
2472                 if (!NILP(visit))
2473                         goto notfound;
2474
2475                 if (!NILP(replace) || !NILP(start) || !NILP(end)) {
2476                         end_multiple_change(buf, mc_count);
2477
2478                         RETURN_UNGCPRO
2479                             (Fsignal(Qfile_error,
2480                                      list2(build_translated_string
2481                                            ("not a regular file"), filename)));
2482                 }
2483         }
2484 #endif                          /* S_IFREG */
2485
2486         if (!NILP(start))
2487                 CHECK_INT(start);
2488         else
2489                 start = Qzero;
2490
2491         if (!NILP(end))
2492                 CHECK_INT(end);
2493
2494         if (fd < 0) {
2495                 if ((fd = interruptible_open((char *)XSTRING_DATA(filename),
2496                                              O_RDONLY | OPEN_BINARY, 0)) < 0)
2497                         goto badopen;
2498         }
2499
2500         /* Replacement should preserve point as it preserves markers.  */
2501         if (!NILP(replace))
2502                 record_unwind_protect(restore_point_unwind,
2503                                       Fpoint_marker(Qnil, Qnil));
2504
2505         record_unwind_protect(close_file_unwind, make_int(fd));
2506
2507         /* Supposedly happens on VMS.  */
2508         if (st.st_size < 0)
2509                 error("File size is negative");
2510
2511         if (NILP(end)) {
2512                 if (!not_regular) {
2513                         end = make_int(st.st_size);
2514                         if (XINT(end) != st.st_size)
2515                                 error("Maximum buffer size exceeded");
2516                 }
2517         }
2518
2519         /* If requested, replace the accessible part of the buffer
2520            with the file contents.  Avoid replacing text at the
2521            beginning or end of the buffer that matches the file contents;
2522            that preserves markers pointing to the unchanged parts.  */
2523 #if !defined (FILE_CODING)
2524         /* The replace-mode code currently only works when the assumption
2525            'one byte == one char' holds true.  This fails Mule because
2526            files may contain multibyte characters.  It holds under Windows NT
2527            provided we convert CRLF into LF. */
2528 # define FSFMACS_SPEEDY_INSERT
2529 #endif                          /* !defined (FILE_CODING) */
2530
2531 #ifndef FSFMACS_SPEEDY_INSERT
2532         if (!NILP(replace)) {
2533                 buffer_delete_range(buf, BUF_BEG(buf), BUF_Z(buf),
2534                                     !NILP(visit) ? INSDEL_NO_LOCKING : 0);
2535         }
2536 #else                           /* FSFMACS_SPEEDY_INSERT */
2537         if (!NILP(replace)) {
2538                 char buffer[1 << 14];
2539                 Bufpos same_at_start = BUF_BEGV(buf);
2540                 Bufpos same_at_end = BUF_ZV(buf);
2541                 int overlap;
2542
2543                 /* Count how many chars at the start of the file
2544                    match the text at the beginning of the buffer.  */
2545                 while (1) {
2546                         int nread;
2547                         Bufpos bufpos;
2548                         nread = read_allowing_quit(fd, buffer, sizeof buffer);
2549                         if (nread < 0)
2550                                 error("IO error reading %s: %s",
2551                                       XSTRING_DATA(filename), strerror(errno));
2552                         else if (nread == 0)
2553                                 break;
2554                         bufpos = 0;
2555                         while (bufpos < nread && same_at_start < BUF_ZV(buf)
2556                                && BUF_FETCH_CHAR(buf,
2557                                                  same_at_start) ==
2558                                buffer[bufpos])
2559                                 same_at_start++, bufpos++;
2560                         /* If we found a discrepancy, stop the scan.
2561                            Otherwise loop around and scan the next bufferful.  */
2562                         if (bufpos != nread)
2563                                 break;
2564                 }
2565                 /* If the file matches the buffer completely,
2566                    there's no need to replace anything.  */
2567                 if (same_at_start - BUF_BEGV(buf) == st.st_size) {
2568                         close(fd);
2569                         unbind_to(speccount, Qnil);
2570                         /* Truncate the buffer to the size of the file.  */
2571                         buffer_delete_range(buf, same_at_start, same_at_end,
2572                                             !NILP(visit) ? INSDEL_NO_LOCKING :
2573                                             0);
2574                         goto handled;
2575                 }
2576                 /* Count how many chars at the end of the file
2577                    match the text at the end of the buffer.  */
2578                 while (1) {
2579                         int total_read, nread;
2580                         Bufpos bufpos, curpos, trial;
2581
2582                         /* At what file position are we now scanning?  */
2583                         curpos = st.st_size - (BUF_ZV(buf) - same_at_end);
2584                         /* If the entire file matches the buffer tail, stop the scan.  */
2585                         if (curpos == 0)
2586                                 break;
2587                         /* How much can we scan in the next step?  */
2588                         trial = min(curpos, (Bufpos) sizeof(buffer));
2589                         if (lseek(fd, curpos - trial, 0) < 0)
2590                                 report_file_error("Setting file position",
2591                                                   list1(filename));
2592
2593                         total_read = 0;
2594                         while (total_read < trial) {
2595                                 nread =
2596                                     read_allowing_quit(fd, buffer + total_read,
2597                                                        trial - total_read);
2598                                 if (nread <= 0)
2599                                         report_file_error
2600                                             ("IO error reading file",
2601                                              list1(filename));
2602                                 total_read += nread;
2603                         }
2604                         /* Scan this bufferful from the end, comparing with
2605                            the Emacs buffer.  */
2606                         bufpos = total_read;
2607                         /* Compare with same_at_start to avoid counting some buffer text
2608                            as matching both at the file's beginning and at the end.  */
2609                         while (bufpos > 0 && same_at_end > same_at_start
2610                                && BUF_FETCH_CHAR(buf, same_at_end - 1) ==
2611                                buffer[bufpos - 1])
2612                                 same_at_end--, bufpos--;
2613                         /* If we found a discrepancy, stop the scan.
2614                            Otherwise loop around and scan the preceding bufferful.  */
2615                         if (bufpos != 0)
2616                                 break;
2617                         /* If display current starts at beginning of line,
2618                            keep it that way.  */
2619                         if (XBUFFER(XWINDOW(Fselected_window(Qnil))->buffer) ==
2620                             buf)
2621                                 XWINDOW(Fselected_window(Qnil))->
2622                                     start_at_line_beg =
2623                                     !NILP(Fbolp(make_buffer(buf)));
2624                 }
2625
2626                 /* Don't try to reuse the same piece of text twice.  */
2627                 overlap = same_at_start - BUF_BEGV(buf) -
2628                     (same_at_end + st.st_size - BUF_ZV(buf));
2629                 if (overlap > 0)
2630                         same_at_end += overlap;
2631
2632                 /* Arrange to read only the nonmatching middle part of the file.  */
2633                 start = make_int(same_at_start - BUF_BEGV(buf));
2634                 end = make_int(st.st_size - (BUF_ZV(buf) - same_at_end));
2635
2636                 buffer_delete_range(buf, same_at_start, same_at_end,
2637                                     !NILP(visit) ? INSDEL_NO_LOCKING : 0);
2638                 /* Insert from the file at the proper position.  */
2639                 BUF_SET_PT(buf, same_at_start);
2640         }
2641 #endif                          /* FSFMACS_SPEEDY_INSERT */
2642
2643         if (!not_regular) {
2644                 total = XINT(end) - XINT(start);
2645
2646                 /* Make sure point-max won't overflow after this insertion.  */
2647                 if (total != XINT(make_int(total)))
2648                         error("Maximum buffer size exceeded");
2649         } else
2650                 /* For a special file, all we can do is guess.  The value of -1
2651                    will make the stream functions read as much as possible.  */
2652                 total = -1;
2653
2654         if (XINT(start) != 0
2655 #ifdef FSFMACS_SPEEDY_INSERT
2656             /* why was this here? asked jwz.  The reason is that the replace-mode
2657                connivings above will normally put the file pointer other than
2658                where it should be. */
2659             || !NILP(replace)
2660 #endif                          /* !FSFMACS_SPEEDY_INSERT */
2661             ) {
2662                 if (lseek(fd, XINT(start), 0) < 0)
2663                         report_file_error("Setting file position",
2664                                           list1(filename));
2665         }
2666
2667         {
2668                 Bufpos cur_point = BUF_PT(buf);
2669                 struct gcpro ngcpro1;
2670                 Lisp_Object stream = make_filedesc_input_stream(fd, 0, total,
2671                                                                 LSTR_ALLOW_QUIT);
2672
2673                 NGCPRO1(stream);
2674                 Lstream_set_buffering(XLSTREAM(stream), LSTREAM_BLOCKN_BUFFERED,
2675                                       65536);
2676 #ifdef FILE_CODING
2677                 stream = make_decoding_input_stream
2678                     (XLSTREAM(stream), Fget_coding_system(codesys));
2679                 Lstream_set_character_mode(XLSTREAM(stream));
2680                 Lstream_set_buffering(XLSTREAM(stream), LSTREAM_BLOCKN_BUFFERED,
2681                                       65536);
2682 #endif                          /* FILE_CODING */
2683
2684                 record_unwind_protect(delete_stream_unwind, stream);
2685
2686                 /* No need to limit the amount of stuff we attempt to read. (It would
2687                    be incorrect, anyway, when Mule is enabled.) Instead, the limiting
2688                    occurs inside of the filedesc stream. */
2689                 while (1) {
2690                         Lstream_data_count this_len;
2691                         Charcount cc_inserted;
2692
2693                         QUIT;
2694                         this_len = Lstream_read(XLSTREAM(stream), read_buf,
2695                                                 sizeof(read_buf));
2696
2697                         if (this_len <= 0) {
2698                                 if (this_len < 0)
2699                                         saverrno = errno;
2700                                 break;
2701                         }
2702
2703                         cc_inserted =
2704                             buffer_insert_raw_string_1(buf, cur_point, read_buf,
2705                                                        this_len, !NILP(visit)
2706                                                        ? INSDEL_NO_LOCKING : 0);
2707                         inserted += cc_inserted;
2708                         cur_point += cc_inserted;
2709                 }
2710 #ifdef FILE_CODING
2711                 if (!NILP(used_codesys)) {
2712                         Lisp_Object tmp =
2713                                 decoding_stream_coding_system(XLSTREAM(stream));
2714                         Fset(used_codesys, XCODING_SYSTEM_NAME(tmp));
2715                 }
2716 #endif                          /* FILE_CODING */
2717                 NUNGCPRO;
2718         }
2719
2720         /* Close the file/stream */
2721         unbind_to(speccount, Qnil);
2722
2723         if (saverrno != 0) {
2724                 error("IO error reading %s: %s",
2725                       XSTRING_DATA(filename), strerror(saverrno));
2726         }
2727
2728       notfound:
2729       handled:
2730
2731         end_multiple_change(buf, mc_count);
2732
2733         if (!NILP(visit)) {
2734                 if (!EQ(buf->undo_list, Qt))
2735                         buf->undo_list = Qnil;
2736                 if (NILP(handler)) {
2737                         buf->modtime = st.st_mtime;
2738                         buf->filename = filename;
2739                         /* XEmacs addition: */
2740                         /* This function used to be in C, ostensibly so that
2741                            it could be called here.  But that's just silly.
2742                            There's no reason C code can't call out to Lisp
2743                            code, and it's a lot cleaner this way. */
2744                         /*  Note: compute-buffer-file-truename is called for
2745                            side-effect!  Its return value is intentionally
2746                            ignored. */
2747                         if (!NILP(Ffboundp(Qcompute_buffer_file_truename)))
2748                                 call1(Qcompute_buffer_file_truename,
2749                                       make_buffer(buf));
2750                 }
2751                 BUF_SAVE_MODIFF(buf) = BUF_MODIFF(buf);
2752                 buf->auto_save_modified = BUF_MODIFF(buf);
2753                 buf->saved_size = make_int(BUF_SIZE(buf));
2754 #ifdef CLASH_DETECTION
2755                 if (NILP(handler)) {
2756                         if (!NILP(buf->file_truename))
2757                                 unlock_file(buf->file_truename);
2758                         unlock_file(filename);
2759                 }
2760 #endif                          /* CLASH_DETECTION */
2761                 if (not_regular)
2762                         RETURN_UNGCPRO(Fsignal(Qfile_error,
2763                                                list2(build_string
2764                                                      ("not a regular file"),
2765                                                      filename)));
2766
2767                 /* If visiting nonexistent file, return nil.  */
2768                 if (buf->modtime == -1)
2769                         report_file_error("Opening input file",
2770                                           list1(filename));
2771         }
2772
2773         /* Decode file format */
2774         if (inserted > 0) {
2775                 Lisp_Object insval = call3(Qformat_decode,
2776                                            Qnil, make_int(inserted), visit);
2777                 CHECK_INT(insval);
2778                 inserted = XINT(insval);
2779         }
2780
2781         if (inserted > 0) {
2782                 Lisp_Object p;
2783                 struct gcpro ngcpro1;
2784
2785                 NGCPRO1(p);
2786                 EXTERNAL_LIST_LOOP(p, Vafter_insert_file_functions) {
2787                         Lisp_Object insval = call1(XCAR(p), make_int(inserted));
2788                         if (!NILP(insval)) {
2789                                 CHECK_NATNUM(insval);
2790                                 inserted = XINT(insval);
2791                         }
2792                         QUIT;
2793                 }
2794                 NUNGCPRO;
2795         }
2796
2797         UNGCPRO;
2798
2799         if (!NILP(val))
2800                 return (val);
2801         else
2802                 return (list2(filename, make_int(inserted)));
2803 }
2804 \f
2805 static int a_write(Lisp_Object outstream, Lisp_Object instream, int pos,
2806                    Lisp_Object * annot);
2807 static Lisp_Object build_annotations(Lisp_Object start, Lisp_Object end);
2808
2809 /* If build_annotations switched buffers, switch back to BUF.
2810    Kill the temporary buffer that was selected in the meantime.  */
2811
2812 static Lisp_Object build_annotations_unwind(Lisp_Object buf)
2813 {
2814         Lisp_Object tembuf;
2815
2816         if (XBUFFER(buf) == current_buffer)
2817                 return Qnil;
2818         tembuf = Fcurrent_buffer();
2819         Fset_buffer(buf);
2820         Fkill_buffer(tembuf);
2821         return Qnil;
2822 }
2823
2824 DEFUN("write-region-internal", Fwrite_region_internal, 3, 7, "r\nFWrite region to file: ",      /*
2825 Write current region into specified file; no coding-system frobbing.
2826 This function is identical to `write-region' except for the handling
2827 of the CODESYS argument under SXEmacs/Mule. (When Mule support is not
2828 present, both functions are identical and ignore the CODESYS argument.)
2829 If support for Mule exists in this Emacs, the file is encoded according
2830 to the value of CODESYS.  If this is nil, no code conversion occurs.
2831
2832 As a special kludge to support auto-saving, when START is nil START and
2833 END are set to the beginning and end, respectively, of the buffer,
2834 regardless of any restrictions.  Don't use this feature.  It is documented
2835 here because write-region handler writers need to be aware of it.
2836 */
2837       (start, end, filename, append, visit, lockname, codesys))
2838 {
2839         /* This function can call lisp.  GC checked 2000-07-28 ben */
2840         int desc;
2841         int failure, stat_res;
2842         int save_errno = 0;
2843         struct stat st;
2844         Lisp_Object fn = Qnil;
2845         int speccount = specpdl_depth();
2846         int visiting_other = STRINGP(visit);
2847         int visiting = (EQ(visit, Qt) || visiting_other);
2848         int quietly = (!visiting && !NILP(visit));
2849         Lisp_Object visit_file = Qnil;
2850         Lisp_Object annotations = Qnil;
2851         struct buffer *given_buffer;
2852         Bufpos start1, end1;
2853         struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
2854         struct gcpro ngcpro1, ngcpro2;
2855         Lisp_Object curbuf;
2856
2857         XSETBUFFER(curbuf, current_buffer);
2858
2859         /* start, end, visit, and append are never modified in this fun
2860            so we don't protect them. */
2861         GCPRO5(visit_file, filename, codesys, lockname, annotations);
2862         NGCPRO2(curbuf, fn);
2863
2864         /* [[ dmoore - if Fexpand_file_name or handlers kill the buffer,
2865            we should signal an error rather than blissfully continuing
2866            along.  ARGH, this function is going to lose lose lose.  We need
2867            to protect the current_buffer from being destroyed, but the
2868            multiple return points make this a pain in the butt. ]] we do
2869            protect curbuf now. --ben */
2870
2871 #ifdef FILE_CODING
2872         codesys = Fget_coding_system(codesys);
2873 #endif                          /* FILE_CODING */
2874
2875         if (current_buffer->base_buffer && !NILP(visit))
2876                 invalid_operation
2877                     ("Cannot do file visiting in an indirect buffer", curbuf);
2878
2879         if (!NILP(start) && !STRINGP(start))
2880                 get_buffer_range_char(current_buffer, start, end, &start1,
2881                                       &end1, 0);
2882
2883         {
2884                 Lisp_Object handler;
2885
2886                 if (visiting_other)
2887                         visit_file = Fexpand_file_name(visit, Qnil);
2888                 else
2889                         visit_file = filename;
2890                 filename = Fexpand_file_name(filename, Qnil);
2891
2892                 if (NILP(lockname))
2893                         lockname = visit_file;
2894
2895                 /* We used to UNGCPRO here.  BAD!  visit_file is used below after
2896                    more Lisp calling. */
2897                 /* If the file name has special constructs in it,
2898                    call the corresponding file handler.  */
2899                 handler = Ffind_file_name_handler(filename, Qwrite_region);
2900                 /* If FILENAME has no handler, see if VISIT has one.  */
2901                 if (NILP(handler) && STRINGP(visit))
2902                         handler = Ffind_file_name_handler(visit, Qwrite_region);
2903
2904                 if (!NILP(handler)) {
2905                         Lisp_Object val =
2906                             call8(handler, Qwrite_region, start, end,
2907                                   filename, append, visit, lockname, codesys);
2908                         if (visiting) {
2909                                 BUF_SAVE_MODIFF(current_buffer) =
2910                                     BUF_MODIFF(current_buffer);
2911                                 current_buffer->saved_size =
2912                                     make_int(BUF_SIZE(current_buffer));
2913                                 current_buffer->filename = visit_file;
2914                                 MARK_MODELINE_CHANGED;
2915                         }
2916                         NUNGCPRO;
2917                         UNGCPRO;
2918                         return val;
2919                 }
2920         }
2921
2922 #ifdef CLASH_DETECTION
2923         if (!auto_saving)
2924                 lock_file(lockname);
2925 #endif                          /* CLASH_DETECTION */
2926
2927         /* Special kludge to simplify auto-saving.  */
2928         if (NILP(start)) {
2929                 start1 = BUF_BEG(current_buffer);
2930                 end1 = BUF_Z(current_buffer);
2931         }
2932
2933         record_unwind_protect(build_annotations_unwind, Fcurrent_buffer());
2934
2935         given_buffer = current_buffer;
2936         annotations = build_annotations(start, end);
2937         if (current_buffer != given_buffer) {
2938                 start1 = BUF_BEGV(current_buffer);
2939                 end1 = BUF_ZV(current_buffer);
2940         }
2941
2942         fn = filename;
2943         desc = -1;
2944         if (!NILP(append)) {
2945                 desc =
2946                     open((char *)XSTRING_DATA(fn), O_WRONLY | OPEN_BINARY, 0);
2947         }
2948         if (desc < 0) {
2949                 desc = open((char *)XSTRING_DATA(fn),
2950                             O_WRONLY | O_TRUNC | O_CREAT | OPEN_BINARY,
2951                             auto_saving ? auto_save_mode_bits : CREAT_MODE);
2952         }
2953
2954         if (desc < 0) {
2955 #ifdef CLASH_DETECTION
2956                 save_errno = errno;
2957                 if (!auto_saving)
2958                         unlock_file(lockname);
2959                 errno = save_errno;
2960 #endif                          /* CLASH_DETECTION */
2961                 report_file_error("Opening output file", list1(filename));
2962         }
2963
2964         {
2965                 Lisp_Object desc_locative = Fcons(make_int(desc), Qnil);
2966                 Lisp_Object instream = Qnil, outstream = Qnil;
2967                 struct gcpro nngcpro1, nngcpro2;
2968                 /* need to gcpro; QUIT could happen out of call to write() */
2969                 NNGCPRO2(instream, outstream);
2970
2971                 record_unwind_protect(close_file_unwind, desc_locative);
2972
2973                 if (!NILP(append)) {
2974                         if (lseek(desc, 0, 2) < 0) {
2975 #ifdef CLASH_DETECTION
2976                                 if (!auto_saving)
2977                                         unlock_file(lockname);
2978 #endif                          /* CLASH_DETECTION */
2979                                 report_file_error("Lseek error",
2980                                                   list1(filename));
2981                         }
2982                 }
2983
2984                 failure = 0;
2985
2986                 /* Note: I tried increasing the buffering size, along with
2987                    various other tricks, but nothing seemed to make much of
2988                    a difference in the time it took to save a large file.
2989                    (Actually that's not true.  With a local disk, changing
2990                    the buffer size doesn't seem to make much difference.
2991                    With an NFS-mounted disk, it could make a lot of difference
2992                    because you're affecting the number of network requests
2993                    that need to be made, and there could be a large latency
2994                    for each request.  So I've increased the buffer size
2995                    to 64K.) */
2996                 outstream = make_filedesc_output_stream(desc, 0, -1, 0);
2997                 Lstream_set_buffering(XLSTREAM(outstream),
2998                                       LSTREAM_BLOCKN_BUFFERED, 65536);
2999 #ifdef FILE_CODING
3000                 outstream =
3001                     make_encoding_output_stream(XLSTREAM(outstream), codesys);
3002                 Lstream_set_buffering(XLSTREAM(outstream),
3003                                       LSTREAM_BLOCKN_BUFFERED, 65536);
3004 #endif                          /* FILE_CODING */
3005                 if (STRINGP(start)) {
3006                         instream = make_lisp_string_input_stream(start, 0, -1);
3007                         start1 = 0;
3008                 } else
3009                         instream =
3010                             make_lisp_buffer_input_stream(current_buffer,
3011                                                           start1, end1,
3012                                                           LSTR_SELECTIVE |
3013                                                           LSTR_IGNORE_ACCESSIBLE);
3014                 failure =
3015                     (0 > (a_write(outstream, instream, start1, &annotations)));
3016                 save_errno = errno;
3017                 /* Note that this doesn't close the desc since we created the
3018                    stream without the LSTR_CLOSING flag, but it does
3019                    flush out any buffered data. */
3020                 if (Lstream_close(XLSTREAM(outstream)) < 0) {
3021                         failure = 1;
3022                         save_errno = errno;
3023                 }
3024                 Lstream_close(XLSTREAM(instream));
3025
3026 #ifdef HAVE_FSYNC
3027                 /* Note fsync appears to change the modtime on BSD4.2 (both vax and sun).
3028                    Disk full in NFS may be reported here.  */
3029                 /* mib says that closing the file will try to write as fast as NFS can do
3030                    it, and that means the fsync here is not crucial for autosave files.  */
3031                 if (!auto_saving && fsync(desc) < 0
3032                     /* If fsync fails with EINTR, don't treat that as serious.  */
3033                     && errno != EINTR) {
3034                         failure = 1;
3035                         save_errno = errno;
3036                 }
3037 #endif                          /* HAVE_FSYNC */
3038
3039                 /* Spurious "file has changed on disk" warnings used to be seen on
3040                    systems where close() can change the modtime.  This is known to
3041                    happen on various NFS file systems, on Windows, and on Linux.
3042                    Rather than handling this on a per-system basis, we
3043                    unconditionally do the sxemacs_stat() after the close(). */
3044
3045                 /* NFS can report a write failure now.  */
3046                 if (close(desc) < 0) {
3047                         failure = 1;
3048                         save_errno = errno;
3049                 }
3050
3051                 /* Discard the close unwind-protect.  Execute the one for
3052                    build_annotations (switches back to the original current buffer
3053                    as necessary). */
3054                 XCAR(desc_locative) = Qnil;
3055                 unbind_to(speccount, Qnil);
3056
3057                 NNUNGCPRO;
3058         }
3059
3060         stat_res = sxemacs_stat((char *)XSTRING_DATA(fn), &st);
3061
3062 #ifdef CLASH_DETECTION
3063         if (!auto_saving)
3064                 unlock_file(lockname);
3065 #endif                          /* CLASH_DETECTION */
3066
3067         /* Do this before reporting IO error
3068            to avoid a "file has changed on disk" warning on
3069            next attempt to save.  */
3070         if (visiting)
3071            if (stat_res == 0)
3072                 current_buffer->modtime = st.st_mtime;
3073            /* else:
3074                 If sxemacs_stat failed, we have bigger problems, and
3075                    most likely the file is gone, so the error next time is
3076                    the right behavior
3077             */
3078
3079         if (failure) {
3080                 errno = save_errno;
3081                 report_file_error("Writing file", list1(fn));
3082         }
3083
3084         if (visiting) {
3085                 BUF_SAVE_MODIFF(current_buffer) = BUF_MODIFF(current_buffer);
3086                 current_buffer->saved_size = make_int(BUF_SIZE(current_buffer));
3087                 current_buffer->filename = visit_file;
3088                 MARK_MODELINE_CHANGED;
3089         } else if (quietly) {
3090                 NUNGCPRO;
3091                 UNGCPRO;
3092                 return Qnil;
3093         }
3094
3095         if (!auto_saving) {
3096                 if (visiting_other)
3097                         message("Wrote %s", XSTRING_DATA(visit_file));
3098                 else {
3099                         Lisp_Object fsp = Qnil;
3100                         struct gcpro nngcpro1;
3101
3102                         NNGCPRO1(fsp);
3103                         fsp = Ffile_symlink_p(fn);
3104                         if (NILP(fsp))
3105                                 message("Wrote %s", XSTRING_DATA(fn));
3106                         else
3107                                 message("Wrote %s (symlink to %s)",
3108                                         XSTRING_DATA(fn), XSTRING_DATA(fsp));
3109                         NNUNGCPRO;
3110                 }
3111         }
3112         NUNGCPRO;
3113         UNGCPRO;
3114         return Qnil;
3115 }
3116
3117 /* #### This is such a load of shit!!!!  There is no way we should define
3118    something so stupid as a subr, just sort the fucking list more
3119    intelligently. */
3120 DEFUN("car-less-than-car", Fcar_less_than_car, 2, 2, 0, /*
3121 Return t if (car A) is numerically less than (car B).
3122 */
3123       (a, b))
3124 {
3125         if (ent_binrel(ASE_BINARY_REL_LESSP, Fcar(a), Fcar(b)))
3126                 return Qt;
3127         else
3128                 return Qnil;;
3129 }
3130
3131 /* Heh heh heh, let's define this too, just to aggravate the person who
3132    wrote the above comment. */
3133 DEFUN("cdr-less-than-cdr", Fcdr_less_than_cdr, 2, 2, 0, /*
3134 Return t if (cdr A) is numerically less than (cdr B).
3135 */
3136       (a, b))
3137 {
3138         if (ent_binrel(ASE_BINARY_REL_LESSP, Fcdr(a), Fcdr(b)))
3139                 return Qt;
3140         else
3141                 return Qnil;
3142 }
3143
3144 /* Build the complete list of annotations appropriate for writing out
3145    the text between START and END, by calling all the functions in
3146    write-region-annotate-functions and merging the lists they return.
3147    If one of these functions switches to a different buffer, we assume
3148    that buffer contains altered text.  Therefore, the caller must
3149    make sure to restore the current buffer in all cases,
3150    as save-excursion would do.  */
3151
3152 static Lisp_Object build_annotations(Lisp_Object start, Lisp_Object end)
3153 {
3154         /* This function can GC */
3155         Lisp_Object annotations;
3156         Lisp_Object p, res;
3157         struct gcpro gcpro1, gcpro2;
3158         Lisp_Object original_buffer;
3159
3160         XSETBUFFER(original_buffer, current_buffer);
3161
3162         annotations = Qnil;
3163         p = Vwrite_region_annotate_functions;
3164         GCPRO2(annotations, p);
3165         while (!NILP(p)) {
3166                 struct buffer *given_buffer = current_buffer;
3167                 Vwrite_region_annotations_so_far = annotations;
3168                 res = call2(Fcar(p), start, end);
3169                 /* If the function makes a different buffer current,
3170                    assume that means this buffer contains altered text to be output.
3171                    Reset START and END from the buffer bounds
3172                    and discard all previous annotations because they should have
3173                    been dealt with by this function.  */
3174                 if (current_buffer != given_buffer) {
3175                         start = make_int(BUF_BEGV(current_buffer));
3176                         end = make_int(BUF_ZV(current_buffer));
3177                         annotations = Qnil;
3178                 }
3179                 Flength(res);   /* Check basic validity of return value */
3180                 annotations = merge(annotations, res, Qcar_less_than_car);
3181                 p = Fcdr(p);
3182         }
3183
3184         /* Now do the same for annotation functions implied by the file-format */
3185         if (auto_saving && (!EQ(Vauto_save_file_format, Qt)))
3186                 p = Vauto_save_file_format;
3187         else
3188                 p = current_buffer->file_format;
3189         while (!NILP(p)) {
3190                 struct buffer *given_buffer = current_buffer;
3191                 Vwrite_region_annotations_so_far = annotations;
3192                 res = call4(Qformat_annotate_function, Fcar(p), start, end,
3193                             original_buffer);
3194                 if (current_buffer != given_buffer) {
3195                         start = make_int(BUF_BEGV(current_buffer));
3196                         end = make_int(BUF_ZV(current_buffer));
3197                         annotations = Qnil;
3198                 }
3199                 Flength(res);
3200                 annotations = merge(annotations, res, Qcar_less_than_car);
3201                 p = Fcdr(p);
3202         }
3203         UNGCPRO;
3204         return annotations;
3205 }
3206
3207 /* Write to stream OUTSTREAM the characters from INSTREAM (it is read until
3208    EOF is encountered), assuming they start at position POS in the buffer
3209    of string that STREAM refers to.  Intersperse with them the annotations
3210    from *ANNOT that fall into the range of positions we are reading from,
3211    each at its appropriate position.
3212
3213    Modify *ANNOT by discarding elements as we output them.
3214    The return value is negative in case of system call failure.  */
3215
3216 /* 4K should probably be fine.  We just need to reduce the number of
3217    function calls to reasonable level.  The Lstream stuff itself will
3218    batch to 64K to reduce the number of system calls. */
3219
3220 #define A_WRITE_BATCH_SIZE 4096
3221
3222 static int
3223 a_write(Lisp_Object outstream, Lisp_Object instream, int pos,
3224         Lisp_Object * annot)
3225 {
3226         Lisp_Object tem;
3227         int nextpos;
3228         unsigned char largebuf[A_WRITE_BATCH_SIZE];
3229         Lstream *instr = XLSTREAM(instream);
3230         Lstream *outstr = XLSTREAM(outstream);
3231
3232         while (LISTP(*annot)) {
3233                 tem = Fcar_safe(Fcar(*annot));
3234                 if (INTP(tem))
3235                         nextpos = XINT(tem);
3236                 else
3237                         nextpos = INT_MAX;
3238 #ifdef MULE
3239                 /* If there are annotations left and we have Mule, then we
3240                    have to do the I/O one emchar at a time so we can
3241                    determine when to insert the annotation. */
3242                 if (!NILP(*annot)) {
3243                         Emchar ch;
3244                         while (pos != nextpos
3245                                && (ch = Lstream_get_emchar(instr)) != EOF) {
3246                                 if (Lstream_put_emchar(outstr, ch) < 0)
3247                                         return -1;
3248                                 pos++;
3249                         }
3250                 } else
3251 #endif                          /* MULE */
3252                 {
3253                         while (pos != nextpos) {
3254                                 /* Otherwise there is no point to that.  Just go in batches. */
3255                                 int chunk =
3256                                     min(nextpos - pos, A_WRITE_BATCH_SIZE);
3257
3258                                 chunk = Lstream_read(instr, largebuf, chunk);
3259                                 if (chunk < 0)
3260                                         return -1;
3261                                 if (chunk == 0) /* EOF */
3262                                         break;
3263                                 if (Lstream_write(outstr, largebuf, chunk) <
3264                                     chunk)
3265                                         return -1;
3266                                 pos += chunk;
3267                         }
3268                 }
3269                 if (pos == nextpos) {
3270                         tem = Fcdr(Fcar(*annot));
3271                         if (STRINGP(tem)) {
3272                                 if (Lstream_write(outstr, XSTRING_DATA(tem),
3273                                                   XSTRING_LENGTH(tem)) < 0)
3274                                         return -1;
3275                         }
3276                         *annot = Fcdr(*annot);
3277                 } else
3278                         return 0;
3279         }
3280         return -1;
3281 }
3282 \f
3283 DEFUN("verify-visited-file-modtime", Fverify_visited_file_modtime, 1, 1, 0,     /*
3284 Return t if last mod time of BUFFER's visited file matches what BUFFER records.
3285 This means that the file has not been changed since it was visited or saved.
3286 */
3287       (buffer))
3288 {
3289         /* This function can call lisp; GC checked 2000-07-11 ben */
3290         struct buffer *b;
3291         struct stat st;
3292         Lisp_Object handler;
3293
3294         CHECK_BUFFER(buffer);
3295         b = XBUFFER(buffer);
3296
3297         if (!STRINGP(b->filename))
3298                 return Qt;
3299         if (b->modtime == 0)
3300                 return Qt;
3301
3302         /* If the file name has special constructs in it,
3303            call the corresponding file handler.  */
3304         handler = Ffind_file_name_handler(b->filename,
3305                                           Qverify_visited_file_modtime);
3306         if (!NILP(handler))
3307                 return call2(handler, Qverify_visited_file_modtime, buffer);
3308
3309         if (sxemacs_stat((char *)XSTRING_DATA(b->filename), &st) < 0) {
3310                 /* If the file doesn't exist now and didn't exist before,
3311                    we say that it isn't modified, provided the error is a tame one.  */
3312                 if (errno == ENOENT || errno == EACCES || errno == ENOTDIR)
3313                         st.st_mtime = -1;
3314                 else
3315                         st.st_mtime = 0;
3316         }
3317         if (st.st_mtime == b->modtime
3318             /* If both are positive, accept them if they are off by one second.  */
3319             || (st.st_mtime > 0 && b->modtime > 0
3320                 && (st.st_mtime == b->modtime + 1
3321                     || st.st_mtime == b->modtime - 1)))
3322                 return Qt;
3323         return Qnil;
3324 }
3325
3326 DEFUN("clear-visited-file-modtime", Fclear_visited_file_modtime, 0, 0, 0,       /*
3327 Clear out records of last mod time of visited file.
3328 Next attempt to save will certainly not complain of a discrepancy.
3329 */
3330       ())
3331 {
3332         current_buffer->modtime = 0;
3333         return Qnil;
3334 }
3335
3336 DEFUN("visited-file-modtime", Fvisited_file_modtime, 0, 0, 0,   /*
3337 Return the current buffer's recorded visited file modification time.
3338 The value is a list of the form (HIGH . LOW), like the time values
3339 that `file-attributes' returns.
3340 */
3341       ())
3342 {
3343         return time_to_lisp((time_t) current_buffer->modtime);
3344 }
3345
3346 DEFUN("set-visited-file-modtime", Fset_visited_file_modtime, 0, 1, 0,   /*
3347 Update buffer's recorded modification time from the visited file's time.
3348 Useful if the buffer was not read from the file normally
3349 or if the file itself has been changed for some known benign reason.
3350 An argument specifies the modification time value to use
3351 \(instead of that of the visited file), in the form of a list
3352 \(HIGH . LOW) or (HIGH LOW).
3353 */
3354       (time_list))
3355 {
3356         /* This function can call lisp */
3357         if (!NILP(time_list)) {
3358                 time_t the_time;
3359                 lisp_to_time(time_list, &the_time);
3360                 current_buffer->modtime = (int)the_time;
3361         } else {
3362                 Lisp_Object filename = Qnil;
3363                 struct stat st;
3364                 Lisp_Object handler;
3365                 struct gcpro gcpro1, gcpro2, gcpro3;
3366
3367                 GCPRO3(filename, time_list, current_buffer->filename);
3368                 filename = Fexpand_file_name(current_buffer->filename, Qnil);
3369
3370                 /* If the file name has special constructs in it,
3371                    call the corresponding file handler.  */
3372                 handler =
3373                     Ffind_file_name_handler(filename,
3374                                             Qset_visited_file_modtime);
3375                 UNGCPRO;
3376                 if (!NILP(handler))
3377                         /* The handler can find the file name the same way we did.  */
3378                         return call2(handler, Qset_visited_file_modtime, Qnil);
3379                 else if (sxemacs_stat((char *)XSTRING_DATA(filename), &st) >= 0)
3380                         current_buffer->modtime = st.st_mtime;
3381         }
3382
3383         return Qnil;
3384 }
3385 \f
3386 static Lisp_Object
3387 auto_save_error(Lisp_Object condition_object, Lisp_Object ignored)
3388 {
3389         /* This function can call lisp */
3390         if (gc_in_progress)
3391                 return Qnil;
3392         /* Don't try printing an error message after everything is gone! */
3393         if (preparing_for_armageddon)
3394                 return Qnil;
3395         clear_echo_area(selected_frame(), Qauto_saving, 1);
3396         Fding(Qt, Qauto_save_error, Qnil);
3397         message("Auto-saving...error for %s",
3398                 XSTRING_DATA(current_buffer->name));
3399         Fsleep_for(make_int(1));
3400         message("Auto-saving...error!for %s",
3401                 XSTRING_DATA(current_buffer->name));
3402         Fsleep_for(make_int(1));
3403         message("Auto-saving...error for %s",
3404                 XSTRING_DATA(current_buffer->name));
3405         Fsleep_for(make_int(1));
3406         return Qnil;
3407 }
3408
3409 static Lisp_Object auto_save_1(Lisp_Object ignored)
3410 {
3411         /* This function can call lisp */
3412         /* #### I think caller is protecting current_buffer? */
3413         struct stat st;
3414         Lisp_Object fn = current_buffer->filename;
3415         Lisp_Object a = current_buffer->auto_save_file_name;
3416
3417         if (!STRINGP(a))
3418                 return (Qnil);
3419
3420         /* Get visited file's mode to become the auto save file's mode.  */
3421         if (STRINGP(fn) && sxemacs_stat((char *)XSTRING_DATA(fn), &st) >= 0)
3422                 /* But make sure we can overwrite it later!  */
3423                 auto_save_mode_bits = st.st_mode | 0600;
3424         else
3425                 /* default mode for auto-save files of buffers with no file is
3426                    readable by owner only.  This may annoy some small number of
3427                    people, but the alternative removes all privacy from email. */
3428                 auto_save_mode_bits = 0600;
3429
3430         return
3431             /* !!#### need to deal with this 'escape-quoted everywhere */
3432             Fwrite_region_internal(Qnil, Qnil, a, Qnil, Qlambda, Qnil,
3433 #ifdef FILE_CODING
3434                                    current_buffer->buffer_file_coding_system
3435 #else
3436                                    Qnil
3437 #endif
3438             );
3439 }
3440
3441 static Lisp_Object
3442 auto_save_expand_name_error(Lisp_Object condition_object, Lisp_Object ignored)
3443 {
3444         /* #### this function should spew an error message about not being
3445            able to open the .saves file. */
3446         return Qnil;
3447 }
3448
3449 static Lisp_Object auto_save_expand_name(Lisp_Object name)
3450 {
3451         struct gcpro gcpro1;
3452
3453         /* note that caller did NOT gc protect name, so we do it. */
3454         /* #### dmoore - this might not be necessary, if condition_case_1
3455            protects it.  but I don't think it does. */
3456         GCPRO1(name);
3457         RETURN_UNGCPRO(Fexpand_file_name(name, Qnil));
3458 }
3459
3460 static Lisp_Object do_auto_save_unwind(Lisp_Object fd)
3461 {
3462         close(XINT(fd));
3463         return (fd);
3464 }
3465
3466 static Lisp_Object do_auto_save_unwind_2(Lisp_Object old_auto_saving)
3467 {
3468         auto_saving = XINT(old_auto_saving);
3469         return Qnil;
3470 }
3471
3472 /* Fdo_auto_save() checks whether a GC is in progress when it is called,
3473    and if so, tries to avoid touching lisp objects.
3474
3475    The only time that Fdo_auto_save() is called while GC is in progress
3476    is if we're going down, as a result of an abort() or a kill signal.
3477    It's fairly important that we generate autosave files in that case!
3478  */
3479
3480 DEFUN("do-auto-save", Fdo_auto_save, 0, 2, "",  /*
3481 Auto-save all buffers that need it.
3482 This is all buffers that have auto-saving enabled
3483 and are changed since last auto-saved.
3484 Auto-saving writes the buffer into a file
3485 so that your editing is not lost if the system crashes.
3486 This file is not the file you visited; that changes only when you save.
3487 Normally we run the normal hook `auto-save-hook' before saving.
3488
3489 Non-nil first argument means do not print any message if successful.
3490 Non-nil second argument means save only current buffer.
3491 */
3492       (no_message, current_only))
3493 {
3494         /* This function can call lisp */
3495         struct buffer *b;
3496         Lisp_Object tail, buf;
3497         int auto_saved = 0;
3498         int do_handled_files;
3499         Lisp_Object oquit = Qnil;
3500         Lisp_Object listfile = Qnil;
3501         Lisp_Object old;
3502         int listdesc = -1;
3503         int speccount = specpdl_depth();
3504         struct gcpro gcpro1, gcpro2, gcpro3;
3505
3506         XSETBUFFER(old, current_buffer);
3507         GCPRO3(oquit, listfile, old);
3508         check_quit();           /* make Vquit_flag accurate */
3509         /* Ordinarily don't quit within this function,
3510            but don't make it impossible to quit (in case we get hung in I/O).  */
3511         oquit = Vquit_flag;
3512         Vquit_flag = Qnil;
3513
3514         /* No further GCPRO needed, because (when it matters) all Lisp_Object
3515            variables point to non-strings reached from Vbuffer_alist.  */
3516
3517         if (minibuf_level != 0 || preparing_for_armageddon)
3518                 no_message = Qt;
3519
3520         run_hook(Qauto_save_hook);
3521
3522         if (STRINGP(Vauto_save_list_file_name))
3523                 listfile = condition_case_1(Qt,
3524                                             auto_save_expand_name,
3525                                             Vauto_save_list_file_name,
3526                                             auto_save_expand_name_error, Qnil);
3527
3528         /* Make sure auto_saving is reset. */
3529         record_unwind_protect(do_auto_save_unwind_2, make_int(auto_saving));
3530
3531         auto_saving = 1;
3532
3533         /* First, save all files which don't have handlers.  If Emacs is
3534            crashing, the handlers may tweak what is causing Emacs to crash
3535            in the first place, and it would be a shame if Emacs failed to
3536            autosave perfectly ordinary files because it couldn't handle some
3537            ange-ftp'd file.  */
3538         for (do_handled_files = 0; do_handled_files < 2; do_handled_files++) {
3539                 for (tail = Vbuffer_alist; CONSP(tail); tail = XCDR(tail)) {
3540                         buf = XCDR(XCAR(tail));
3541                         b = XBUFFER(buf);
3542
3543                         if (!NILP(current_only)
3544                             && b != current_buffer)
3545                                 continue;
3546
3547                         /* Don't auto-save indirect buffers.
3548                            The base buffer takes care of it.  */
3549                         if (b->base_buffer)
3550                                 continue;
3551
3552                         /* Check for auto save enabled
3553                            and file changed since last auto save
3554                            and file changed since last real save.  */
3555                         if (STRINGP(b->auto_save_file_name)
3556                             && BUF_SAVE_MODIFF(b) < BUF_MODIFF(b)
3557                             && b->auto_save_modified < BUF_MODIFF(b)
3558                             /* -1 means we've turned off autosaving for a while--see below.  */
3559                             && XINT(b->saved_size) >= 0
3560                             && (do_handled_files
3561                                 ||
3562                                 NILP(Ffind_file_name_handler
3563                                      (b->auto_save_file_name,
3564                                       Qwrite_region)))) {
3565                                 EMACS_TIME before_time, after_time;
3566
3567                                 EMACS_GET_TIME(before_time);
3568                                 /* If we had a failure, don't try again for 20 minutes.  */
3569                                 if (!preparing_for_armageddon
3570                                     && b->auto_save_failure_time >= 0
3571                                     && (EMACS_SECS(before_time) -
3572                                         b->auto_save_failure_time < 1200))
3573                                         continue;
3574
3575                                 if (!preparing_for_armageddon &&
3576                                     (XINT(b->saved_size) * 10
3577                                      > (BUF_Z(b) - BUF_BEG(b)) * 13)
3578                                     /* A short file is likely to change a large fraction;
3579                                        spare the user annoying messages.  */
3580                                     && XINT(b->saved_size) > 5000
3581                                     /* These messages are frequent and annoying for `*mail*'.  */
3582                                     && !NILP(b->filename)
3583                                     && NILP(no_message)
3584                                     && disable_auto_save_when_buffer_shrinks) {
3585                                         /* It has shrunk too much; turn off auto-saving here.
3586                                            Unless we're about to crash, in which case auto-save it
3587                                            anyway.
3588                                          */
3589                                         message
3590                                             ("Buffer %s has shrunk a lot; auto save turned off there",
3591                                              XSTRING_DATA(b->name));
3592                                         /* Turn off auto-saving until there's a real save,
3593                                            and prevent any more warnings.  */
3594                                         b->saved_size = make_int(-1);
3595                                         if (!gc_in_progress)
3596                                                 Fsleep_for(make_int(1));
3597                                         continue;
3598                                 }
3599                                 set_buffer_internal(b);
3600                                 if (!auto_saved && NILP(no_message)) {
3601                                         static const unsigned char *msg
3602                                             =
3603                                             (const unsigned char *)
3604                                             "Auto-saving...";
3605                                         echo_area_message(selected_frame(), msg,
3606                                                           Qnil, 0,
3607                                                           strlen((const char *)
3608                                                                  msg),
3609                                                           Qauto_saving);
3610                                 }
3611
3612                                 /* Open the auto-save list file, if necessary.
3613                                    We only do this now so that the file only exists
3614                                    if we actually auto-saved any files. */
3615                                 if (!auto_saved && !inhibit_auto_save_session
3616                                     && !NILP(Vauto_save_list_file_prefix)
3617                                     && STRINGP(listfile) && listdesc < 0) {
3618                                         listdesc =
3619                                             open((char *)XSTRING_DATA(listfile),
3620                                                  O_WRONLY | O_TRUNC | O_CREAT |
3621                                                  OPEN_BINARY, CREAT_MODE);
3622
3623                                         /* Arrange to close that file whether or not we get
3624                                            an error. */
3625                                         if (listdesc >= 0)
3626                                                 record_unwind_protect
3627                                                     (do_auto_save_unwind,
3628                                                      make_int(listdesc));
3629                                 }
3630
3631                                 /* Record all the buffers that we are auto-saving in
3632                                    the special file that lists them.  For each of
3633                                    these buffers, record visited name (if any) and
3634                                    auto save name.  */
3635                                 if (listdesc >= 0) {
3636                                         const Extbyte *auto_save_file_name_ext;
3637                                         Extcount auto_save_file_name_ext_len;
3638
3639                                         TO_EXTERNAL_FORMAT(LISP_STRING,
3640                                                            b->
3641                                                            auto_save_file_name,
3642                                                            ALLOCA,
3643                                                            (auto_save_file_name_ext,
3644                                                             auto_save_file_name_ext_len),
3645                                                            Qfile_name);
3646                                         if (!NILP(b->filename)) {
3647                                                 const Extbyte *filename_ext;
3648                                                 Extcount filename_ext_len;
3649
3650                                                 TO_EXTERNAL_FORMAT(LISP_STRING,
3651                                                                    b->filename,
3652                                                                    ALLOCA,
3653                                                                    (filename_ext,
3654                                                                     filename_ext_len),
3655                                                                    Qfile_name);
3656                                                 write(listdesc, filename_ext,
3657                                                       filename_ext_len);
3658                                         }
3659                                         write(listdesc, "\n", 1);
3660                                         write(listdesc, auto_save_file_name_ext,
3661                                               auto_save_file_name_ext_len);
3662                                         write(listdesc, "\n", 1);
3663                                 }
3664
3665                                 /* dmoore - In a bad scenario we've set b=XBUFFER(buf)
3666                                    based on values in Vbuffer_alist.  auto_save_1 may
3667                                    cause lisp handlers to run.  Those handlers may kill
3668                                    the buffer and then GC.  Since the buffer is killed,
3669                                    it's no longer in Vbuffer_alist so it might get reaped
3670                                    by the GC.  We also need to protect tail. */
3671                                 /* #### There is probably a lot of other code which has
3672                                    pointers into buffers which may get blown away by
3673                                    handlers. */
3674                                 {
3675                                         struct gcpro ngcpro1, ngcpro2;
3676                                         NGCPRO2(buf, tail);
3677                                         condition_case_1(Qt,
3678                                                          auto_save_1, Qnil,
3679                                                          auto_save_error, Qnil);
3680                                         NUNGCPRO;
3681                                 }
3682                                 /* Handler killed our saved current-buffer!  Pick any. */
3683                                 if (!BUFFER_LIVE_P(XBUFFER(old)))
3684                                         XSETBUFFER(old, current_buffer);
3685
3686                                 set_buffer_internal(XBUFFER(old));
3687                                 auto_saved++;
3688
3689                                 /* Handler killed their own buffer! */
3690                                 if (!BUFFER_LIVE_P(b))
3691                                         continue;
3692
3693                                 b->auto_save_modified = BUF_MODIFF(b);
3694                                 b->saved_size = make_int(BUF_SIZE(b));
3695                                 EMACS_GET_TIME(after_time);
3696                                 /* If auto-save took more than 60 seconds,
3697                                    assume it was an NFS failure that got a timeout.  */
3698                                 if (EMACS_SECS(after_time) -
3699                                     EMACS_SECS(before_time) > 60)
3700                                         b->auto_save_failure_time =
3701                                             EMACS_SECS(after_time);
3702                         }
3703                 }
3704         }
3705
3706         /* Prevent another auto save till enough input events come in.  */
3707         if (auto_saved)
3708                 record_auto_save();
3709
3710         /* If we didn't save anything into the listfile, remove the old
3711            one because nothing needed to be auto-saved.  Do this afterwards
3712            rather than before in case we get a crash attempting to autosave
3713            (in that case we'd still want the old one around). */
3714         if (listdesc < 0 && !auto_saved && STRINGP(listfile))
3715                 unlink((char *)XSTRING_DATA(listfile));
3716
3717         /* Show "...done" only if the echo area would otherwise be empty. */
3718         if (auto_saved && NILP(no_message)
3719             && NILP(clear_echo_area(selected_frame(), Qauto_saving, 0))) {
3720                 static const unsigned char *msg
3721                     = (const unsigned char *)"Auto-saving...done";
3722                 echo_area_message(selected_frame(), msg, Qnil, 0,
3723                                   strlen((const char *)msg), Qauto_saving);
3724         }
3725
3726         Vquit_flag = oquit;
3727
3728         RETURN_UNGCPRO(unbind_to(speccount, Qnil));
3729 }
3730
3731 DEFUN("set-buffer-auto-saved", Fset_buffer_auto_saved, 0, 0, 0, /*
3732 Mark current buffer as auto-saved with its current text.
3733 No auto-save file will be written until the buffer changes again.
3734 */
3735       ())
3736 {
3737         current_buffer->auto_save_modified = BUF_MODIFF(current_buffer);
3738         current_buffer->saved_size = make_int(BUF_SIZE(current_buffer));
3739         current_buffer->auto_save_failure_time = -1;
3740         return Qnil;
3741 }
3742
3743 DEFUN("clear-buffer-auto-save-failure", Fclear_buffer_auto_save_failure, 0, 0, 0,       /*
3744 Clear any record of a recent auto-save failure in the current buffer.
3745 */
3746       ())
3747 {
3748         current_buffer->auto_save_failure_time = -1;
3749         return Qnil;
3750 }
3751
3752 DEFUN("recent-auto-save-p", Frecent_auto_save_p, 0, 0, 0,       /*
3753 Return t if buffer has been auto-saved since last read in or saved.
3754 */
3755       ())
3756 {
3757         return (BUF_SAVE_MODIFF(current_buffer) <
3758                 current_buffer->auto_save_modified) ? Qt : Qnil;
3759 }
3760 \f
3761 /************************************************************************/
3762 /*                            initialization                            */
3763 /************************************************************************/
3764
3765 void syms_of_fileio(void)
3766 {
3767         defsymbol(&Qexpand_file_name, "expand-file-name");
3768         defsymbol(&Qfile_truename, "file-truename");
3769         defsymbol(&Qsubstitute_in_file_name, "substitute-in-file-name");
3770         defsymbol(&Qdirectory_file_name, "directory-file-name");
3771         defsymbol(&Qfile_dirname, "file-dirname");
3772         defsymbol(&Qfile_basename, "file-basename");
3773         defsymbol(&Qfile_name_directory, "file-name-directory");
3774         defsymbol(&Qfile_name_nondirectory, "file-name-nondirectory");
3775         defsymbol(&Qunhandled_file_name_directory,
3776                   "unhandled-file-name-directory");
3777         defsymbol(&Qfile_name_as_directory, "file-name-as-directory");
3778         defsymbol(&Qcopy_file, "copy-file");
3779         defsymbol(&Qmake_directory_internal, "make-directory-internal");
3780         defsymbol(&Qdelete_directory, "delete-directory");
3781         defsymbol(&Qdelete_file, "delete-file");
3782         defsymbol(&Qrename_file, "rename-file");
3783         defsymbol(&Qadd_name_to_file, "add-name-to-file");
3784         defsymbol(&Qmake_symbolic_link, "make-symbolic-link");
3785         defsymbol(&Qfile_exists_p, "file-exists-p");
3786         defsymbol(&Qfile_executable_p, "file-executable-p");
3787         defsymbol(&Qfile_readable_p, "file-readable-p");
3788         defsymbol(&Qfile_symlink_p, "file-symlink-p");
3789         defsymbol(&Qfile_writable_p, "file-writable-p");
3790         defsymbol(&Qfile_directory_p, "file-directory-p");
3791         defsymbol(&Qfile_regular_p, "file-regular-p");
3792         defsymbol(&Qfile_accessible_directory_p, "file-accessible-directory-p");
3793         defsymbol(&Qfile_modes, "file-modes");
3794         defsymbol(&Qset_file_modes, "set-file-modes");
3795         defsymbol(&Qfile_newer_than_file_p, "file-newer-than-file-p");
3796         defsymbol(&Qinsert_file_contents, "insert-file-contents");
3797         defsymbol(&Qwrite_region, "write-region");
3798         defsymbol(&Qverify_visited_file_modtime, "verify-visited-file-modtime");
3799         defsymbol(&Qset_visited_file_modtime, "set-visited-file-modtime");
3800         defsymbol(&Qcar_less_than_car, "car-less-than-car");    /* Vomitous! */
3801
3802         defsymbol(&Qauto_save_hook, "auto-save-hook");
3803         defsymbol(&Qauto_save_error, "auto-save-error");
3804         defsymbol(&Qauto_saving, "auto-saving");
3805
3806         defsymbol(&Qformat_decode, "format-decode");
3807         defsymbol(&Qformat_annotate_function, "format-annotate-function");
3808
3809         defsymbol(&Qcompute_buffer_file_truename,
3810                   "compute-buffer-file-truename");
3811         DEFERROR_STANDARD(Qfile_error, Qio_error);
3812         DEFERROR_STANDARD(Qfile_already_exists, Qfile_error);
3813
3814         DEFSUBR(Ffind_file_name_handler);
3815
3816         DEFSUBR(Ffile_name_directory);
3817         DEFSUBR(Ffile_name_nondirectory);
3818         DEFSUBR(Ffile_basename);
3819         DEFSUBR(Ffile_dirname);
3820         DEFSUBR(Funhandled_file_name_directory);
3821         DEFSUBR(Ffile_name_as_directory);
3822         DEFSUBR(Fdirectory_file_name);
3823         DEFSUBR(Fmake_temp_name);
3824         DEFSUBR(Fexpand_file_name);
3825         DEFSUBR(Ffile_truename);
3826         DEFSUBR(Fsubstitute_in_file_name);
3827         DEFSUBR(Fcopy_file);
3828         DEFSUBR(Fmake_directory_internal);
3829         DEFSUBR(Fdelete_directory);
3830         DEFSUBR(Fdelete_file);
3831         DEFSUBR(Frename_file);
3832         DEFSUBR(Fadd_name_to_file);
3833         DEFSUBR(Fmake_symbolic_link);
3834 #ifdef HPUX_NET
3835         DEFSUBR(Fsysnetunam);
3836 #endif                          /* HPUX_NET */
3837         DEFSUBR(Ffile_name_absolute_p);
3838         DEFSUBR(Ffile_exists_p);
3839         DEFSUBR(Ffile_executable_p);
3840         DEFSUBR(Ffile_readable_p);
3841         DEFSUBR(Ffile_writable_p);
3842         DEFSUBR(Ffile_symlink_p);
3843         DEFSUBR(Ffile_directory_p);
3844         DEFSUBR(Ffile_accessible_directory_p);
3845         DEFSUBR(Ffile_regular_p);
3846         DEFSUBR(Ffile_modes);
3847         DEFSUBR(Fset_file_modes);
3848         DEFSUBR(Fset_default_file_modes);
3849         DEFSUBR(Fdefault_file_modes);
3850         DEFSUBR(Funix_sync);
3851         DEFSUBR(Ffile_newer_than_file_p);
3852         DEFSUBR(Finsert_file_contents_internal);
3853         DEFSUBR(Fwrite_region_internal);
3854         DEFSUBR(Fcar_less_than_car);    /* Vomitous! */
3855         DEFSUBR(Fcdr_less_than_cdr);    /* Yeah oh yeah bucko .... */
3856         DEFSUBR(Fverify_visited_file_modtime);
3857         DEFSUBR(Fclear_visited_file_modtime);
3858         DEFSUBR(Fvisited_file_modtime);
3859         DEFSUBR(Fset_visited_file_modtime);
3860
3861         DEFSUBR(Fdo_auto_save);
3862         DEFSUBR(Fset_buffer_auto_saved);
3863         DEFSUBR(Fclear_buffer_auto_save_failure);
3864         DEFSUBR(Frecent_auto_save_p);
3865 }
3866
3867 void vars_of_fileio(void)
3868 {
3869         DEFVAR_LISP("auto-save-file-format", &Vauto_save_file_format    /*
3870 *Format in which to write auto-save files.
3871 Should be a list of symbols naming formats that are defined in `format-alist'.
3872 If it is t, which is the default, auto-save files are written in the
3873 same format as a regular save would use.
3874                                                                          */ );
3875         Vauto_save_file_format = Qt;
3876
3877         DEFVAR_LISP("file-name-handler-alist", &Vfile_name_handler_alist        /*
3878 *Alist of elements (REGEXP . HANDLER) for file names handled specially.
3879 If a file name matches REGEXP, then all I/O on that file is done by calling
3880 HANDLER.
3881
3882 The first argument given to HANDLER is the name of the I/O primitive
3883 to be handled; the remaining arguments are the arguments that were
3884 passed to that primitive.  For example, if you do
3885 (file-exists-p FILENAME)
3886 and FILENAME is handled by HANDLER, then HANDLER is called like this:
3887 (funcall HANDLER 'file-exists-p FILENAME)
3888 The function `find-file-name-handler' checks this list for a handler
3889 for its argument.
3890                                                                                  */ );
3891         Vfile_name_handler_alist = Qnil;
3892
3893         DEFVAR_LISP("after-insert-file-functions", &Vafter_insert_file_functions        /*
3894 A list of functions to be called at the end of `insert-file-contents'.
3895 Each is passed one argument, the number of bytes inserted.  It should return
3896 the new byte count, and leave point the same.  If `insert-file-contents' is
3897 intercepted by a handler from `file-name-handler-alist', that handler is
3898 responsible for calling the after-insert-file-functions if appropriate.
3899                                                                                          */ );
3900         Vafter_insert_file_functions = Qnil;
3901
3902         DEFVAR_LISP("write-region-annotate-functions", &Vwrite_region_annotate_functions        /*
3903 A list of functions to be called at the start of `write-region'.
3904 Each is passed two arguments, START and END, as for `write-region'.
3905 It should return a list of pairs (POSITION . STRING) of strings to be
3906 effectively inserted at the specified positions of the file being written
3907 \(1 means to insert before the first byte written).  The POSITIONs must be
3908 sorted into increasing order.  If there are several functions in the list,
3909 the several lists are merged destructively.
3910                                                                                                  */ );
3911         Vwrite_region_annotate_functions = Qnil;
3912
3913         DEFVAR_LISP("write-region-annotations-so-far", &Vwrite_region_annotations_so_far        /*
3914 When an annotation function is called, this holds the previous annotations.
3915 These are the annotations made by other annotation functions
3916 that were already called.  See also `write-region-annotate-functions'.
3917                                                                                                  */ );
3918         Vwrite_region_annotations_so_far = Qnil;
3919
3920         DEFVAR_LISP("inhibit-file-name-handlers", &Vinhibit_file_name_handlers  /*
3921 A list of file name handlers that temporarily should not be used.
3922 This applies only to the operation `inhibit-file-name-operation'.
3923                                                                                  */ );
3924         Vinhibit_file_name_handlers = Qnil;
3925
3926         DEFVAR_LISP("inhibit-file-name-operation", &Vinhibit_file_name_operation        /*
3927 The operation for which `inhibit-file-name-handlers' is applicable.
3928                                                                                          */ );
3929         Vinhibit_file_name_operation = Qnil;
3930
3931         DEFVAR_LISP("auto-save-list-file-name", &Vauto_save_list_file_name      /*
3932 File name in which we write a list of all auto save file names.
3933                                                                                  */ );
3934         Vauto_save_list_file_name = Qnil;
3935
3936         DEFVAR_LISP("auto-save-list-file-prefix", &Vauto_save_list_file_prefix  /*
3937 Prefix for generating auto-save-list-file-name.
3938 Emacs's pid and the system name will be appended to
3939 this prefix to create a unique file name.
3940                                                                                  */ );
3941         Vauto_save_list_file_prefix = build_string("~/.saves-");
3942
3943         DEFVAR_BOOL("inhibit-auto-save-session", &inhibit_auto_save_session     /*
3944 When non-nil, inhibit auto save list file creation.
3945                                                                                  */ );
3946         inhibit_auto_save_session = 0;
3947
3948         DEFVAR_BOOL("disable-auto-save-when-buffer-shrinks", &disable_auto_save_when_buffer_shrinks     /*
3949 If non-nil, auto-saving is disabled when a buffer shrinks too much.
3950 This is to prevent you from losing your edits if you accidentally
3951 delete a large chunk of the buffer and don't notice it until too late.
3952 Saving the buffer normally turns auto-save back on.
3953                                                                                                          */ );
3954         disable_auto_save_when_buffer_shrinks = 1;
3955
3956         DEFVAR_LISP("directory-sep-char", &Vdirectory_sep_char  /*
3957 Directory separator character for built-in functions that return file names.
3958 The value should be either ?/ or ?\\ (any other value is treated as ?\\).
3959 This variable affects the built-in functions only on Windows,
3960 on other platforms, it is initialized so that Lisp code can find out
3961 what the normal separator is.
3962                                                                  */ );
3963         Vdirectory_sep_char = make_char('/');
3964
3965         reinit_vars_of_fileio();
3966 }
3967
3968 void reinit_vars_of_fileio(void)
3969 {
3970         /* We want temp_name_rand to be initialized to a value likely to be
3971            unique to the process, not to the executable.  The danger is that
3972            two different SXEmacs processes using the same binary on different
3973            machines creating temp files in the same directory will be
3974            unlucky enough to have the same pid.  If we randomize using
3975            process startup time, then in practice they will be unlikely to
3976            collide. We use the microseconds field so that scripts that start
3977            simultaneous SXEmacs processes on multiple machines will have less
3978            chance of collision.  */
3979         {
3980                 EMACS_TIME thyme;
3981
3982                 EMACS_GET_TIME(thyme);
3983                 temp_name_rand =
3984                     (unsigned int)(EMACS_SECS(thyme) ^ EMACS_USECS(thyme));
3985         }
3986 }