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