diff options
Diffstat (limited to 'src/fileio.c')
-rw-r--r-- | src/fileio.c | 600 |
1 files changed, 301 insertions, 299 deletions
diff --git a/src/fileio.c b/src/fileio.c index fb1fe28aca2..43ab456d813 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -86,6 +86,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include <careadlinkat.h> #include <stat-time.h> +#include <binary-io.h> + #ifdef HPUX #include <netio.h> #endif @@ -113,49 +115,10 @@ static bool auto_save_error_occurred; static bool valid_timestamp_file_system; static dev_t timestamp_file_system; -/* The symbol bound to coding-system-for-read when - insert-file-contents is called for recovering a file. This is not - an actual coding system name, but just an indicator to tell - insert-file-contents to use `emacs-mule' with a special flag for - auto saving and recovering a file. */ -static Lisp_Object Qauto_save_coding; - -/* Property name of a file name handler, - which gives a list of operations it handles.. */ -static Lisp_Object Qoperations; - -/* Lisp functions for translating file formats. */ -static Lisp_Object Qformat_decode, Qformat_annotate_function; - -/* Lisp function for setting buffer-file-coding-system and the - multibyteness of the current buffer after inserting a file. */ -static Lisp_Object Qafter_insert_file_set_coding; - -static Lisp_Object Qwrite_region_annotate_functions; /* Each time an annotation function changes the buffer, the new buffer is added here. */ static Lisp_Object Vwrite_region_annotation_buffers; -static Lisp_Object Qdelete_by_moving_to_trash; - -/* Lisp function for moving files to trash. */ -static Lisp_Object Qmove_file_to_trash; - -/* Lisp function for recursively copying directories. */ -static Lisp_Object Qcopy_directory; - -/* Lisp function for recursively deleting directories. */ -static Lisp_Object Qdelete_directory; - -static Lisp_Object Qsubstitute_env_in_file_name; - -Lisp_Object Qfile_error, Qfile_notify_error; -static Lisp_Object Qfile_already_exists, Qfile_date_error; -static Lisp_Object Qexcl; -Lisp_Object Qfile_name_history; - -static Lisp_Object Qcar_less_than_car; - static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, Lisp_Object *, struct coding_system *); static bool e_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t, @@ -197,7 +160,7 @@ check_writable (const char *filename, int amode) bool res = faccessat (AT_FDCWD, filename, amode, AT_EACCESS) == 0; #ifdef CYGWIN /* faccessat may have returned failure because Cygwin couldn't - determine the file's UID or GID; if so, we return success. */ + determine the file's UID or GID; if so, we return success. */ if (!res) { int faccessat_errno = errno; @@ -223,37 +186,17 @@ void report_file_errno (char const *string, Lisp_Object name, int errorno) { Lisp_Object data = CONSP (name) || NILP (name) ? name : list1 (name); - Lisp_Object errstring; - char *str; - synchronize_system_messages_locale (); - str = strerror (errorno); - errstring = code_convert_string_norecord (build_unibyte_string (str), - Vlocale_coding_system, 0); - - while (1) - switch (errorno) - { - case EEXIST: - xsignal (Qfile_already_exists, Fcons (errstring, data)); - break; - default: - /* System error messages are capitalized. Downcase the initial - unless it is followed by a slash. (The slash case caters to - error messages that begin with "I/O" or, in German, "E/A".) */ - if (STRING_MULTIBYTE (errstring) - && ! EQ (Faref (errstring, make_number (1)), make_number ('/'))) - { - int c; - - str = SSDATA (errstring); - c = STRING_CHAR ((unsigned char *) str); - Faset (errstring, make_number (0), make_number (downcase (c))); - } - - xsignal (Qfile_error, - Fcons (build_string (string), Fcons (errstring, data))); - } + char *str = strerror (errorno); + Lisp_Object errstring + = code_convert_string_norecord (build_unibyte_string (str), + Vlocale_coding_system, 0); + Lisp_Object errdata = Fcons (errstring, data); + + if (errorno == EEXIST) + xsignal (Qfile_already_exists, errdata); + else + xsignal (Qfile_error, Fcons (build_string (string), errdata)); } /* Signal a file-access failure that set errno. STRING describes the @@ -290,43 +233,6 @@ restore_point_unwind (Lisp_Object location) } -static Lisp_Object Qexpand_file_name; -static Lisp_Object Qsubstitute_in_file_name; -static Lisp_Object Qdirectory_file_name; -static Lisp_Object Qfile_name_directory; -static Lisp_Object Qfile_name_nondirectory; -static Lisp_Object Qunhandled_file_name_directory; -static Lisp_Object Qfile_name_as_directory; -static Lisp_Object Qcopy_file; -static Lisp_Object Qmake_directory_internal; -static Lisp_Object Qmake_directory; -static Lisp_Object Qdelete_directory_internal; -Lisp_Object Qdelete_file; -static Lisp_Object Qrename_file; -static Lisp_Object Qadd_name_to_file; -static Lisp_Object Qmake_symbolic_link; -Lisp_Object Qfile_exists_p; -static Lisp_Object Qfile_executable_p; -static Lisp_Object Qfile_readable_p; -static Lisp_Object Qfile_writable_p; -static Lisp_Object Qfile_symlink_p; -static Lisp_Object Qaccess_file; -Lisp_Object Qfile_directory_p; -static Lisp_Object Qfile_regular_p; -static Lisp_Object Qfile_accessible_directory_p; -static Lisp_Object Qfile_modes; -static Lisp_Object Qset_file_modes; -static Lisp_Object Qset_file_times; -static Lisp_Object Qfile_selinux_context; -static Lisp_Object Qset_file_selinux_context; -static Lisp_Object Qfile_acl; -static Lisp_Object Qset_file_acl; -static Lisp_Object Qfile_newer_than_file_p; -Lisp_Object Qinsert_file_contents; -Lisp_Object Qwrite_region; -static Lisp_Object Qverify_visited_file_modtime; -static Lisp_Object Qset_visited_file_modtime; - DEFUN ("find-file-name-handler", Ffind_file_name_handler, Sfind_file_name_handler, 2, 2, 0, doc: /* Return FILENAME's handler function for OPERATION, if it has one. @@ -396,13 +302,6 @@ Otherwise return a directory name. Given a Unix syntax file name, returns a string ending in slash. */) (Lisp_Object filename) { -#ifndef DOS_NT - register const char *beg; -#else - register char *beg; - Lisp_Object tem_fn; -#endif - register const char *p; Lisp_Object handler; CHECK_STRING (filename); @@ -417,12 +316,8 @@ Given a Unix syntax file name, returns a string ending in slash. */) return STRINGP (handled_name) ? handled_name : Qnil; } -#ifdef DOS_NT - beg = xlispstrdupa (filename); -#else - beg = SSDATA (filename); -#endif - p = beg + SBYTES (filename); + char *beg = SSDATA (filename); + char const *p = beg + SBYTES (filename); while (p != beg && !IS_DIRECTORY_SEP (p[-1]) #ifdef DOS_NT @@ -438,6 +333,11 @@ Given a Unix syntax file name, returns a string ending in slash. */) return Qnil; #ifdef DOS_NT /* Expansion of "c:" to drive and default directory. */ + Lisp_Object tem_fn; + USE_SAFE_ALLOCA; + SAFE_ALLOCA_STRING (beg, filename); + p = beg + (p - SSDATA (filename)); + if (p[-1] == ':') { /* MAXPATHLEN+1 is guaranteed to be enough space for getdefdir. */ @@ -481,6 +381,7 @@ Given a Unix syntax file name, returns a string ending in slash. */) dostounix_filename (beg); tem_fn = make_specified_string (beg, -1, p - beg, 0); } + SAFE_FREE (); return tem_fn; #else /* DOS_NT */ return make_specified_string (beg, -1, p - beg, STRING_MULTIBYTE (filename)); @@ -603,8 +504,6 @@ For a Unix-syntax file name, just appends a slash. */) USE_SAFE_ALLOCA; CHECK_STRING (file); - if (NILP (file)) - return Qnil; /* If the file name has special constructs in it, call the corresponding file handler. */ @@ -672,9 +571,6 @@ In Unix-syntax, this function just removes the final slash. */) CHECK_STRING (directory); - if (NILP (directory)) - return Qnil; - /* If the file name has special constructs in it, call the corresponding file handler. */ handler = Ffind_file_name_handler (directory, Qdirectory_file_name); @@ -847,8 +743,6 @@ probably use `make-temp-file' instead, except in three circumstances: return make_temp_name (prefix, 0); } - - DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0, doc: /* Convert filename NAME to absolute, and canonicalize it. Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relative @@ -878,7 +772,9 @@ filesystem tree, not (expand-file-name ".." dirname). */) /* These point to SDATA and need to be careful with string-relocation during GC (via DECODE_FILE). */ char *nm; + char *nmlim; const char *newdir; + const char *newdirlim; /* This should only point to alloca'd data. */ char *target; @@ -886,10 +782,10 @@ filesystem tree, not (expand-file-name ".." dirname). */) struct passwd *pw; #ifdef DOS_NT int drive = 0; - bool collapse_newdir = 1; + bool collapse_newdir = true; bool is_escaped = 0; #endif /* DOS_NT */ - ptrdiff_t length; + ptrdiff_t length, nbytes; Lisp_Object handler, result, handled_name; bool multibyte; Lisp_Object hdir; @@ -989,7 +885,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) { unsigned char *p = SDATA (name); - while (*p && ASCII_BYTE_P (*p)) + while (*p && ASCII_CHAR_P (*p)) p++; if (*p == '\0') { @@ -1018,8 +914,9 @@ filesystem tree, not (expand-file-name ".." dirname). */) default_directory = Fdowncase (default_directory); #endif - /* Make a local copy of nm[] to protect it from GC in DECODE_FILE below. */ - nm = xlispstrdupa (name); + /* Make a local copy of NAME to protect it from GC in DECODE_FILE below. */ + SAFE_ALLOCA_STRING (nm, name); + nmlim = nm + SBYTES (name); #ifdef DOS_NT /* Note if special escape prefix is present, but remove for now. */ @@ -1104,7 +1001,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) if (IS_DIRECTORY_SEP (nm[1])) { if (strcmp (nm, SSDATA (name)) != 0) - name = make_specified_string (nm, -1, strlen (nm), multibyte); + name = make_specified_string (nm, -1, nmlim - nm, multibyte); } else #endif @@ -1115,18 +1012,19 @@ filesystem tree, not (expand-file-name ".." dirname). */) name = make_specified_string (nm, -1, p - nm, multibyte); temp[0] = DRIVE_LETTER (drive); - name = concat2 (build_string (temp), name); + AUTO_STRING (drive_prefix, temp); + name = concat2 (drive_prefix, name); } #ifdef WINDOWSNT if (!NILP (Vw32_downcase_file_names)) name = Fdowncase (name); #endif - return name; #else /* not DOS_NT */ - if (strcmp (nm, SSDATA (name)) == 0) - return name; - return make_specified_string (nm, -1, strlen (nm), multibyte); + if (strcmp (nm, SSDATA (name)) != 0) + name = make_specified_string (nm, -1, nmlim - nm, multibyte); #endif /* not DOS_NT */ + SAFE_FREE (); + return name; } } @@ -1146,7 +1044,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) return an absolute name, if the final prefix is not absolute we append it to the current working directory. */ - newdir = 0; + newdir = newdirlim = 0; if (nm[0] == '~') /* prefix ~ */ { @@ -1156,7 +1054,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) Lisp_Object tem; if (!(newdir = egetenv ("HOME"))) - newdir = ""; + newdir = newdirlim = ""; nm++; /* `egetenv' may return a unibyte string, which will bite us since we expect the directory to be multibyte. */ @@ -1171,13 +1069,15 @@ filesystem tree, not (expand-file-name ".." dirname). */) else #endif tem = build_string (newdir); + newdirlim = newdir + SBYTES (tem); if (multibyte && !STRING_MULTIBYTE (tem)) { hdir = DECODE_FILE (tem); newdir = SSDATA (hdir); + newdirlim = newdir + SBYTES (hdir); } #ifdef DOS_NT - collapse_newdir = 0; + collapse_newdir = false; #endif } else /* ~user/filename */ @@ -1201,14 +1101,16 @@ filesystem tree, not (expand-file-name ".." dirname). */) bite us since we expect the directory to be multibyte. */ tem = make_unibyte_string (newdir, strlen (newdir)); + newdirlim = newdir + SBYTES (tem); if (multibyte && !STRING_MULTIBYTE (tem)) { hdir = DECODE_FILE (tem); newdir = SSDATA (hdir); + newdirlim = newdir + SBYTES (hdir); } nm = p; #ifdef DOS_NT - collapse_newdir = 0; + collapse_newdir = false; #endif } @@ -1234,8 +1136,11 @@ filesystem tree, not (expand-file-name ".." dirname). */) Lisp_Object tem = build_string (adir); tem = DECODE_FILE (tem); + newdirlim = adir + SBYTES (tem); memcpy (adir, SSDATA (tem), SBYTES (tem) + 1); } + else + newdirlim = adir + strlen (adir); } if (!adir) { @@ -1245,6 +1150,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) adir[1] = ':'; adir[2] = '/'; adir[3] = 0; + newdirlim = adir + 3; } newdir = adir; } @@ -1265,6 +1171,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) && !newdir) { newdir = SSDATA (default_directory); + newdirlim = newdir + SBYTES (default_directory); #ifdef DOS_NT /* Note if special escape prefix is present, but remove for now. */ if (newdir[0] == '/' && newdir[1] == ':') @@ -1309,12 +1216,15 @@ filesystem tree, not (expand-file-name ".." dirname). */) } if (!IS_DIRECTORY_SEP (nm[0])) { - ptrdiff_t newlen = strlen (newdir); - char *tmp = alloca (newlen + file_name_as_directory_slop - + strlen (nm) + 1); - file_name_as_directory (tmp, newdir, newlen, multibyte); - strcat (tmp, nm); + ptrdiff_t nmlen = nmlim - nm; + ptrdiff_t newdirlen = newdirlim - newdir; + char *tmp = alloca (newdirlen + file_name_as_directory_slop + + nmlen + 1); + ptrdiff_t dlen = file_name_as_directory (tmp, newdir, newdirlen, + multibyte); + memcpy (tmp + dlen, nm, nmlen + 1); nm = tmp; + nmlim = nm + dlen + nmlen; } adir = alloca (adir_size); if (drive) @@ -1329,8 +1239,11 @@ filesystem tree, not (expand-file-name ".." dirname). */) Lisp_Object tem = build_string (adir); tem = DECODE_FILE (tem); + newdirlim = adir + SBYTES (tem); memcpy (adir, SSDATA (tem), SBYTES (tem) + 1); } + else + newdirlim = adir + strlen (adir); newdir = adir; } @@ -1349,35 +1262,32 @@ filesystem tree, not (expand-file-name ".." dirname). */) if (IS_DIRECTORY_SEP (newdir[0]) && IS_DIRECTORY_SEP (newdir[1]) && !IS_DIRECTORY_SEP (newdir[2])) { - char *adir = strcpy (alloca (strlen (newdir) + 1), newdir); + char *adir = strcpy (alloca (newdirlim - newdir + 1), newdir); char *p = adir + 2; while (*p && !IS_DIRECTORY_SEP (*p)) p++; p++; while (*p && !IS_DIRECTORY_SEP (*p)) p++; *p = 0; newdir = adir; + newdirlim = newdir + strlen (adir); } else #endif - newdir = ""; + newdir = newdirlim = ""; } } #endif /* DOS_NT */ - if (newdir) - { - /* Ignore any slash at the end of newdir, unless newdir is - just "/" or "//". */ - length = strlen (newdir); - while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1]) - && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0]))) - length--; - } - else - length = 0; + /* Ignore any slash at the end of newdir, unless newdir is + just "/" or "//". */ + length = newdirlim - newdir; + while (length > 1 && IS_DIRECTORY_SEP (newdir[length - 1]) + && ! (length == 2 && IS_DIRECTORY_SEP (newdir[0]))) + length--; /* Now concatenate the directory and name to new space in the stack frame. */ - tlen = length + file_name_as_directory_slop + strlen (nm) + 1; + tlen = length + file_name_as_directory_slop + (nmlim - nm) + 1; + eassert (tlen > file_name_as_directory_slop + 1); #ifdef DOS_NT /* Reserve space for drive specifier and escape prefix, since either or both may need to be inserted. (The Microsoft x86 compiler @@ -1388,6 +1298,7 @@ filesystem tree, not (expand-file-name ".." dirname). */) target = SAFE_ALLOCA (tlen); #endif /* not DOS_NT */ *target = 0; + nbytes = 0; if (newdir) { @@ -1405,13 +1316,14 @@ filesystem tree, not (expand-file-name ".." dirname). */) { memcpy (target, newdir, length); target[length] = 0; + nbytes = length; } } else - file_name_as_directory (target, newdir, length, multibyte); + nbytes = file_name_as_directory (target, newdir, length, multibyte); } - strcat (target, nm); + memcpy (target + nbytes, nm, nmlim - nm + 1); /* Now canonicalize by removing `//', `/.' and `/foo/..' if they appear. */ @@ -1717,7 +1629,8 @@ search_embedded_absfilename (char *nm, char *endp) for (s = p; *s && !IS_DIRECTORY_SEP (*s); s++); if (p[0] == '~' && s > p + 1) /* We've got "/~something/". */ { - char *o = alloca (s - p + 1); + USE_SAFE_ALLOCA; + char *o = SAFE_ALLOCA (s - p + 1); struct passwd *pw; memcpy (o, p, s - p); o [s - p] = 0; @@ -1728,6 +1641,7 @@ search_embedded_absfilename (char *nm, char *endp) block_input (); pw = getpwnam (o + 1); unblock_input (); + SAFE_FREE (); if (pw) return p; } @@ -1776,7 +1690,8 @@ those `/' is discarded. */) /* Always work on a copy of the string, in case GC happens during decode of environment variables, causing the original Lisp_String data to be relocated. */ - nm = xlispstrdupa (filename); + USE_SAFE_ALLOCA; + SAFE_ALLOCA_STRING (nm, filename); #ifdef DOS_NT dostounix_filename (nm); @@ -1790,8 +1705,13 @@ those `/' is discarded. */) /* Start over with the new string, so we check the file-name-handler again. Important with filenames like "/home/foo//:/hello///there" which would substitute to "/:/hello///there" rather than "/there". */ - return Fsubstitute_in_file_name - (make_specified_string (p, -1, endp - p, multibyte)); + { + Lisp_Object result + = (Fsubstitute_in_file_name + (make_specified_string (p, -1, endp - p, multibyte))); + SAFE_FREE (); + return result; + } /* See if any variables are substituted into the string. */ @@ -1813,6 +1733,7 @@ those `/' is discarded. */) if (!NILP (Vw32_downcase_file_names)) filename = Fdowncase (filename); #endif + SAFE_FREE (); return filename; } @@ -1831,14 +1752,14 @@ those `/' is discarded. */) { Lisp_Object xname = make_specified_string (xnm, -1, x - xnm, multibyte); - xname = Fdowncase (xname); - return xname; + filename = Fdowncase (xname); } else #endif - return (xnm == SSDATA (filename) - ? filename - : make_specified_string (xnm, -1, x - xnm, multibyte)); + if (xnm != SSDATA (filename)) + filename = make_specified_string (xnm, -1, x - xnm, multibyte); + SAFE_FREE (); + return filename; } /* A slightly faster and more convenient way to get @@ -2671,7 +2592,10 @@ emacs_readlinkat (int fd, char const *filename) val = build_unibyte_string (buf); if (buf[0] == '/' && strchr (buf, ':')) - val = concat2 (build_unibyte_string ("/:"), val); + { + AUTO_STRING (slash_colon, "/:"); + val = concat2 (slash_colon, val); + } if (buf != readlink_buf) xfree (buf); val = DECODE_FILE (val); @@ -2765,23 +2689,24 @@ searchable directory. */) } absname = ENCODE_FILE (absname); - return file_accessible_directory_p (SSDATA (absname)) ? Qt : Qnil; + return file_accessible_directory_p (absname) ? Qt : Qnil; } /* If FILE is a searchable directory or a symlink to a searchable directory, return true. Otherwise return false and set errno to an error number. */ bool -file_accessible_directory_p (char const *file) +file_accessible_directory_p (Lisp_Object file) { #ifdef DOS_NT /* There's no need to test whether FILE is searchable, as the searchable/executable bit is invented on DOS_NT platforms. */ - return file_directory_p (file); + return file_directory_p (SSDATA (file)); #else /* On POSIXish platforms, use just one system call; this avoids a race and is typically faster. */ - ptrdiff_t len = strlen (file); + const char *data = SSDATA (file); + ptrdiff_t len = SBYTES (file); char const *dir; bool ok; int saved_errno; @@ -2793,15 +2718,15 @@ file_accessible_directory_p (char const *file) "/" and "//" are distinct on some platforms, whereas "/", "///", "////", etc. are all equivalent. */ if (! len) - dir = file; + dir = data; else { /* Just check for trailing '/' when deciding whether to append '/'. That's simpler than testing the two special cases "/" and "//", and it's a safe optimization here. */ char *buf = SAFE_ALLOCA (len + 3); - memcpy (buf, file, len); - strcpy (buf + len, &"/."[file[len - 1] == '/']); + memcpy (buf, data, len); + strcpy (buf + len, &"/."[data[len - 1] == '/']); dir = buf; } @@ -2867,7 +2792,8 @@ or if SELinux is disabled, or if Emacs lacks SELinux support. */) (Lisp_Object filename) { Lisp_Object absname; - Lisp_Object values[4]; + Lisp_Object user = Qnil, role = Qnil, type = Qnil, range = Qnil; + Lisp_Object handler; #if HAVE_LIBSELINUX security_context_t con; @@ -2885,10 +2811,6 @@ or if SELinux is disabled, or if Emacs lacks SELinux support. */) absname = ENCODE_FILE (absname); - values[0] = Qnil; - values[1] = Qnil; - values[2] = Qnil; - values[3] = Qnil; #if HAVE_LIBSELINUX if (is_selinux_enabled ()) { @@ -2897,20 +2819,20 @@ or if SELinux is disabled, or if Emacs lacks SELinux support. */) { context = context_new (con); if (context_user_get (context)) - values[0] = build_string (context_user_get (context)); + user = build_string (context_user_get (context)); if (context_role_get (context)) - values[1] = build_string (context_role_get (context)); + role = build_string (context_role_get (context)); if (context_type_get (context)) - values[2] = build_string (context_type_get (context)); + type = build_string (context_type_get (context)); if (context_range_get (context)) - values[3] = build_string (context_range_get (context)); + range = build_string (context_range_get (context)); context_free (context); freecon (con); } } #endif - return Flist (sizeof (values) / sizeof (values[0]), values); + return list4 (user, role, type, range); } DEFUN ("set-file-selinux-context", Fset_file_selinux_context, @@ -3386,6 +3308,56 @@ time_error_value (int errnum) return make_timespec (0, ns); } +static Lisp_Object +get_window_points_and_markers (void) +{ + Lisp_Object pt_marker = Fpoint_marker (); + Lisp_Object windows + = call3 (Qget_buffer_window_list, Fcurrent_buffer (), Qnil, Qt); + Lisp_Object window_markers = windows; + /* Window markers (and point) are handled specially: rather than move to + just before or just after the modified text, we try to keep the + markers at the same distance (bug#19161). + In general, this is wrong, but for window-markers, this should be harmless + and is convenient for the end user when most of the file is unmodified, + except for a few minor details near the beginning and near the end. */ + for (; CONSP (windows); windows = XCDR (windows)) + if (WINDOWP (XCAR (windows))) + { + Lisp_Object window_marker = XWINDOW (XCAR (windows))->pointm; + XSETCAR (windows, + Fcons (window_marker, Fmarker_position (window_marker))); + } + return Fcons (Fcons (pt_marker, Fpoint ()), window_markers); +} + +static void +restore_window_points (Lisp_Object window_markers, ptrdiff_t inserted, + ptrdiff_t same_at_start, ptrdiff_t same_at_end) +{ + for (; CONSP (window_markers); window_markers = XCDR (window_markers)) + if (CONSP (XCAR (window_markers))) + { + Lisp_Object car = XCAR (window_markers); + Lisp_Object marker = XCAR (car); + Lisp_Object oldpos = XCDR (car); + if (MARKERP (marker) && INTEGERP (oldpos) + && XINT (oldpos) > same_at_start + && XINT (oldpos) < same_at_end) + { + ptrdiff_t oldsize = same_at_end - same_at_start; + ptrdiff_t newsize = inserted; + double growth = newsize / (double)oldsize; + ptrdiff_t newpos + = same_at_start + growth * (XINT (oldpos) - same_at_start); + Fset_marker (marker, make_number (newpos), Qnil); + } + } +} + +/* FIXME: insert-file-contents should be split with the top-level moved to + Elisp and only the core kept in C. */ + DEFUN ("insert-file-contents", Finsert_file_contents, Sinsert_file_contents, 1, 5, 0, doc: /* Insert contents of file FILENAME after point. @@ -3430,24 +3402,32 @@ by calling `format-decode', which see. */) int save_errno = 0; char read_buf[READ_BUF_SIZE]; struct coding_system coding; - bool replace_handled = 0; - bool set_coding_system = 0; + bool replace_handled = false; + bool set_coding_system = false; Lisp_Object coding_system; - bool read_quit = 0; + bool read_quit = false; /* If the undo log only contains the insertion, there's no point keeping it. It's typically when we first fill a file-buffer. */ bool empty_undo_list_p = (!NILP (visit) && NILP (BVAR (current_buffer, undo_list)) && BEG == Z); Lisp_Object old_Vdeactivate_mark = Vdeactivate_mark; - bool we_locked_file = 0; + bool we_locked_file = false; ptrdiff_t fd_index; + Lisp_Object window_markers = Qnil; + /* same_at_start and same_at_end count bytes, because file access counts + bytes and BEG and END count bytes. */ + ptrdiff_t same_at_start = BEGV_BYTE; + ptrdiff_t same_at_end = ZV_BYTE; + /* SAME_AT_END_CHARPOS counts characters, because + restore_window_points needs the old character count. */ + ptrdiff_t same_at_end_charpos = ZV; if (current_buffer->base_buffer && ! NILP (visit)) error ("Cannot do file visiting in an indirect buffer"); if (!NILP (BVAR (current_buffer, read_only))) - Fbarf_if_buffer_read_only (); + Fbarf_if_buffer_read_only (Qnil); val = Qnil; p = Qnil; @@ -3497,7 +3477,11 @@ by calling `format-decode', which see. */) /* Replacement should preserve point as it preserves markers. */ if (!NILP (replace)) - record_unwind_protect (restore_point_unwind, Fpoint_marker ()); + { + window_markers = get_window_points_and_markers (); + record_unwind_protect (restore_point_unwind, + XCAR (XCAR (window_markers))); + } if (fstat (fd, &st) != 0) report_file_error ("Input file status", orig_filename); @@ -3575,14 +3559,14 @@ by calling `format-decode', which see. */) } /* Prevent redisplay optimizations. */ - current_buffer->clip_changed = 1; + current_buffer->clip_changed = true; if (EQ (Vcoding_system_for_read, Qauto_save_coding)) { coding_system = coding_inherit_eol_type (Qutf_8_emacs, Qunix); setup_coding_system (coding_system, &coding); /* Ensure we set Vlast_coding_system_used. */ - set_coding_system = 1; + set_coding_system = true; } else if (BEG < Z) { @@ -3624,13 +3608,14 @@ by calling `format-decode', which see. */) report_file_error ("Read error", orig_filename); else if (nread > 0) { + AUTO_STRING (name, " *code-converting-work*"); struct buffer *prev = current_buffer; Lisp_Object workbuf; struct buffer *buf; record_unwind_current_buffer (); - workbuf = Fget_buffer_create (build_string (" *code-converting-work*")); + workbuf = Fget_buffer_create (name); buf = XBUFFER (workbuf); delete_all_overlays (buf); @@ -3665,11 +3650,9 @@ by calling `format-decode', which see. */) { /* If we have not yet decided a coding system, check file-coding-system-alist. */ - Lisp_Object args[6]; - - args[0] = Qinsert_file_contents, args[1] = orig_filename; - args[2] = visit, args[3] = beg, args[4] = end, args[5] = replace; - coding_system = Ffind_operation_coding_system (6, args); + coding_system = CALLN (Ffind_operation_coding_system, + Qinsert_file_contents, orig_filename, + visit, beg, end, replace); if (CONSP (coding_system)) coding_system = XCAR (coding_system); } @@ -3687,7 +3670,7 @@ by calling `format-decode', which see. */) setup_coding_system (coding_system, &coding); /* Ensure we set Vlast_coding_system_used. */ - set_coding_system = 1; + set_coding_system = true; } /* If requested, replace the accessible part of the buffer @@ -3709,16 +3692,11 @@ by calling `format-decode', which see. */) && (NILP (coding_system) || ! CODING_REQUIRE_DECODING (&coding))) { - /* same_at_start and same_at_end count bytes, - because file access counts bytes - and BEG and END count bytes. */ - ptrdiff_t same_at_start = BEGV_BYTE; - ptrdiff_t same_at_end = ZV_BYTE; ptrdiff_t overlap; /* There is still a possibility we will find the need to do code conversion. If that happens, set this variable to give up on handling REPLACE in the optimized way. */ - bool giveup_match_end = 0; + bool giveup_match_end = false; if (beg_offset != 0) { @@ -3752,7 +3730,7 @@ by calling `format-decode', which see. */) /* We found that the file should be decoded somehow. Let's give up here. */ { - giveup_match_end = 1; + giveup_match_end = true; break; } @@ -3765,7 +3743,7 @@ by calling `format-decode', which see. */) if (bufpos != nread) break; } - immediate_quit = 0; + immediate_quit = false; /* If the file matches the buffer completely, there's no need to replace anything. */ if (same_at_start - BEGV_BYTE == end_offset - beg_offset) @@ -3777,7 +3755,7 @@ by calling `format-decode', which see. */) del_range_1 (same_at_start, same_at_end, 0, 0); goto handled; } - immediate_quit = 1; + immediate_quit = true; QUIT; /* Count how many chars at the end of the file match the text at the end of the buffer. But, if we have @@ -3828,7 +3806,7 @@ by calling `format-decode', which see. */) && FETCH_BYTE (same_at_end - 1) >= 0200 && ! NILP (BVAR (current_buffer, enable_multibyte_characters)) && (CODING_MAY_REQUIRE_DECODING (&coding))) - giveup_match_end = 1; + giveup_match_end = true; break; } @@ -3863,6 +3841,7 @@ by calling `format-decode', which see. */) + (! NILP (end) ? end_offset : st.st_size) - ZV_BYTE)); if (overlap > 0) same_at_end += overlap; + same_at_end_charpos = BYTE_TO_CHAR (same_at_end); /* Arrange to read only the nonmatching middle part of the file. */ beg_offset += same_at_start - BEGV_BYTE; @@ -3870,7 +3849,7 @@ by calling `format-decode', which see. */) invalidate_buffer_caches (current_buffer, BYTE_TO_CHAR (same_at_start), - BYTE_TO_CHAR (same_at_end)); + same_at_end_charpos); del_range_byte (same_at_start, same_at_end, 0); /* Insert from the file at the proper position. */ temp = BYTE_TO_CHAR (same_at_start); @@ -3881,7 +3860,7 @@ by calling `format-decode', which see. */) if (XBUFFER (XWINDOW (selected_window)->contents) == current_buffer) XWINDOW (selected_window)->start_at_line_beg = !NILP (Fbolp ()); - replace_handled = 1; + replace_handled = true; } } @@ -3896,8 +3875,6 @@ by calling `format-decode', which see. */) in a more optimized way. */ if (!NILP (replace) && ! replace_handled && BEGV < ZV) { - ptrdiff_t same_at_start = BEGV_BYTE; - ptrdiff_t same_at_end = ZV_BYTE; ptrdiff_t same_at_start_charpos; ptrdiff_t inserted_chars; ptrdiff_t overlap; @@ -3961,7 +3938,7 @@ by calling `format-decode', which see. */) } coding_system = CODING_ID_NAME (coding.id); - set_coding_system = 1; + set_coding_system = true; decoded = BUF_BEG_ADDR (XBUFFER (conversion_buffer)); inserted = (BUF_Z_BYTE (XBUFFER (conversion_buffer)) - BUF_BEG_BYTE (XBUFFER (conversion_buffer))); @@ -4021,6 +3998,7 @@ by calling `format-decode', which see. */) overlap = same_at_start - BEGV_BYTE - (same_at_end + inserted - ZV_BYTE); if (overlap > 0) same_at_end += overlap; + same_at_end_charpos = BYTE_TO_CHAR (same_at_end); /* If display currently starts at beginning of line, keep it that way. */ @@ -4036,7 +4014,7 @@ by calling `format-decode', which see. */) { invalidate_buffer_caches (current_buffer, BYTE_TO_CHAR (same_at_start), - BYTE_TO_CHAR (same_at_end)); + same_at_end_charpos); del_range_byte (same_at_start, same_at_end, 0); temp = GPT; eassert (same_at_start == GPT_BYTE); @@ -4044,7 +4022,7 @@ by calling `format-decode', which see. */) } else { - temp = BYTE_TO_CHAR (same_at_start); + temp = same_at_end_charpos; } /* Insert from the file at the proper position. */ SET_PT_BOTH (temp, same_at_start); @@ -4082,13 +4060,11 @@ by calling `format-decode', which see. */) if (NILP (visit) && total > 0) { -#ifdef CLASH_DETECTION if (!NILP (BVAR (current_buffer, file_truename)) /* Make binding buffer-file-name to nil effective. */ && !NILP (BVAR (current_buffer, filename)) && SAVE_MODIFF >= MODIFF) - we_locked_file = 1; -#endif /* CLASH_DETECTION */ + we_locked_file = true; prepare_to_modify_buffer (PT, PT, NULL); } @@ -4118,7 +4094,7 @@ by calling `format-decode', which see. */) while (how_much < total) { - /* try is reserved in some compilers (Microsoft C) */ + /* `try' is reserved in some compilers (Microsoft C). */ ptrdiff_t trytry = min (total - how_much, READ_BUF_SIZE); ptrdiff_t this; @@ -4143,7 +4119,7 @@ by calling `format-decode', which see. */) if (NILP (nbytes)) { - read_quit = 1; + read_quit = true; break; } @@ -4188,10 +4164,8 @@ by calling `format-decode', which see. */) if (inserted == 0) { -#ifdef CLASH_DETECTION if (we_locked_file) unlock_file (BVAR (current_buffer, file_truename)); -#endif Vdeactivate_mark = old_Vdeactivate_mark; } else @@ -4255,11 +4229,9 @@ by calling `format-decode', which see. */) { /* If the coding system is not yet decided, check file-coding-system-alist. */ - Lisp_Object args[6]; - - args[0] = Qinsert_file_contents, args[1] = orig_filename; - args[2] = visit, args[3] = beg, args[4] = end, args[5] = Qnil; - coding_system = Ffind_operation_coding_system (6, args); + coding_system = CALLN (Ffind_operation_coding_system, + Qinsert_file_contents, orig_filename, + visit, beg, end, Qnil); if (CONSP (coding_system)) coding_system = XCAR (coding_system); } @@ -4278,7 +4250,7 @@ by calling `format-decode', which see. */) coding_system = raw_text_coding_system (coding_system); setup_coding_system (coding_system, &coding); /* Ensure we set Vlast_coding_system_used. */ - set_coding_system = 1; + set_coding_system = true; } if (!NILP (visit)) @@ -4289,7 +4261,7 @@ by calling `format-decode', which see. */) /* Can't do this if part of the buffer might be preserved. */ && NILP (replace)) /* Visiting a file with these coding system makes the buffer - unibyte. */ + unibyte. */ bset_enable_multibyte_characters (current_buffer, Qnil); } @@ -4328,6 +4300,11 @@ by calling `format-decode', which see. */) handled: + if (inserted > 0) + restore_window_points (window_markers, inserted, + BYTE_TO_CHAR (same_at_start), + same_at_end_charpos); + if (!NILP (visit)) { if (empty_undo_list_p) @@ -4343,14 +4320,12 @@ by calling `format-decode', which see. */) SAVE_MODIFF = MODIFF; BUF_AUTOSAVE_MODIFF (current_buffer) = MODIFF; XSETFASTINT (BVAR (current_buffer, save_length), Z - BEG); -#ifdef CLASH_DETECTION if (NILP (handler)) { if (!NILP (BVAR (current_buffer, file_truename))) unlock_file (BVAR (current_buffer, file_truename)); unlock_file (filename); } -#endif /* CLASH_DETECTION */ if (not_regular) xsignal2 (Qfile_error, build_string ("not a regular file"), orig_filename); @@ -4584,12 +4559,9 @@ choose_write_coding_system (Lisp_Object start, Lisp_Object end, Lisp_Object file if (NILP (val)) { /* Check file-coding-system-alist. */ - Lisp_Object args[7], coding_systems; - - args[0] = Qwrite_region; args[1] = start; args[2] = end; - args[3] = filename; args[4] = append; args[5] = visit; - args[6] = lockname; - coding_systems = Ffind_operation_coding_system (7, args); + Lisp_Object coding_systems + = CALLN (Ffind_operation_coding_system, Qwrite_region, start, end, + filename, append, visit, lockname); if (CONSP (coding_systems) && !NILP (XCDR (coding_systems))) val = XCDR (coding_systems); } @@ -4659,8 +4631,8 @@ Optional fifth argument VISIT, if t or a string, means If VISIT is a string, it is a second file name; the output goes to FILENAME, but the buffer is marked as visiting VISIT. VISIT is also the file name to lock and unlock for clash detection. -If VISIT is neither t nor nil nor a string, - that means do not display the \"Wrote file\" message. +If VISIT is neither t nor nil nor a string, or if Emacs is in batch mode, + do not display the \"Wrote file\" message. The optional sixth arg LOCKNAME, if non-nil, specifies the name to use for locking and unlocking, overriding FILENAME and VISIT. The optional seventh arg MUSTBENEW, if non-nil, insists on a check @@ -4809,13 +4781,11 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, = choose_write_coding_system (start, end, filename, append, visit, lockname, &coding); -#ifdef CLASH_DETECTION if (open_and_close_file && !auto_saving) { lock_file (lockname); file_locked = 1; } -#endif /* CLASH_DETECTION */ encoded_filename = ENCODE_FILE (filename); fn = SSDATA (encoded_filename); @@ -4837,10 +4807,8 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, if (desc < 0) { int open_errno = errno; -#ifdef CLASH_DETECTION if (file_locked) unlock_file (lockname); -#endif /* CLASH_DETECTION */ UNGCPRO; report_file_errno ("Opening output file", filename, open_errno); } @@ -4855,10 +4823,8 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, if (ret < 0) { int lseek_errno = errno; -#ifdef CLASH_DETECTION if (file_locked) unlock_file (lockname); -#endif /* CLASH_DETECTION */ UNGCPRO; report_file_errno ("Lseek error", filename, lseek_errno); } @@ -5001,10 +4967,8 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, unbind_to (count, Qnil); -#ifdef CLASH_DETECTION if (file_locked) unlock_file (lockname); -#endif /* CLASH_DETECTION */ /* Do this before reporting IO error to avoid a "file has changed on disk" warning on @@ -5035,7 +4999,7 @@ write_region (Lisp_Object start, Lisp_Object end, Lisp_Object filename, return Qnil; } - if (!auto_saving) + if (!auto_saving && !noninteractive) message_with_string ((NUMBERP (append) ? "Updated %s" : ! NILP (append) @@ -5050,10 +5014,7 @@ DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0, doc: /* Return t if (car A) is numerically less than (car B). */) (Lisp_Object a, Lisp_Object b) { - Lisp_Object args[2]; - args[0] = Fcar (a); - args[1] = Fcar (b); - return Flss (2, args); + return CALLN (Flss, Fcar (a), Fcar (b)); } /* Build the complete list of annotations appropriate for writing out @@ -5072,7 +5033,7 @@ build_annotations (Lisp_Object start, Lisp_Object end) struct gcpro gcpro1, gcpro2; Lisp_Object original_buffer; int i; - bool used_global = 0; + bool used_global = false; XSETBUFFER (original_buffer, current_buffer); @@ -5084,11 +5045,10 @@ build_annotations (Lisp_Object start, Lisp_Object end) struct buffer *given_buffer = current_buffer; if (EQ (Qt, XCAR (p)) && !used_global) { /* Use the global value of the hook. */ - Lisp_Object arg[2]; - used_global = 1; - arg[0] = Fdefault_value (Qwrite_region_annotate_functions); - arg[1] = XCDR (p); - p = Fappend (2, arg); + used_global = true; + p = CALLN (Fappend, + Fdefault_value (Qwrite_region_annotate_functions), + XCDR (p)); continue; } Vwrite_region_annotations_so_far = annotations; @@ -5309,20 +5269,12 @@ If BUF is omitted or nil, it defaults to the current buffer. See Info node `(elisp)Modification Time' for more details. */) (Lisp_Object buf) { - struct buffer *b; + struct buffer *b = decode_buffer (buf); struct stat st; Lisp_Object handler; Lisp_Object filename; struct timespec mtime; - if (NILP (buf)) - b = current_buffer; - else - { - CHECK_BUFFER (buf); - b = XBUFFER (buf); - } - if (!STRINGP (BVAR (b, filename))) return Qt; if (b->modtime.tv_nsec == UNKNOWN_MODTIME_NSECS) return Qt; @@ -5416,7 +5368,7 @@ An argument specifies the modification time value to use static Lisp_Object auto_save_error (Lisp_Object error_val) { - Lisp_Object args[3], msg; + Lisp_Object msg; int i; struct gcpro gcpro1; @@ -5424,10 +5376,9 @@ auto_save_error (Lisp_Object error_val) ring_bell (XFRAME (selected_frame)); - args[0] = build_string ("Auto-saving %s: %s"); - args[1] = BVAR (current_buffer, name); - args[2] = Ferror_message_string (error_val); - msg = Fformat (3, args); + AUTO_STRING (format, "Auto-saving %s: %s"); + msg = CALLN (Fformat, format, BVAR (current_buffer, name), + Ferror_message_string (error_val)); GCPRO1 (msg); for (i = 0; i < 3; ++i) @@ -5749,8 +5700,8 @@ then any auto-save counts as "recent". */) they're never autosaved. */ return (SAVE_MODIFF < BUF_AUTOSAVE_MODIFF (current_buffer) ? Qt : Qnil); } - -/* Reading and completing file names */ + +/* Reading and completing file names. */ DEFUN ("next-read-file-uses-dialog-p", Fnext_read_file_uses_dialog_p, Snext_read_file_uses_dialog_p, 0, 0, 0, @@ -5759,8 +5710,8 @@ The return value is only relevant for a call to `read-file-name' that happens before any other event (mouse or keypress) is handled. */) (void) { -#if defined (USE_MOTIF) || defined (HAVE_NTGUI) || defined (USE_GTK) \ - || defined (HAVE_NS) +#if (defined USE_GTK || defined USE_MOTIF \ + || defined HAVE_NS || defined HAVE_NTGUI) if ((NILP (last_nonmenu_event) || CONSP (last_nonmenu_event)) && use_dialog_box && use_file_dialog @@ -5770,23 +5721,47 @@ before any other event (mouse or keypress) is handled. */) return Qnil; } -Lisp_Object -Fread_file_name (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object initial, Lisp_Object predicate) + +DEFUN ("set-binary-mode", Fset_binary_mode, Sset_binary_mode, 2, 2, 0, + doc: /* Switch STREAM to binary I/O mode or text I/O mode. +STREAM can be one of the symbols `stdin', `stdout', or `stderr'. +If MODE is non-nil, switch STREAM to binary mode, otherwise switch +it to text mode. + +As a side effect, this function flushes any pending STREAM's data. + +Value is the previous value of STREAM's I/O mode, nil for text mode, +non-nil for binary mode. + +On MS-Windows and MS-DOS, binary mode is needed to read or write +arbitrary binary data, and for disabling translation between CR-LF +pairs and a single newline character. Examples include generation +of text files with Unix-style end-of-line format using `princ' in +batch mode, with standard output redirected to a file. + +On Posix systems, this function always returns non-nil, and has no +effect except for flushing STREAM's data. */) + (Lisp_Object stream, Lisp_Object mode) { - struct gcpro gcpro1; - Lisp_Object args[7]; - - GCPRO1 (default_filename); - args[0] = intern ("read-file-name"); - args[1] = prompt; - args[2] = dir; - args[3] = default_filename; - args[4] = mustmatch; - args[5] = initial; - args[6] = predicate; - RETURN_UNGCPRO (Ffuncall (7, args)); -} + FILE *fp = NULL; + int binmode; + + CHECK_SYMBOL (stream); + if (EQ (stream, Qstdin)) + fp = stdin; + else if (EQ (stream, Qstdout)) + fp = stdout; + else if (EQ (stream, Qstderr)) + fp = stderr; + else + xsignal2 (Qerror, build_string ("unsupported stream"), stream); + binmode = NILP (mode) ? O_TEXT : O_BINARY; + if (fp != stdin) + fflush (fp); + + return (set_binary_mode (fileno (fp), binmode) == O_BINARY) ? Qt : Qnil; +} void init_fileio (void) @@ -5818,7 +5793,10 @@ init_fileio (void) void syms_of_fileio (void) { + /* Property name of a file name handler, + which gives a list of operations it handles. */ DEFSYM (Qoperations, "operations"); + DEFSYM (Qexpand_file_name, "expand-file-name"); DEFSYM (Qsubstitute_in_file_name, "substitute-in-file-name"); DEFSYM (Qdirectory_file_name, "directory-file-name"); @@ -5855,6 +5833,12 @@ syms_of_fileio (void) DEFSYM (Qwrite_region, "write-region"); DEFSYM (Qverify_visited_file_modtime, "verify-visited-file-modtime"); DEFSYM (Qset_visited_file_modtime, "set-visited-file-modtime"); + + /* The symbol bound to coding-system-for-read when + insert-file-contents is called for recovering a file. This is not + an actual coding system name, but just an indicator to tell + insert-file-contents to use `emacs-mule' with a special flag for + auto saving and recovering a file. */ DEFSYM (Qauto_save_coding, "auto-save-coding"); DEFSYM (Qfile_name_history, "file-name-history"); @@ -5890,9 +5874,14 @@ On MS-Windows, the value of this variable is largely ignored if behaves as if file names were encoded in `utf-8'. */); Vdefault_file_name_coding_system = Qnil; + /* Lisp functions for translating file formats. */ DEFSYM (Qformat_decode, "format-decode"); DEFSYM (Qformat_annotate_function, "format-annotate-function"); + + /* Lisp function for setting buffer-file-coding-system and the + multibyteness of the current buffer after inserting a file. */ DEFSYM (Qafter_insert_file_set_coding, "after-insert-file-set-coding"); + DEFSYM (Qcar_less_than_car, "car-less-than-car"); Fput (Qfile_error, Qerror_conditions, @@ -6046,12 +6035,23 @@ When non-nil, certain file deletion commands use the function This includes interactive calls to `delete-file' and `delete-directory' and the Dired deletion commands. */); delete_by_moving_to_trash = 0; - Qdelete_by_moving_to_trash = intern_c_string ("delete-by-moving-to-trash"); + DEFSYM (Qdelete_by_moving_to_trash, "delete-by-moving-to-trash"); + /* Lisp function for moving files to trash. */ DEFSYM (Qmove_file_to_trash, "move-file-to-trash"); + + /* Lisp function for recursively copying directories. */ DEFSYM (Qcopy_directory, "copy-directory"); + + /* Lisp function for recursively deleting directories. */ DEFSYM (Qdelete_directory, "delete-directory"); + DEFSYM (Qsubstitute_env_in_file_name, "substitute-env-in-file-name"); + DEFSYM (Qget_buffer_window_list, "get-buffer-window-list"); + + DEFSYM (Qstdin, "stdin"); + DEFSYM (Qstdout, "stdout"); + DEFSYM (Qstderr, "stderr"); defsubr (&Sfind_file_name_handler); defsubr (&Sfile_name_directory); @@ -6102,6 +6102,8 @@ This includes interactive calls to `delete-file' and defsubr (&Snext_read_file_uses_dialog_p); + defsubr (&Sset_binary_mode); + #ifdef HAVE_SYNC defsubr (&Sunix_sync); #endif |