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