aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVincent Belaïche2016-01-20 08:30:51 +0100
committerVincent Belaïche2016-01-20 08:30:51 +0100
commitb895c72059521fec064ff27b4cfcfa4104081c4e (patch)
treec1697f0e4d95d8c3556798f6c4c53c98a4714bd0 /src
parentbadcd38aa86ed7973f2be2743c405710973a0bdd (diff)
parent1b76d9168336ede8976b980aeaed64ae2908501a (diff)
downloademacs-b895c72059521fec064ff27b4cfcfa4104081c4e.tar.gz
emacs-b895c72059521fec064ff27b4cfcfa4104081c4e.zip
Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs
Diffstat (limited to 'src')
-rw-r--r--src/buffer.c8
-rw-r--r--src/conf_post.h28
-rw-r--r--src/emacs-module.c3
-rw-r--r--src/fns.c3
-rw-r--r--src/gnutls.c10
-rw-r--r--src/gnutls.h1
-rw-r--r--src/keyboard.c80
-rw-r--r--src/sysdep.c66
-rw-r--r--src/w32.c62
-rw-r--r--src/w32.h1
-rw-r--r--src/w32fns.c42
-rw-r--r--src/w32heap.c89
-rw-r--r--src/w32proc.c7
-rw-r--r--src/window.c64
14 files changed, 336 insertions, 128 deletions
diff --git a/src/buffer.c b/src/buffer.c
index 1468e7a2be1..4df77a181d6 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5630,13 +5630,7 @@ Decimal digits after the % specify field width to which to pad. */);
5630 doc: /* Symbol for current buffer's major mode. 5630 doc: /* Symbol for current buffer's major mode.
5631The default value (normally `fundamental-mode') affects new buffers. 5631The default value (normally `fundamental-mode') affects new buffers.
5632A value of nil means to use the current buffer's major mode, provided 5632A value of nil means to use the current buffer's major mode, provided
5633it is not marked as "special". 5633it is not marked as "special". */);
5634
5635When a mode is used by default, `find-file' switches to it before it
5636reads the contents into the buffer and before it finishes setting up
5637the buffer. Thus, the mode and its hooks should not expect certain
5638variables such as `buffer-read-only' and `buffer-file-coding-system'
5639to be set up. */);
5640 5634
5641 DEFVAR_PER_BUFFER ("mode-name", &BVAR (current_buffer, mode_name), 5635 DEFVAR_PER_BUFFER ("mode-name", &BVAR (current_buffer, mode_name),
5642 Qnil, 5636 Qnil,
diff --git a/src/conf_post.h b/src/conf_post.h
index 98ff12e5a53..5c332a05a5c 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -51,10 +51,21 @@ typedef bool bool_bf;
51#endif 51#endif
52#endif 52#endif
53 53
54/* When not using Clang, assume its attributes and features are absent. */ 54/* Simulate __has_attribute on compilers that lack it. It is used only
55 on arguments like alloc_size that are handled in this simulation. */
55#ifndef __has_attribute 56#ifndef __has_attribute
56# define __has_attribute(a) false 57# define __has_attribute(a) __has_attribute_##a
57#endif 58# define __has_attribute_alloc_size (4 < __GNUC__ + (3 <= __GNUC_MINOR__))
59# define __has_attribute_cleanup (3 < __GNUC__ + (4 <= __GNUC_MINOR__))
60# define __has_attribute_externally_visible \
61 (4 < __GNUC__ + (1 <= __GNUC_MINOR__))
62# define __has_attribute_no_address_safety_analysis false
63# define __has_attribute_no_sanitize_address \
64 (4 < __GNUC__ + (8 <= __GNUC_MINOR__))
65#endif
66
67/* Simulate __has_feature on compilers that lack it. It is used only
68 to define ADDRESS_SANITIZER below. */
58#ifndef __has_feature 69#ifndef __has_feature
59# define __has_feature(a) false 70# define __has_feature(a) false
60#endif 71#endif
@@ -222,9 +233,7 @@ extern int emacs_setenv_TZ (char const *);
222#define NO_INLINE 233#define NO_INLINE
223#endif 234#endif
224 235
225#if (__clang__ \ 236#if __has_attribute (externally_visible)
226 ? __has_attribute (externally_visible) \
227 : (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)))
228#define EXTERNALLY_VISIBLE __attribute__((externally_visible)) 237#define EXTERNALLY_VISIBLE __attribute__((externally_visible))
229#else 238#else
230#define EXTERNALLY_VISIBLE 239#define EXTERNALLY_VISIBLE
@@ -253,9 +262,7 @@ extern int emacs_setenv_TZ (char const *);
253# define ATTRIBUTE_MALLOC 262# define ATTRIBUTE_MALLOC
254#endif 263#endif
255 264
256#if (__clang__ \ 265#if __has_attribute (alloc_size)
257 ? __has_attribute (alloc_size) \
258 : 4 < __GNUC__ + (3 <= __GNUC_MINOR__))
259# define ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args)) 266# define ATTRIBUTE_ALLOC_SIZE(args) __attribute__ ((__alloc_size__ args))
260#else 267#else
261# define ATTRIBUTE_ALLOC_SIZE(args) 268# define ATTRIBUTE_ALLOC_SIZE(args)
@@ -278,8 +285,7 @@ extern int emacs_setenv_TZ (char const *);
278/* Attribute of functions whose code should not have addresses 285/* Attribute of functions whose code should not have addresses
279 sanitized. */ 286 sanitized. */
280 287
281#if (__has_attribute (no_sanitize_address) \ 288#if __has_attribute (no_sanitize_address)
282 || 4 < __GNUC__ + (8 <= __GNUC_MINOR__))
283# define ATTRIBUTE_NO_SANITIZE_ADDRESS \ 289# define ATTRIBUTE_NO_SANITIZE_ADDRESS \
284 __attribute__ ((no_sanitize_address)) ADDRESS_SANITIZER_WORKAROUND 290 __attribute__ ((no_sanitize_address)) ADDRESS_SANITIZER_WORKAROUND
285#elif __has_attribute (no_address_safety_analysis) 291#elif __has_attribute (no_address_safety_analysis)
diff --git a/src/emacs-module.c b/src/emacs-module.c
index b5e044e758f..79a077b3cb4 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -35,8 +35,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
35 35
36/* Feature tests. */ 36/* Feature tests. */
37 37
38/* True if __attribute__ ((cleanup (...))) works, false otherwise. */ 38#if __has_attribute (cleanup)
39#ifdef HAVE_VAR_ATTRIBUTE_CLEANUP
40enum { module_has_cleanup = true }; 39enum { module_has_cleanup = true };
41#else 40#else
42enum { module_has_cleanup = false }; 41enum { module_has_cleanup = false };
diff --git a/src/fns.c b/src/fns.c
index 977229b97b7..86ad333702e 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -50,7 +50,8 @@ All integers representable in Lisp, i.e. between `most-negative-fixnum'
50and `most-positive-fixnum', inclusive, are equally likely. 50and `most-positive-fixnum', inclusive, are equally likely.
51 51
52With positive integer LIMIT, return random number in interval [0,LIMIT). 52With positive integer LIMIT, return random number in interval [0,LIMIT).
53With argument t, set the random number seed from the current time and pid. 53With argument t, set the random number seed from the system's entropy
54pool if available, otherwise from less-random volatile data such as the time.
54With a string argument, set the seed based on the string's contents. 55With a string argument, set the seed based on the string's contents.
55Other values of LIMIT are ignored. 56Other values of LIMIT are ignored.
56 57
diff --git a/src/gnutls.c b/src/gnutls.c
index a1d058fcd48..01a5983d3b0 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -1112,15 +1112,17 @@ The return value is a property list with top-level keys :warnings and
1112/* Initialize global GnuTLS state to defaults. 1112/* Initialize global GnuTLS state to defaults.
1113 Call `gnutls-global-deinit' when GnuTLS usage is no longer needed. 1113 Call `gnutls-global-deinit' when GnuTLS usage is no longer needed.
1114 Return zero on success. */ 1114 Return zero on success. */
1115static Lisp_Object 1115Lisp_Object
1116emacs_gnutls_global_init (void) 1116emacs_gnutls_global_init (void)
1117{ 1117{
1118 int ret = GNUTLS_E_SUCCESS; 1118 int ret = GNUTLS_E_SUCCESS;
1119 1119
1120 if (!gnutls_global_initialized) 1120 if (!gnutls_global_initialized)
1121 ret = gnutls_global_init (); 1121 {
1122 1122 ret = gnutls_global_init ();
1123 gnutls_global_initialized = 1; 1123 if (ret == GNUTLS_E_SUCCESS)
1124 gnutls_global_initialized = 1;
1125 }
1124 1126
1125 return gnutls_make_error (ret); 1127 return gnutls_make_error (ret);
1126} 1128}
diff --git a/src/gnutls.h b/src/gnutls.h
index c4fe738bfa0..8e879c168bd 100644
--- a/src/gnutls.h
+++ b/src/gnutls.h
@@ -83,6 +83,7 @@ extern ptrdiff_t emacs_gnutls_record_check_pending (gnutls_session_t state);
83extern void emacs_gnutls_transport_set_errno (gnutls_session_t state, int err); 83extern void emacs_gnutls_transport_set_errno (gnutls_session_t state, int err);
84#endif 84#endif
85extern Lisp_Object emacs_gnutls_deinit (Lisp_Object); 85extern Lisp_Object emacs_gnutls_deinit (Lisp_Object);
86extern Lisp_Object emacs_gnutls_global_init (void);
86 87
87#endif 88#endif
88 89
diff --git a/src/keyboard.c b/src/keyboard.c
index c3aa76af518..c8a9728e896 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -64,6 +64,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
64#include <unistd.h> 64#include <unistd.h>
65#include <fcntl.h> 65#include <fcntl.h>
66 66
67#include <ignore-value.h>
68
67#ifdef HAVE_WINDOW_SYSTEM 69#ifdef HAVE_WINDOW_SYSTEM
68#include TERM_HEADER 70#include TERM_HEADER
69#endif /* HAVE_WINDOW_SYSTEM */ 71#endif /* HAVE_WINDOW_SYSTEM */
@@ -1234,9 +1236,6 @@ static void adjust_point_for_property (ptrdiff_t, bool);
1234Lisp_Object 1236Lisp_Object
1235command_loop_1 (void) 1237command_loop_1 (void)
1236{ 1238{
1237 Lisp_Object cmd;
1238 Lisp_Object keybuf[30];
1239 int i;
1240 EMACS_INT prev_modiff = 0; 1239 EMACS_INT prev_modiff = 0;
1241 struct buffer *prev_buffer = NULL; 1240 struct buffer *prev_buffer = NULL;
1242 bool already_adjusted = 0; 1241 bool already_adjusted = 0;
@@ -1280,6 +1279,10 @@ command_loop_1 (void)
1280 1279
1281 while (1) 1280 while (1)
1282 { 1281 {
1282 Lisp_Object cmd;
1283 Lisp_Object keybuf[30];
1284 int i;
1285
1283 if (! FRAME_LIVE_P (XFRAME (selected_frame))) 1286 if (! FRAME_LIVE_P (XFRAME (selected_frame)))
1284 Fkill_emacs (Qnil); 1287 Fkill_emacs (Qnil);
1285 1288
@@ -10205,6 +10208,21 @@ deliver_interrupt_signal (int sig)
10205 deliver_process_signal (sig, handle_interrupt_signal); 10208 deliver_process_signal (sig, handle_interrupt_signal);
10206} 10209}
10207 10210
10211/* Output MSG directly to standard output, without buffering. Ignore
10212 failures. This is safe in a signal handler. */
10213static void
10214write_stdout (char const *msg)
10215{
10216 ignore_value (write (STDOUT_FILENO, msg, strlen (msg)));
10217}
10218
10219/* Read a byte from stdin, without buffering. Safe in signal handlers. */
10220static int
10221read_stdin (void)
10222{
10223 char c;
10224 return read (STDIN_FILENO, &c, 1) == 1 ? c : EOF;
10225}
10208 10226
10209/* If Emacs is stuck because `inhibit-quit' is true, then keep track 10227/* If Emacs is stuck because `inhibit-quit' is true, then keep track
10210 of the number of times C-g has been requested. If C-g is pressed 10228 of the number of times C-g has been requested. If C-g is pressed
@@ -10241,9 +10259,9 @@ handle_interrupt (bool in_signal_handler)
10241 sigemptyset (&blocked); 10259 sigemptyset (&blocked);
10242 sigaddset (&blocked, SIGINT); 10260 sigaddset (&blocked, SIGINT);
10243 pthread_sigmask (SIG_BLOCK, &blocked, 0); 10261 pthread_sigmask (SIG_BLOCK, &blocked, 0);
10262 fflush (stdout);
10244 } 10263 }
10245 10264
10246 fflush (stdout);
10247 reset_all_sys_modes (); 10265 reset_all_sys_modes ();
10248 10266
10249#ifdef SIGTSTP 10267#ifdef SIGTSTP
@@ -10259,8 +10277,9 @@ handle_interrupt (bool in_signal_handler)
10259 /* Perhaps should really fork an inferior shell? 10277 /* Perhaps should really fork an inferior shell?
10260 But that would not provide any way to get back 10278 But that would not provide any way to get back
10261 to the original shell, ever. */ 10279 to the original shell, ever. */
10262 printf ("No support for stopping a process on this operating system;\n"); 10280 write_stdout ("No support for stopping a process"
10263 printf ("you can continue or abort.\n"); 10281 " on this operating system;\n"
10282 "you can continue or abort.\n");
10264#endif /* not SIGTSTP */ 10283#endif /* not SIGTSTP */
10265#ifdef MSDOS 10284#ifdef MSDOS
10266 /* We must remain inside the screen area when the internal terminal 10285 /* We must remain inside the screen area when the internal terminal
@@ -10271,46 +10290,49 @@ handle_interrupt (bool in_signal_handler)
10271 the code used for auto-saving doesn't cope with the mark bit. */ 10290 the code used for auto-saving doesn't cope with the mark bit. */
10272 if (!gc_in_progress) 10291 if (!gc_in_progress)
10273 { 10292 {
10274 printf ("Auto-save? (y or n) "); 10293 write_stdout ("Auto-save? (y or n) ");
10275 fflush (stdout); 10294 c = read_stdin ();
10276 if (((c = getchar ()) & ~040) == 'Y') 10295 if ((c & 040) == 'Y')
10277 { 10296 {
10278 Fdo_auto_save (Qt, Qnil); 10297 Fdo_auto_save (Qt, Qnil);
10279#ifdef MSDOS 10298#ifdef MSDOS
10280 printf ("\r\nAuto-save done"); 10299 write_stdout ("\r\nAuto-save done");
10281#else /* not MSDOS */ 10300#else
10282 printf ("Auto-save done\n"); 10301 write_stdout ("Auto-save done\n");
10283#endif /* not MSDOS */ 10302#endif
10284 } 10303 }
10285 while (c != '\n') c = getchar (); 10304 while (c != '\n')
10305 c = read_stdin ();
10286 } 10306 }
10287 else 10307 else
10288 { 10308 {
10289 /* During GC, it must be safe to reenable quitting again. */ 10309 /* During GC, it must be safe to reenable quitting again. */
10290 Vinhibit_quit = Qnil; 10310 Vinhibit_quit = Qnil;
10311 write_stdout
10312 (
10291#ifdef MSDOS 10313#ifdef MSDOS
10292 printf ("\r\n"); 10314 "\r\n"
10293#endif /* not MSDOS */ 10315#endif
10294 printf ("Garbage collection in progress; cannot auto-save now\r\n"); 10316 "Garbage collection in progress; cannot auto-save now\r\n"
10295 printf ("but will instead do a real quit after garbage collection ends\r\n"); 10317 "but will instead do a real quit"
10296 fflush (stdout); 10318 " after garbage collection ends\r\n");
10297 } 10319 }
10298 10320
10299#ifdef MSDOS 10321#ifdef MSDOS
10300 printf ("\r\nAbort? (y or n) "); 10322 write_stdout ("\r\nAbort? (y or n) ");
10301#else /* not MSDOS */ 10323#else
10302 printf ("Abort (and dump core)? (y or n) "); 10324 write_stdout ("Abort (and dump core)? (y or n) ");
10303#endif /* not MSDOS */ 10325#endif
10304 fflush (stdout); 10326 c = read_stdin ();
10305 if (((c = getchar ()) & ~040) == 'Y') 10327 if ((c & ~040) == 'Y')
10306 emacs_abort (); 10328 emacs_abort ();
10307 while (c != '\n') c = getchar (); 10329 while (c != '\n')
10330 c = read_stdin ();
10308#ifdef MSDOS 10331#ifdef MSDOS
10309 printf ("\r\nContinuing...\r\n"); 10332 write_stdout ("\r\nContinuing...\r\n");
10310#else /* not MSDOS */ 10333#else /* not MSDOS */
10311 printf ("Continuing...\n"); 10334 write_stdout ("Continuing...\n");
10312#endif /* not MSDOS */ 10335#endif /* not MSDOS */
10313 fflush (stdout);
10314 init_all_sys_modes (); 10336 init_all_sys_modes ();
10315 } 10337 }
10316 else 10338 else
diff --git a/src/sysdep.c b/src/sysdep.c
index e73acec733e..a86b53642f2 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -99,6 +99,14 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
99#include "process.h" 99#include "process.h"
100#include "cm.h" 100#include "cm.h"
101 101
102#include "gnutls.h"
103#if 0x020c00 <= GNUTLS_VERSION_NUMBER && !defined WINDOWSNT
104# include <gnutls/crypto.h>
105#else
106# define emacs_gnutls_global_init() Qnil
107# define gnutls_rnd(level, data, len) (-1)
108#endif
109
102#ifdef WINDOWSNT 110#ifdef WINDOWSNT
103#include <direct.h> 111#include <direct.h>
104/* In process.h which conflicts with the local copy. */ 112/* In process.h which conflicts with the local copy. */
@@ -2071,36 +2079,56 @@ init_signals (bool dumping)
2071# endif /* !HAVE_RANDOM */ 2079# endif /* !HAVE_RANDOM */
2072#endif /* !RAND_BITS */ 2080#endif /* !RAND_BITS */
2073 2081
2082#ifdef HAVE_RANDOM
2083typedef unsigned int random_seed;
2084static void set_random_seed (random_seed arg) { srandom (arg); }
2085#elif defined HAVE_LRAND48
2086/* Although srand48 uses a long seed, this is unsigned long to avoid
2087 undefined behavior on signed integer overflow in init_random. */
2088typedef unsigned long int random_seed;
2089static void set_random_seed (random_seed arg) { srand48 (arg); }
2090#else
2091typedef unsigned int random_seed;
2092static void set_random_seed (random_seed arg) { srand (arg); }
2093#endif
2094
2074void 2095void
2075seed_random (void *seed, ptrdiff_t seed_size) 2096seed_random (void *seed, ptrdiff_t seed_size)
2076{ 2097{
2077#if defined HAVE_RANDOM || ! defined HAVE_LRAND48 2098 random_seed arg = 0;
2078 unsigned int arg = 0;
2079#else
2080 long int arg = 0;
2081#endif
2082 unsigned char *argp = (unsigned char *) &arg; 2099 unsigned char *argp = (unsigned char *) &arg;
2083 unsigned char *seedp = seed; 2100 unsigned char *seedp = seed;
2084 ptrdiff_t i; 2101 for (ptrdiff_t i = 0; i < seed_size; i++)
2085 for (i = 0; i < seed_size; i++)
2086 argp[i % sizeof arg] ^= seedp[i]; 2102 argp[i % sizeof arg] ^= seedp[i];
2087#ifdef HAVE_RANDOM 2103 set_random_seed (arg);
2088 srandom (arg);
2089#else
2090# ifdef HAVE_LRAND48
2091 srand48 (arg);
2092# else
2093 srand (arg);
2094# endif
2095#endif
2096} 2104}
2097 2105
2098void 2106void
2099init_random (void) 2107init_random (void)
2100{ 2108{
2101 struct timespec t = current_timespec (); 2109 random_seed v;
2102 uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec; 2110 if (! (EQ (emacs_gnutls_global_init (), Qt)
2103 seed_random (&v, sizeof v); 2111 && gnutls_rnd (GNUTLS_RND_NONCE, &v, sizeof v) == 0))
2112 {
2113 bool success = false;
2114#ifndef WINDOWSNT
2115 int fd = emacs_open ("/dev/urandom", O_RDONLY | O_BINARY, 0);
2116 if (0 <= fd)
2117 {
2118 success = emacs_read (fd, &v, sizeof v) == sizeof v;
2119 emacs_close (fd);
2120 }
2121#else
2122 success = w32_init_random (&v, sizeof v) == 0;
2123#endif
2124 if (! success)
2125 {
2126 /* Fall back to current time value + PID. */
2127 struct timespec t = current_timespec ();
2128 v = getpid () ^ t.tv_sec ^ t.tv_nsec;
2129 }
2130 }
2131 set_random_seed (v);
2104} 2132}
2105 2133
2106/* 2134/*
diff --git a/src/w32.c b/src/w32.c
index 4770718f5e3..183a4e7e9d9 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -484,6 +484,7 @@ typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
484 484
485int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int); 485int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
486int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL); 486int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
487DWORD multiByteToWideCharFlags;
487 488
488 /* ** A utility function ** */ 489 /* ** A utility function ** */
489static BOOL 490static BOOL
@@ -1550,8 +1551,8 @@ codepage_for_filenames (CPINFO *cp_info)
1550int 1551int
1551filename_to_utf16 (const char *fn_in, wchar_t *fn_out) 1552filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
1552{ 1553{
1553 int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1, 1554 int result = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, fn_in,
1554 fn_out, MAX_PATH); 1555 -1, fn_out, MAX_PATH);
1555 1556
1556 if (!result) 1557 if (!result)
1557 { 1558 {
@@ -1641,8 +1642,8 @@ filename_from_ansi (const char *fn_in, char *fn_out)
1641{ 1642{
1642 wchar_t fn_utf16[MAX_PATH]; 1643 wchar_t fn_utf16[MAX_PATH];
1643 int codepage = codepage_for_filenames (NULL); 1644 int codepage = codepage_for_filenames (NULL);
1644 int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1, 1645 int result = pMultiByteToWideChar (codepage, multiByteToWideCharFlags, fn_in,
1645 fn_utf16, MAX_PATH); 1646 -1, fn_utf16, MAX_PATH);
1646 1647
1647 if (!result) 1648 if (!result)
1648 { 1649 {
@@ -8043,14 +8044,19 @@ pipe2 (int * phandles, int pipe2_flags)
8043{ 8044{
8044 int rc; 8045 int rc;
8045 unsigned flags; 8046 unsigned flags;
8047 unsigned pipe_size = 0;
8046 8048
8047 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC)); 8049 eassert (pipe2_flags == (O_BINARY | O_CLOEXEC));
8048 8050
8051 /* Allow Lisp to override the default buffer size of the pipe. */
8052 if (w32_pipe_buffer_size > 0 && w32_pipe_buffer_size < UINT_MAX)
8053 pipe_size = w32_pipe_buffer_size;
8054
8049 /* make pipe handles non-inheritable; when we spawn a child, we 8055 /* make pipe handles non-inheritable; when we spawn a child, we
8050 replace the relevant handle with an inheritable one. Also put 8056 replace the relevant handle with an inheritable one. Also put
8051 pipes into binary mode; we will do text mode translation ourselves 8057 pipes into binary mode; we will do text mode translation ourselves
8052 if required. */ 8058 if required. */
8053 rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY); 8059 rc = _pipe (phandles, pipe_size, _O_NOINHERIT | _O_BINARY);
8054 8060
8055 if (rc == 0) 8061 if (rc == 0)
8056 { 8062 {
@@ -8632,15 +8638,35 @@ sys_write (int fd, const void * buffer, unsigned int count)
8632 http://thread.gmane.org/gmane.comp.version-control.git/145294 8638 http://thread.gmane.org/gmane.comp.version-control.git/145294
8633 in the git mailing list. */ 8639 in the git mailing list. */
8634 const unsigned char *p = buffer; 8640 const unsigned char *p = buffer;
8635 const unsigned chunk = 30 * 1024 * 1024; 8641 const bool is_pipe = (fd < MAXDESC
8642 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8643 == (FILE_PIPE | FILE_NDELAY)));
8644 /* Some programs, notably Node.js's node.exe, seem to never
8645 completely empty the pipe, so writing more than the size of
8646 the pipe's buffer always returns ENOSPC, and we loop forever
8647 between send_process and here. As a workaround, write no
8648 more than the pipe's buffer can hold. */
8649 DWORD pipe_buffer_size;
8650 if (is_pipe)
8651 {
8652 if (!GetNamedPipeInfo ((HANDLE)_get_osfhandle (fd),
8653 NULL, &pipe_buffer_size, NULL, NULL))
8654 {
8655 DebPrint (("GetNamedPipeInfo: error %u\n", GetLastError ()));
8656 pipe_buffer_size = 4096;
8657 }
8658 }
8659 const unsigned chunk = is_pipe ? pipe_buffer_size : 30 * 1024 * 1024;
8636 8660
8637 nchars = 0; 8661 nchars = 0;
8662 errno = 0;
8638 while (count > 0) 8663 while (count > 0)
8639 { 8664 {
8640 unsigned this_chunk = count < chunk ? count : chunk; 8665 unsigned this_chunk = count < chunk ? count : chunk;
8641 int n = _write (fd, p, this_chunk); 8666 int n = _write (fd, p, this_chunk);
8642 8667
8643 nchars += n; 8668 if (n > 0)
8669 nchars += n;
8644 if (n < 0) 8670 if (n < 0)
8645 { 8671 {
8646 /* When there's no buffer space in a pipe that is in the 8672 /* When there's no buffer space in a pipe that is in the
@@ -8654,12 +8680,10 @@ sys_write (int fd, const void * buffer, unsigned int count)
8654 avoiding deadlock whereby each side of the pipe is 8680 avoiding deadlock whereby each side of the pipe is
8655 blocked on write, waiting for the other party to read 8681 blocked on write, waiting for the other party to read
8656 its end of the pipe. */ 8682 its end of the pipe. */
8657 if (errno == ENOSPC 8683 if (errno == ENOSPC && is_pipe)
8658 && fd < MAXDESC
8659 && ((fd_info[fd].flags & (FILE_PIPE | FILE_NDELAY))
8660 == (FILE_PIPE | FILE_NDELAY)))
8661 errno = EAGAIN; 8684 errno = EAGAIN;
8662 nchars = n; 8685 if (nchars == 0)
8686 nchars = -1;
8663 break; 8687 break;
8664 } 8688 }
8665 else if (n < this_chunk) 8689 else if (n < this_chunk)
@@ -9081,14 +9105,14 @@ check_windows_init_file (void)
9081 "not unpacked properly.\nSee the README.W32 file in the " 9105 "not unpacked properly.\nSee the README.W32 file in the "
9082 "top-level Emacs directory for more information.", 9106 "top-level Emacs directory for more information.",
9083 init_file_name, load_path); 9107 init_file_name, load_path);
9084 needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, 9108 needed = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9085 -1, NULL, 0); 9109 buffer, -1, NULL, 0);
9086 if (needed > 0) 9110 if (needed > 0)
9087 { 9111 {
9088 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t)); 9112 wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
9089 9113
9090 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1, 9114 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags, buffer,
9091 msg_w, needed); 9115 -1, msg_w, needed);
9092 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, 9116 needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
9093 NULL, 0, NULL, NULL); 9117 NULL, 0, NULL, NULL);
9094 if (needed > 0) 9118 if (needed > 0)
@@ -9275,6 +9299,7 @@ maybe_load_unicows_dll (void)
9275 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar"); 9299 (MultiByteToWideChar_Proc)GetProcAddress (ret, "MultiByteToWideChar");
9276 pWideCharToMultiByte = 9300 pWideCharToMultiByte =
9277 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte"); 9301 (WideCharToMultiByte_Proc)GetProcAddress (ret, "WideCharToMultiByte");
9302 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9278 return ret; 9303 return ret;
9279 } 9304 }
9280 else 9305 else
@@ -9304,6 +9329,11 @@ maybe_load_unicows_dll (void)
9304 pointers; no need for the LoadLibrary dance. */ 9329 pointers; no need for the LoadLibrary dance. */
9305 pMultiByteToWideChar = MultiByteToWideChar; 9330 pMultiByteToWideChar = MultiByteToWideChar;
9306 pWideCharToMultiByte = WideCharToMultiByte; 9331 pWideCharToMultiByte = WideCharToMultiByte;
9332 /* On NT 4.0, though, MB_ERR_INVALID_CHARS is not supported. */
9333 if (w32_major_version < 5)
9334 multiByteToWideCharFlags = 0;
9335 else
9336 multiByteToWideCharFlags = MB_ERR_INVALID_CHARS;
9307 return LoadLibrary ("Gdi32.dll"); 9337 return LoadLibrary ("Gdi32.dll");
9308 } 9338 }
9309} 9339}
diff --git a/src/w32.h b/src/w32.h
index 501056d38c6..097241b1b8f 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -183,6 +183,7 @@ typedef int (WINAPI *MultiByteToWideChar_Proc)(UINT,DWORD,LPCSTR,int,LPWSTR,int)
183typedef int (WINAPI *WideCharToMultiByte_Proc)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL); 183typedef int (WINAPI *WideCharToMultiByte_Proc)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
184extern MultiByteToWideChar_Proc pMultiByteToWideChar; 184extern MultiByteToWideChar_Proc pMultiByteToWideChar;
185extern WideCharToMultiByte_Proc pWideCharToMultiByte; 185extern WideCharToMultiByte_Proc pWideCharToMultiByte;
186extern DWORD multiByteToWideCharFlags;
186 187
187extern void init_environment (char **); 188extern void init_environment (char **);
188extern void check_windows_init_file (void); 189extern void check_windows_init_file (void);
diff --git a/src/w32fns.c b/src/w32fns.c
index f3806a992a0..01f5d6f3ae0 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -6984,12 +6984,12 @@ value of DIR as in previous invocations; this is standard Windows behavior. */)
6984 if (errno == ENOENT && filename_buf_w[MAX_PATH - 1] != 0) 6984 if (errno == ENOENT && filename_buf_w[MAX_PATH - 1] != 0)
6985 report_file_error ("filename too long", default_filename); 6985 report_file_error ("filename too long", default_filename);
6986 } 6986 }
6987 len = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 6987 len = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
6988 SSDATA (prompt), -1, NULL, 0); 6988 SSDATA (prompt), -1, NULL, 0);
6989 if (len > 32768) 6989 if (len > 32768)
6990 len = 32768; 6990 len = 32768;
6991 prompt_w = alloca (len * sizeof (wchar_t)); 6991 prompt_w = alloca (len * sizeof (wchar_t));
6992 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 6992 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
6993 SSDATA (prompt), -1, prompt_w, len); 6993 SSDATA (prompt), -1, prompt_w, len);
6994 } 6994 }
6995 else 6995 else
@@ -7002,12 +7002,12 @@ value of DIR as in previous invocations; this is standard Windows behavior. */)
7002 if (errno == ENOENT && filename_buf_a[MAX_PATH - 1] != 0) 7002 if (errno == ENOENT && filename_buf_a[MAX_PATH - 1] != 0)
7003 report_file_error ("filename too long", default_filename); 7003 report_file_error ("filename too long", default_filename);
7004 } 7004 }
7005 len = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 7005 len = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
7006 SSDATA (prompt), -1, NULL, 0); 7006 SSDATA (prompt), -1, NULL, 0);
7007 if (len > 32768) 7007 if (len > 32768)
7008 len = 32768; 7008 len = 32768;
7009 prompt_w = alloca (len * sizeof (wchar_t)); 7009 prompt_w = alloca (len * sizeof (wchar_t));
7010 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 7010 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
7011 SSDATA (prompt), -1, prompt_w, len); 7011 SSDATA (prompt), -1, prompt_w, len);
7012 len = pWideCharToMultiByte (CP_ACP, 0, prompt_w, -1, NULL, 0, NULL, NULL); 7012 len = pWideCharToMultiByte (CP_ACP, 0, prompt_w, -1, NULL, 0, NULL, NULL);
7013 if (len > 32768) 7013 if (len > 32768)
@@ -7489,10 +7489,10 @@ a ShowWindow flag:
7489 current_dir = ENCODE_FILE (current_dir); 7489 current_dir = ENCODE_FILE (current_dir);
7490 /* Cannot use filename_to_utf16/ansi with DOCUMENT, since it could 7490 /* Cannot use filename_to_utf16/ansi with DOCUMENT, since it could
7491 be a URL that is not limited to MAX_PATH chararcters. */ 7491 be a URL that is not limited to MAX_PATH chararcters. */
7492 doclen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 7492 doclen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
7493 SSDATA (document), -1, NULL, 0); 7493 SSDATA (document), -1, NULL, 0);
7494 doc_w = xmalloc (doclen * sizeof (wchar_t)); 7494 doc_w = xmalloc (doclen * sizeof (wchar_t));
7495 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 7495 pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
7496 SSDATA (document), -1, doc_w, doclen); 7496 SSDATA (document), -1, doc_w, doclen);
7497 if (use_unicode) 7497 if (use_unicode)
7498 { 7498 {
@@ -7507,12 +7507,12 @@ a ShowWindow flag:
7507 int len; 7507 int len;
7508 7508
7509 parameters = ENCODE_SYSTEM (parameters); 7509 parameters = ENCODE_SYSTEM (parameters);
7510 len = pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS, 7510 len = pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags,
7511 SSDATA (parameters), -1, NULL, 0); 7511 SSDATA (parameters), -1, NULL, 0);
7512 if (len > 32768) 7512 if (len > 32768)
7513 len = 32768; 7513 len = 32768;
7514 params_w = alloca (len * sizeof (wchar_t)); 7514 params_w = alloca (len * sizeof (wchar_t));
7515 pMultiByteToWideChar (CP_ACP, MB_ERR_INVALID_CHARS, 7515 pMultiByteToWideChar (CP_ACP, multiByteToWideCharFlags,
7516 SSDATA (parameters), -1, params_w, len); 7516 SSDATA (parameters), -1, params_w, len);
7517 params_w[len - 1] = 0; 7517 params_w[len - 1] = 0;
7518 } 7518 }
@@ -8959,7 +8959,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
8959 later versions support up to 128. */ 8959 later versions support up to 128. */
8960 if (nidw.cbSize == MYNOTIFYICONDATAW_V1_SIZE) 8960 if (nidw.cbSize == MYNOTIFYICONDATAW_V1_SIZE)
8961 { 8961 {
8962 tiplen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 8962 tiplen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
8963 tip, utf8_mbslen_lim (tip, 63), 8963 tip, utf8_mbslen_lim (tip, 63),
8964 tipw, 64); 8964 tipw, 64);
8965 if (tiplen >= 63) 8965 if (tiplen >= 63)
@@ -8967,7 +8967,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
8967 } 8967 }
8968 else 8968 else
8969 { 8969 {
8970 tiplen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 8970 tiplen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
8971 tip, utf8_mbslen_lim (tip, 127), 8971 tip, utf8_mbslen_lim (tip, 127),
8972 tipw, 128); 8972 tipw, 128);
8973 if (tiplen >= 127) 8973 if (tiplen >= 127)
@@ -8986,7 +8986,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
8986 { 8986 {
8987 int slen; 8987 int slen;
8988 8988
8989 slen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 8989 slen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
8990 msg, utf8_mbslen_lim (msg, 255), 8990 msg, utf8_mbslen_lim (msg, 255),
8991 msgw, 256); 8991 msgw, 256);
8992 if (slen >= 255) 8992 if (slen >= 255)
@@ -8999,7 +8999,7 @@ add_tray_notification (struct frame *f, const char *icon, const char *tip,
8999 } 8999 }
9000 wcscpy (nidw.szInfo, msgw); 9000 wcscpy (nidw.szInfo, msgw);
9001 nidw.uTimeout = timeout; 9001 nidw.uTimeout = timeout;
9002 slen = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, 9002 slen = pMultiByteToWideChar (CP_UTF8, multiByteToWideCharFlags,
9003 title, utf8_mbslen_lim (title, 63), 9003 title, utf8_mbslen_lim (title, 63),
9004 titlew, 64); 9004 titlew, 64);
9005 if (slen >= 63) 9005 if (slen >= 63)
@@ -9670,6 +9670,12 @@ static PVOID except_addr;
9670 9670
9671/* Stack overflow recovery. */ 9671/* Stack overflow recovery. */
9672 9672
9673/* MinGW headers don't declare this (should be in malloc.h). Also,
9674 the function is not present pre-W2K, so make the call through
9675 a function pointer. */
9676typedef int (__cdecl *_resetstkoflw_proc) (void);
9677static _resetstkoflw_proc resetstkoflw;
9678
9673/* Re-establish the guard page at stack limit. This is needed because 9679/* Re-establish the guard page at stack limit. This is needed because
9674 when a stack overflow is detected, Windows removes the guard bit 9680 when a stack overflow is detected, Windows removes the guard bit
9675 from the guard page, so if we don't re-establish that protection, 9681 from the guard page, so if we don't re-establish that protection,
@@ -9677,12 +9683,14 @@ static PVOID except_addr;
9677void 9683void
9678w32_reset_stack_overflow_guard (void) 9684w32_reset_stack_overflow_guard (void)
9679{ 9685{
9680 /* MinGW headers don't declare this (should be in malloc.h). */ 9686 if (resetstkoflw == NULL)
9681 _CRTIMP int __cdecl _resetstkoflw (void); 9687 resetstkoflw =
9682 9688 (_resetstkoflw_proc)GetProcAddress (GetModuleHandle ("msvcrt.dll"),
9689 "_resetstkoflw");
9683 /* We ignore the return value. If _resetstkoflw fails, the next 9690 /* We ignore the return value. If _resetstkoflw fails, the next
9684 stack overflow will crash the program. */ 9691 stack overflow will crash the program. */
9685 (void)_resetstkoflw (); 9692 if (resetstkoflw != NULL)
9693 (void)resetstkoflw ();
9686} 9694}
9687 9695
9688static void 9696static void
@@ -9927,6 +9935,8 @@ globals_of_w32fns (void)
9927 9935
9928 after_deadkey = -1; 9936 after_deadkey = -1;
9929 9937
9938 resetstkoflw = NULL;
9939
9930 /* MessageBox does not work without this when linked to comctl32.dll 6.0. */ 9940 /* MessageBox does not work without this when linked to comctl32.dll 6.0. */
9931 InitCommonControls (); 9941 InitCommonControls ();
9932 9942
diff --git a/src/w32heap.c b/src/w32heap.c
index 54646bfbe3e..3d1c5ff50a2 100644
--- a/src/w32heap.c
+++ b/src/w32heap.c
@@ -258,9 +258,18 @@ init_heap (void)
258 } 258 }
259#endif 259#endif
260 260
261 the_malloc_fn = malloc_after_dump; 261 if (os_subtype == OS_9X)
262 the_realloc_fn = realloc_after_dump; 262 {
263 the_free_fn = free_after_dump; 263 the_malloc_fn = malloc_after_dump_9x;
264 the_realloc_fn = realloc_after_dump_9x;
265 the_free_fn = free_after_dump_9x;
266 }
267 else
268 {
269 the_malloc_fn = malloc_after_dump;
270 the_realloc_fn = realloc_after_dump;
271 the_free_fn = free_after_dump;
272 }
264 } 273 }
265 else 274 else
266 { 275 {
@@ -291,9 +300,18 @@ init_heap (void)
291 exit (-1); 300 exit (-1);
292 } 301 }
293 heap = s_pfn_Rtl_Create_Heap (0, data_region_base, 0, 0, NULL, &params); 302 heap = s_pfn_Rtl_Create_Heap (0, data_region_base, 0, 0, NULL, &params);
294 the_malloc_fn = malloc_before_dump; 303
295 the_realloc_fn = realloc_before_dump; 304 if (os_subtype == OS_9X)
296 the_free_fn = free_before_dump; 305 {
306 fprintf (stderr, "Cannot dump Emacs on Windows 9X; exiting.\n");
307 exit (-1);
308 }
309 else
310 {
311 the_malloc_fn = malloc_before_dump;
312 the_realloc_fn = realloc_before_dump;
313 the_free_fn = free_before_dump;
314 }
297 } 315 }
298 316
299 /* Update system version information to match current system. */ 317 /* Update system version information to match current system. */
@@ -504,6 +522,65 @@ free_before_dump (void *ptr)
504 } 522 }
505} 523}
506 524
525/* On Windows 9X, HeapAlloc may return pointers that are not aligned
526 on 8-byte boundary, alignment which is required by the Lisp memory
527 management. To circumvent this problem, manually enforce alignment
528 on Windows 9X. */
529
530void *
531malloc_after_dump_9x (size_t size)
532{
533 void *p = malloc_after_dump (size + 8);
534 void *pa;
535 if (p == NULL)
536 return p;
537 pa = (void*)(((intptr_t)p + 8) & ~7);
538 *((void**)pa-1) = p;
539 return pa;
540}
541
542void *
543realloc_after_dump_9x (void *ptr, size_t size)
544{
545 if (FREEABLE_P (ptr))
546 {
547 void *po = *((void**)ptr-1);
548 void *p;
549 void *pa;
550 p = realloc_after_dump (po, size + 8);
551 if (p == NULL)
552 return p;
553 pa = (void*)(((intptr_t)p + 8) & ~7);
554 if (ptr != NULL &&
555 (char*)pa - (char*)p != (char*)ptr - (char*)po)
556 {
557 /* Handle the case where alignment in pre-realloc and
558 post-realloc blocks does not match. */
559 MoveMemory (pa, (void*)((char*)p + ((char*)ptr - (char*)po)), size);
560 }
561 *((void**)pa-1) = p;
562 return pa;
563 }
564 else
565 {
566 /* Non-freeable pointers have no alignment-enforcing header
567 (since dumping is not allowed on Windows 9X). */
568 void* p = malloc_after_dump_9x (size);
569 if (p != NULL)
570 CopyMemory (p, ptr, size);
571 return p;
572 }
573}
574
575void
576free_after_dump_9x (void *ptr)
577{
578 if (FREEABLE_P (ptr))
579 {
580 free_after_dump (*((void**)ptr-1));
581 }
582}
583
507#ifdef ENABLE_CHECKING 584#ifdef ENABLE_CHECKING
508void 585void
509report_temacs_memory_usage (void) 586report_temacs_memory_usage (void)
diff --git a/src/w32proc.c b/src/w32proc.c
index a65f085fb3d..a89a9850466 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -3702,6 +3702,13 @@ of time slices to wait (effectively boosting the priority of the child
3702process temporarily). A value of zero disables waiting entirely. */); 3702process temporarily). A value of zero disables waiting entirely. */);
3703 w32_pipe_read_delay = 50; 3703 w32_pipe_read_delay = 50;
3704 3704
3705 DEFVAR_INT ("w32-pipe-buffer-size", w32_pipe_buffer_size,
3706 doc: /* Size of buffer for pipes created to communicate with subprocesses.
3707The size is in bytes, and must be non-negative. The default is zero,
3708which lets the OS use its default size, usually 4KB (4096 bytes).
3709Any negative value means to use the default value of zero. */);
3710 w32_pipe_buffer_size = 0;
3711
3705 DEFVAR_LISP ("w32-downcase-file-names", Vw32_downcase_file_names, 3712 DEFVAR_LISP ("w32-downcase-file-names", Vw32_downcase_file_names,
3706 doc: /* Non-nil means convert all-upper case file names to lower case. 3713 doc: /* Non-nil means convert all-upper case file names to lower case.
3707This applies when performing completions and file name expansion. 3714This applies when performing completions and file name expansion.
diff --git a/src/window.c b/src/window.c
index bb414e7d311..4aeb8b39a70 100644
--- a/src/window.c
+++ b/src/window.c
@@ -4979,27 +4979,34 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
4979 4979
4980 if (n > 0) 4980 if (n > 0)
4981 { 4981 {
4982 int last_y = it.last_visible_y - this_scroll_margin - 1;
4983
4982 /* We moved the window start towards ZV, so PT may be now 4984 /* We moved the window start towards ZV, so PT may be now
4983 in the scroll margin at the top. */ 4985 in the scroll margin at the top. */
4984 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS); 4986 move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
4985 if (IT_CHARPOS (it) == PT && it.current_y >= this_scroll_margin 4987 if (IT_CHARPOS (it) == PT
4988 && it.current_y >= this_scroll_margin
4989 && it.current_y <= last_y - WINDOW_HEADER_LINE_HEIGHT (w)
4986 && (NILP (Vscroll_preserve_screen_position) 4990 && (NILP (Vscroll_preserve_screen_position)
4987 || EQ (Vscroll_preserve_screen_position, Qt))) 4991 || EQ (Vscroll_preserve_screen_position, Qt)))
4988 /* We found PT at a legitimate height. Leave it alone. */ 4992 /* We found PT at a legitimate height. Leave it alone. */
4989 ; 4993 ;
4990 else if (window_scroll_pixel_based_preserve_y >= 0)
4991 {
4992 /* If we have a header line, take account of it.
4993 This is necessary because we set it.current_y to 0, above. */
4994 move_it_to (&it, -1,
4995 window_scroll_pixel_based_preserve_x,
4996 (window_scroll_pixel_based_preserve_y
4997 - WINDOW_WANTS_HEADER_LINE_P (w)),
4998 -1, MOVE_TO_Y | MOVE_TO_X);
4999 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5000 }
5001 else 4994 else
5002 { 4995 {
4996 if (window_scroll_pixel_based_preserve_y >= 0)
4997 {
4998 /* Don't enter the scroll margin at the end of the window. */
4999 int goal_y = min (last_y, window_scroll_pixel_based_preserve_y);
5000
5001 /* If we have a header line, take account of it. This
5002 is necessary because we set it.current_y to 0, above. */
5003 move_it_to (&it, -1,
5004 window_scroll_pixel_based_preserve_x,
5005 goal_y - WINDOW_HEADER_LINE_HEIGHT (w),
5006 -1, MOVE_TO_Y | MOVE_TO_X);
5007 }
5008
5009 /* Get out of the scroll margin at the top of the window. */
5003 while (it.current_y < this_scroll_margin) 5010 while (it.current_y < this_scroll_margin)
5004 { 5011 {
5005 int prev = it.current_y; 5012 int prev = it.current_y;
@@ -5023,7 +5030,7 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
5023 /* We moved the window start towards BEGV, so PT may be now 5030 /* We moved the window start towards BEGV, so PT may be now
5024 in the scroll margin at the bottom. */ 5031 in the scroll margin at the bottom. */
5025 move_it_to (&it, PT, -1, 5032 move_it_to (&it, PT, -1,
5026 (it.last_visible_y - CURRENT_HEADER_LINE_HEIGHT (w) 5033 (it.last_visible_y - WINDOW_HEADER_LINE_HEIGHT (w)
5027 - this_scroll_margin - 1), 5034 - this_scroll_margin - 1),
5028 -1, 5035 -1,
5029 MOVE_TO_POS | MOVE_TO_Y); 5036 MOVE_TO_POS | MOVE_TO_Y);
@@ -5074,14 +5081,20 @@ window_scroll_pixel_based (Lisp_Object window, int n, bool whole, bool noerror)
5074 ; 5081 ;
5075 else if (window_scroll_pixel_based_preserve_y >= 0) 5082 else if (window_scroll_pixel_based_preserve_y >= 0)
5076 { 5083 {
5084 int goal_y = min (it.last_visible_y - this_scroll_margin - 1,
5085 window_scroll_pixel_based_preserve_y);
5086
5087 /* Don't let the preserved screen Y coordinate put us inside
5088 any of the two margins. */
5089 if (goal_y < this_scroll_margin)
5090 goal_y = this_scroll_margin;
5077 SET_TEXT_POS_FROM_MARKER (start, w->start); 5091 SET_TEXT_POS_FROM_MARKER (start, w->start);
5078 start_display (&it, w, start); 5092 start_display (&it, w, start);
5079 /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT 5093 /* It would be wrong to subtract CURRENT_HEADER_LINE_HEIGHT
5080 here because we called start_display again and did not 5094 here because we called start_display again and did not
5081 alter it.current_y this time. */ 5095 alter it.current_y this time. */
5082 move_it_to (&it, -1, window_scroll_pixel_based_preserve_x, 5096 move_it_to (&it, -1, window_scroll_pixel_based_preserve_x,
5083 window_scroll_pixel_based_preserve_y, -1, 5097 goal_y, -1, MOVE_TO_Y | MOVE_TO_X);
5084 MOVE_TO_Y | MOVE_TO_X);
5085 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); 5098 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
5086 } 5099 }
5087 else 5100 else
@@ -5197,6 +5210,7 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror)
5197 w->force_start = true; 5210 w->force_start = true;
5198 5211
5199 if (!NILP (Vscroll_preserve_screen_position) 5212 if (!NILP (Vscroll_preserve_screen_position)
5213 && this_scroll_margin == 0
5200 && (whole || !EQ (Vscroll_preserve_screen_position, Qt))) 5214 && (whole || !EQ (Vscroll_preserve_screen_position, Qt)))
5201 { 5215 {
5202 SET_PT_BOTH (pos, pos_byte); 5216 SET_PT_BOTH (pos, pos_byte);
@@ -5222,8 +5236,16 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror)
5222 marker_byte_position (opoint_marker)); 5236 marker_byte_position (opoint_marker));
5223 else if (!NILP (Vscroll_preserve_screen_position)) 5237 else if (!NILP (Vscroll_preserve_screen_position))
5224 { 5238 {
5239 int nlines = window_scroll_preserve_vpos;
5240
5225 SET_PT_BOTH (pos, pos_byte); 5241 SET_PT_BOTH (pos, pos_byte);
5226 Fvertical_motion (original_pos, window, Qnil); 5242 if (window_scroll_preserve_vpos < this_scroll_margin)
5243 nlines = this_scroll_margin;
5244 else if (window_scroll_preserve_vpos
5245 >= w->total_lines - this_scroll_margin)
5246 nlines = w->total_lines - this_scroll_margin - 1;
5247 Fvertical_motion (Fcons (make_number (window_scroll_preserve_hpos),
5248 make_number (nlines)), window, Qnil);
5227 } 5249 }
5228 else 5250 else
5229 SET_PT (top_margin); 5251 SET_PT (top_margin);
@@ -5249,8 +5271,16 @@ window_scroll_line_based (Lisp_Object window, int n, bool whole, bool noerror)
5249 { 5271 {
5250 if (!NILP (Vscroll_preserve_screen_position)) 5272 if (!NILP (Vscroll_preserve_screen_position))
5251 { 5273 {
5274 int nlines = window_scroll_preserve_vpos;
5275
5252 SET_PT_BOTH (pos, pos_byte); 5276 SET_PT_BOTH (pos, pos_byte);
5253 Fvertical_motion (original_pos, window, Qnil); 5277 if (window_scroll_preserve_vpos < this_scroll_margin)
5278 nlines = this_scroll_margin;
5279 else if (window_scroll_preserve_vpos
5280 >= ht - this_scroll_margin)
5281 nlines = ht - this_scroll_margin - 1;
5282 Fvertical_motion (Fcons (make_number (window_scroll_preserve_hpos),
5283 make_number (nlines)), window, Qnil);
5254 } 5284 }
5255 else 5285 else
5256 Fvertical_motion (make_number (-1), window, Qnil); 5286 Fvertical_motion (make_number (-1), window, Qnil);