diff options
| author | Andrea Corallo | 2020-03-09 07:49:33 +0000 |
|---|---|---|
| committer | Andrea Corallo | 2020-03-09 07:49:33 +0000 |
| commit | 87ee6ff4eb6df369965f37fba073e3ef1bb5d0bd (patch) | |
| tree | 2af79516bca28e875879e01cb45b16fa4525a905 /src | |
| parent | 9838ee7ed870844470703b2648f8b59c0575bd46 (diff) | |
| parent | a461baae79af3cea8780e9d9a845a1e859e96e5e (diff) | |
| download | emacs-87ee6ff4eb6df369965f37fba073e3ef1bb5d0bd.tar.gz emacs-87ee6ff4eb6df369965f37fba073e3ef1bb5d0bd.zip | |
Merge remote-tracking branch 'savannah/master' into HEAD
Diffstat (limited to 'src')
| -rw-r--r-- | src/composite.c | 18 | ||||
| -rw-r--r-- | src/conf_post.h | 7 | ||||
| -rw-r--r-- | src/editfns.c | 19 | ||||
| -rw-r--r-- | src/emacs.c | 1 | ||||
| -rw-r--r-- | src/fileio.c | 53 | ||||
| -rw-r--r-- | src/font.c | 4 | ||||
| -rw-r--r-- | src/font.h | 2 | ||||
| -rw-r--r-- | src/fontset.c | 12 | ||||
| -rw-r--r-- | src/fringe.c | 7 | ||||
| -rw-r--r-- | src/gnutls.c | 19 | ||||
| -rw-r--r-- | src/intervals.c | 12 | ||||
| -rw-r--r-- | src/intervals.h | 24 | ||||
| -rw-r--r-- | src/nsterm.m | 11 | ||||
| -rw-r--r-- | src/pdumper.c | 9 | ||||
| -rw-r--r-- | src/process.c | 13 | ||||
| -rw-r--r-- | src/sysdep.c | 15 | ||||
| -rw-r--r-- | src/systime.h | 3 | ||||
| -rw-r--r-- | src/timefns.c | 83 | ||||
| -rw-r--r-- | src/w32.c | 106 | ||||
| -rw-r--r-- | src/w32term.c | 42 | ||||
| -rw-r--r-- | src/xdisp.c | 4 |
21 files changed, 303 insertions, 161 deletions
diff --git a/src/composite.c b/src/composite.c index 05365cfb65e..84de334ce0d 100644 --- a/src/composite.c +++ b/src/composite.c | |||
| @@ -818,6 +818,11 @@ fill_gstring_body (Lisp_Object gstring) | |||
| 818 | Lisp_Object header = AREF (gstring, 0); | 818 | Lisp_Object header = AREF (gstring, 0); |
| 819 | ptrdiff_t len = LGSTRING_CHAR_LEN (gstring); | 819 | ptrdiff_t len = LGSTRING_CHAR_LEN (gstring); |
| 820 | ptrdiff_t i; | 820 | ptrdiff_t i; |
| 821 | struct font *font = NULL; | ||
| 822 | unsigned int code; | ||
| 823 | |||
| 824 | if (FONT_OBJECT_P (font_object)) | ||
| 825 | font = XFONT_OBJECT (font_object); | ||
| 821 | 826 | ||
| 822 | for (i = 0; i < len; i++) | 827 | for (i = 0; i < len; i++) |
| 823 | { | 828 | { |
| @@ -832,10 +837,15 @@ fill_gstring_body (Lisp_Object gstring) | |||
| 832 | LGLYPH_SET_FROM (g, i); | 837 | LGLYPH_SET_FROM (g, i); |
| 833 | LGLYPH_SET_TO (g, i); | 838 | LGLYPH_SET_TO (g, i); |
| 834 | LGLYPH_SET_CHAR (g, c); | 839 | LGLYPH_SET_CHAR (g, c); |
| 835 | if (FONT_OBJECT_P (font_object)) | 840 | |
| 836 | { | 841 | if (font != NULL) |
| 837 | font_fill_lglyph_metrics (g, font_object); | 842 | code = font->driver->encode_char (font, LGLYPH_CHAR (g)); |
| 838 | } | 843 | else |
| 844 | code = FONT_INVALID_CODE; | ||
| 845 | if (code != FONT_INVALID_CODE) | ||
| 846 | { | ||
| 847 | font_fill_lglyph_metrics (g, font, code); | ||
| 848 | } | ||
| 839 | else | 849 | else |
| 840 | { | 850 | { |
| 841 | int width = XFIXNAT (CHAR_TABLE_REF (Vchar_width_table, c)); | 851 | int width = XFIXNAT (CHAR_TABLE_REF (Vchar_width_table, c)); |
diff --git a/src/conf_post.h b/src/conf_post.h index 2f8d19fdca8..eb8fb18c00c 100644 --- a/src/conf_post.h +++ b/src/conf_post.h | |||
| @@ -78,6 +78,7 @@ typedef bool bool_bf; | |||
| 78 | # define __has_attribute_no_address_safety_analysis false | 78 | # define __has_attribute_no_address_safety_analysis false |
| 79 | # define __has_attribute_no_sanitize_address GNUC_PREREQ (4, 8, 0) | 79 | # define __has_attribute_no_sanitize_address GNUC_PREREQ (4, 8, 0) |
| 80 | # define __has_attribute_no_sanitize_undefined GNUC_PREREQ (4, 9, 0) | 80 | # define __has_attribute_no_sanitize_undefined GNUC_PREREQ (4, 9, 0) |
| 81 | # define __has_attribute_returns_nonnull GNUC_PREREQ (4, 9, 0) | ||
| 81 | # define __has_attribute_warn_unused_result GNUC_PREREQ (3, 4, 0) | 82 | # define __has_attribute_warn_unused_result GNUC_PREREQ (3, 4, 0) |
| 82 | #endif | 83 | #endif |
| 83 | 84 | ||
| @@ -321,6 +322,12 @@ extern int emacs_setenv_TZ (char const *); | |||
| 321 | 322 | ||
| 322 | #define ATTRIBUTE_MALLOC_SIZE(args) ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE (args) | 323 | #define ATTRIBUTE_MALLOC_SIZE(args) ATTRIBUTE_MALLOC ATTRIBUTE_ALLOC_SIZE (args) |
| 323 | 324 | ||
| 325 | #if __has_attribute (returns_nonnull) | ||
| 326 | # define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((returns_nonnull)) | ||
| 327 | #else | ||
| 328 | # define ATTRIBUTE_RETURNS_NONNULL | ||
| 329 | #endif | ||
| 330 | |||
| 324 | /* Work around GCC bug 59600: when a function is inlined, the inlined | 331 | /* Work around GCC bug 59600: when a function is inlined, the inlined |
| 325 | code may have its addresses sanitized even if the function has the | 332 | code may have its addresses sanitized even if the function has the |
| 326 | no_sanitize_address attribute. This bug is fixed in GCC 4.9.0 and | 333 | no_sanitize_address attribute. This bug is fixed in GCC 4.9.0 and |
diff --git a/src/editfns.c b/src/editfns.c index ddf190b1752..eb15566fb48 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -1262,14 +1262,17 @@ name, or nil if there is no such user. */) | |||
| 1262 | if (q) | 1262 | if (q) |
| 1263 | { | 1263 | { |
| 1264 | Lisp_Object login = Fuser_login_name (INT_TO_INTEGER (pw->pw_uid)); | 1264 | Lisp_Object login = Fuser_login_name (INT_TO_INTEGER (pw->pw_uid)); |
| 1265 | USE_SAFE_ALLOCA; | 1265 | if (!NILP (login)) |
| 1266 | char *r = SAFE_ALLOCA (strlen (p) + SBYTES (login) + 1); | 1266 | { |
| 1267 | memcpy (r, p, q - p); | 1267 | USE_SAFE_ALLOCA; |
| 1268 | char *s = lispstpcpy (&r[q - p], login); | 1268 | char *r = SAFE_ALLOCA (strlen (p) + SBYTES (login) + 1); |
| 1269 | r[q - p] = upcase ((unsigned char) r[q - p]); | 1269 | memcpy (r, p, q - p); |
| 1270 | strcpy (s, q + 1); | 1270 | char *s = lispstpcpy (&r[q - p], login); |
| 1271 | full = build_string (r); | 1271 | r[q - p] = upcase ((unsigned char) r[q - p]); |
| 1272 | SAFE_FREE (); | 1272 | strcpy (s, q + 1); |
| 1273 | full = build_string (r); | ||
| 1274 | SAFE_FREE (); | ||
| 1275 | } | ||
| 1273 | } | 1276 | } |
| 1274 | #endif /* AMPERSAND_FULL_NAME */ | 1277 | #endif /* AMPERSAND_FULL_NAME */ |
| 1275 | 1278 | ||
diff --git a/src/emacs.c b/src/emacs.c index ce1c9edc2dc..fcc02a3a874 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -1974,7 +1974,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1974 | /* This calls putenv and so must precede init_process_emacs. */ | 1974 | /* This calls putenv and so must precede init_process_emacs. */ |
| 1975 | init_timefns (); | 1975 | init_timefns (); |
| 1976 | 1976 | ||
| 1977 | /* This sets Voperating_system_release, which init_process_emacs uses. */ | ||
| 1978 | init_editfns (); | 1977 | init_editfns (); |
| 1979 | 1978 | ||
| 1980 | /* These two call putenv. */ | 1979 | /* These two call putenv. */ |
diff --git a/src/fileio.c b/src/fileio.c index 2532f5233c4..ffe79559a3f 100644 --- a/src/fileio.c +++ b/src/fileio.c | |||
| @@ -2077,7 +2077,7 @@ permissions. */) | |||
| 2077 | report_file_error ("Copying permissions from", file); | 2077 | report_file_error ("Copying permissions from", file); |
| 2078 | case -3: | 2078 | case -3: |
| 2079 | xsignal2 (Qfile_date_error, | 2079 | xsignal2 (Qfile_date_error, |
| 2080 | build_string ("Resetting file times"), newname); | 2080 | build_string ("Cannot set file date"), newname); |
| 2081 | case -4: | 2081 | case -4: |
| 2082 | report_file_error ("Copying permissions to", newname); | 2082 | report_file_error ("Copying permissions to", newname); |
| 2083 | } | 2083 | } |
| @@ -2253,9 +2253,8 @@ permissions. */) | |||
| 2253 | 2253 | ||
| 2254 | if (!NILP (keep_time)) | 2254 | if (!NILP (keep_time)) |
| 2255 | { | 2255 | { |
| 2256 | struct timespec atime = get_stat_atime (&st); | 2256 | struct timespec ts[] = { get_stat_atime (&st), get_stat_mtime (&st) }; |
| 2257 | struct timespec mtime = get_stat_mtime (&st); | 2257 | if (futimens (ofd, ts) != 0) |
| 2258 | if (set_file_times (ofd, SSDATA (encoded_newname), atime, mtime) != 0) | ||
| 2259 | xsignal2 (Qfile_date_error, | 2258 | xsignal2 (Qfile_date_error, |
| 2260 | build_string ("Cannot set file date"), newname); | 2259 | build_string ("Cannot set file date"), newname); |
| 2261 | } | 2260 | } |
| @@ -3430,39 +3429,41 @@ The value is an integer. */) | |||
| 3430 | } | 3429 | } |
| 3431 | 3430 | ||
| 3432 | 3431 | ||
| 3433 | DEFUN ("set-file-times", Fset_file_times, Sset_file_times, 1, 2, 0, | 3432 | DEFUN ("set-file-times", Fset_file_times, Sset_file_times, 1, 3, 0, |
| 3434 | doc: /* Set times of file FILENAME to TIMESTAMP. | 3433 | doc: /* Set times of file FILENAME to TIMESTAMP. |
| 3435 | Set both access and modification times. | 3434 | If optional FLAG is `nofollow', do not follow FILENAME if it is a |
| 3436 | Return t on success, else nil. | 3435 | symbolic link. Set both access and modification times. Return t on |
| 3437 | Use the current time if TIMESTAMP is nil. TIMESTAMP is in the format of | 3436 | success, else nil. Use the current time if TIMESTAMP is nil. |
| 3438 | `current-time'. */) | 3437 | TIMESTAMP is in the format of `current-time'. */) |
| 3439 | (Lisp_Object filename, Lisp_Object timestamp) | 3438 | (Lisp_Object filename, Lisp_Object timestamp, Lisp_Object flag) |
| 3440 | { | 3439 | { |
| 3441 | Lisp_Object absname, encoded_absname; | 3440 | int nofollow = symlink_nofollow_flag (flag); |
| 3442 | Lisp_Object handler; | ||
| 3443 | struct timespec t = lisp_time_argument (timestamp); | ||
| 3444 | 3441 | ||
| 3445 | absname = Fexpand_file_name (filename, BVAR (current_buffer, directory)); | 3442 | struct timespec ts[2]; |
| 3443 | if (!NILP (timestamp)) | ||
| 3444 | ts[0] = ts[1] = lisp_time_argument (timestamp); | ||
| 3445 | else | ||
| 3446 | ts[0].tv_nsec = ts[1].tv_nsec = UTIME_NOW; | ||
| 3446 | 3447 | ||
| 3447 | /* If the file name has special constructs in it, | 3448 | /* If the file name has special constructs in it, |
| 3448 | call the corresponding file name handler. */ | 3449 | call the corresponding file name handler. */ |
| 3449 | handler = Ffind_file_name_handler (absname, Qset_file_times); | 3450 | Lisp_Object |
| 3451 | absname = Fexpand_file_name (filename, BVAR (current_buffer, directory)), | ||
| 3452 | handler = Ffind_file_name_handler (absname, Qset_file_times); | ||
| 3450 | if (!NILP (handler)) | 3453 | if (!NILP (handler)) |
| 3451 | return call3 (handler, Qset_file_times, absname, timestamp); | 3454 | return call4 (handler, Qset_file_times, absname, timestamp, flag); |
| 3452 | 3455 | ||
| 3453 | encoded_absname = ENCODE_FILE (absname); | 3456 | Lisp_Object encoded_absname = ENCODE_FILE (absname); |
| 3454 | 3457 | ||
| 3455 | { | 3458 | if (utimensat (AT_FDCWD, SSDATA (encoded_absname), ts, nofollow) != 0) |
| 3456 | if (set_file_times (-1, SSDATA (encoded_absname), t, t) != 0) | 3459 | { |
| 3457 | { | ||
| 3458 | #ifdef MSDOS | 3460 | #ifdef MSDOS |
| 3459 | /* Setting times on a directory always fails. */ | 3461 | /* Setting times on a directory always fails. */ |
| 3460 | if (file_directory_p (encoded_absname)) | 3462 | if (file_directory_p (encoded_absname)) |
| 3461 | return Qnil; | 3463 | return Qnil; |
| 3462 | #endif | 3464 | #endif |
| 3463 | report_file_error ("Setting file times", absname); | 3465 | report_file_error ("Setting file times", absname); |
| 3464 | } | 3466 | } |
| 3465 | } | ||
| 3466 | 3467 | ||
| 3467 | return Qt; | 3468 | return Qt; |
| 3468 | } | 3469 | } |
diff --git a/src/font.c b/src/font.c index bb39aef92d5..2a456300619 100644 --- a/src/font.c +++ b/src/font.c | |||
| @@ -4416,10 +4416,8 @@ DEFUN ("clear-font-cache", Fclear_font_cache, Sclear_font_cache, 0, 0, 0, | |||
| 4416 | 4416 | ||
| 4417 | 4417 | ||
| 4418 | void | 4418 | void |
| 4419 | font_fill_lglyph_metrics (Lisp_Object glyph, Lisp_Object font_object) | 4419 | font_fill_lglyph_metrics (Lisp_Object glyph, struct font *font, unsigned int code) |
| 4420 | { | 4420 | { |
| 4421 | struct font *font = XFONT_OBJECT (font_object); | ||
| 4422 | unsigned code = font->driver->encode_char (font, LGLYPH_CHAR (glyph)); | ||
| 4423 | struct font_metrics metrics; | 4421 | struct font_metrics metrics; |
| 4424 | 4422 | ||
| 4425 | LGLYPH_SET_CODE (glyph, code); | 4423 | LGLYPH_SET_CODE (glyph, code); |
diff --git a/src/font.h b/src/font.h index 0561e3c83f5..8614e7fa10a 100644 --- a/src/font.h +++ b/src/font.h | |||
| @@ -886,7 +886,7 @@ extern Lisp_Object font_update_drivers (struct frame *f, Lisp_Object list); | |||
| 886 | extern Lisp_Object font_range (ptrdiff_t, ptrdiff_t, ptrdiff_t *, | 886 | extern Lisp_Object font_range (ptrdiff_t, ptrdiff_t, ptrdiff_t *, |
| 887 | struct window *, struct face *, | 887 | struct window *, struct face *, |
| 888 | Lisp_Object); | 888 | Lisp_Object); |
| 889 | extern void font_fill_lglyph_metrics (Lisp_Object, Lisp_Object); | 889 | extern void font_fill_lglyph_metrics (Lisp_Object, struct font *, unsigned int); |
| 890 | 890 | ||
| 891 | extern Lisp_Object font_put_extra (Lisp_Object font, Lisp_Object prop, | 891 | extern Lisp_Object font_put_extra (Lisp_Object font, Lisp_Object prop, |
| 892 | Lisp_Object val); | 892 | Lisp_Object val); |
diff --git a/src/fontset.c b/src/fontset.c index bca9452418e..c2bb8b21f26 100644 --- a/src/fontset.c +++ b/src/fontset.c | |||
| @@ -367,8 +367,14 @@ fontset_add (Lisp_Object fontset, Lisp_Object range, Lisp_Object elt, Lisp_Objec | |||
| 367 | static int | 367 | static int |
| 368 | fontset_compare_rfontdef (const void *val1, const void *val2) | 368 | fontset_compare_rfontdef (const void *val1, const void *val2) |
| 369 | { | 369 | { |
| 370 | return (RFONT_DEF_SCORE (*(Lisp_Object *) val1) | 370 | Lisp_Object v1 = *(Lisp_Object *) val1, v2 = *(Lisp_Object *) val2; |
| 371 | - RFONT_DEF_SCORE (*(Lisp_Object *) val2)); | 371 | if (NILP (v1) && NILP (v2)) |
| 372 | return 0; | ||
| 373 | else if (NILP (v1)) | ||
| 374 | return INT_MIN; | ||
| 375 | else if (NILP (v2)) | ||
| 376 | return INT_MAX; | ||
| 377 | return (RFONT_DEF_SCORE (v1) - RFONT_DEF_SCORE (v2)); | ||
| 372 | } | 378 | } |
| 373 | 379 | ||
| 374 | /* Update a cons cell which has this form: | 380 | /* Update a cons cell which has this form: |
| @@ -400,6 +406,8 @@ reorder_font_vector (Lisp_Object font_group, struct font *font) | |||
| 400 | for (i = 0; i < size; i++) | 406 | for (i = 0; i < size; i++) |
| 401 | { | 407 | { |
| 402 | Lisp_Object rfont_def = AREF (vec, i); | 408 | Lisp_Object rfont_def = AREF (vec, i); |
| 409 | if (NILP (rfont_def)) | ||
| 410 | continue; | ||
| 403 | Lisp_Object font_def = RFONT_DEF_FONT_DEF (rfont_def); | 411 | Lisp_Object font_def = RFONT_DEF_FONT_DEF (rfont_def); |
| 404 | Lisp_Object font_spec = FONT_DEF_SPEC (font_def); | 412 | Lisp_Object font_spec = FONT_DEF_SPEC (font_def); |
| 405 | int score = RFONT_DEF_SCORE (rfont_def) & 0xFF; | 413 | int score = RFONT_DEF_SCORE (rfont_def) & 0xFF; |
diff --git a/src/fringe.c b/src/fringe.c index 97aad843c2e..2a46e3c34f2 100644 --- a/src/fringe.c +++ b/src/fringe.c | |||
| @@ -1500,7 +1500,8 @@ DEFUN ("define-fringe-bitmap", Fdefine_fringe_bitmap, Sdefine_fringe_bitmap, | |||
| 1500 | BITMAP is a symbol identifying the new fringe bitmap. | 1500 | BITMAP is a symbol identifying the new fringe bitmap. |
| 1501 | BITS is either a string or a vector of integers. | 1501 | BITS is either a string or a vector of integers. |
| 1502 | HEIGHT is height of bitmap. If HEIGHT is nil, use length of BITS. | 1502 | HEIGHT is height of bitmap. If HEIGHT is nil, use length of BITS. |
| 1503 | WIDTH must be an integer between 1 and 16, or nil which defaults to 8. | 1503 | WIDTH must be an integer from 1 to 16, or nil which defaults to 8. An |
| 1504 | error is signaled if WIDTH is outside this range. | ||
| 1504 | Optional fifth arg ALIGN may be one of `top', `center', or `bottom', | 1505 | Optional fifth arg ALIGN may be one of `top', `center', or `bottom', |
| 1505 | indicating the positioning of the bitmap relative to the rows where it | 1506 | indicating the positioning of the bitmap relative to the rows where it |
| 1506 | is used; the default is to center the bitmap. Fifth arg may also be a | 1507 | is used; the default is to center the bitmap. Fifth arg may also be a |
| @@ -1535,7 +1536,9 @@ If BITMAP already exists, the existing definition is replaced. */) | |||
| 1535 | else | 1536 | else |
| 1536 | { | 1537 | { |
| 1537 | CHECK_FIXNUM (width); | 1538 | CHECK_FIXNUM (width); |
| 1538 | fb.width = max (0, min (XFIXNUM (width), 255)); | 1539 | fb.width = max (1, min (XFIXNUM (width), 16)); |
| 1540 | if (fb.width != XFIXNUM (width)) | ||
| 1541 | args_out_of_range (width, build_string ("Width must be from 1 to 16")); | ||
| 1539 | } | 1542 | } |
| 1540 | 1543 | ||
| 1541 | fb.period = 0; | 1544 | fb.period = 0; |
diff --git a/src/gnutls.c b/src/gnutls.c index 31fcd37c0a6..70176c41cdd 100644 --- a/src/gnutls.c +++ b/src/gnutls.c | |||
| @@ -2834,16 +2834,21 @@ Any GnuTLS extension with ID up to 100 | |||
| 2834 | void | 2834 | void |
| 2835 | syms_of_gnutls (void) | 2835 | syms_of_gnutls (void) |
| 2836 | { | 2836 | { |
| 2837 | DEFSYM (Qlibgnutls_version, "libgnutls-version"); | 2837 | DEFVAR_LISP ("libgnutls-version", Vlibgnutls_version, |
| 2838 | Fset (Qlibgnutls_version, | 2838 | doc: /* The version of libgnutls that Emacs was compiled with. |
| 2839 | The version number is encoded as an integer with the major version in | ||
| 2840 | the ten thousands place, minor version in the hundreds, and patch | ||
| 2841 | level in the ones. For builds without libgnutls, the value is -1. */); | ||
| 2842 | Vlibgnutls_version = make_fixnum | ||
| 2839 | #ifdef HAVE_GNUTLS | 2843 | #ifdef HAVE_GNUTLS |
| 2840 | make_fixnum (GNUTLS_VERSION_MAJOR * 10000 | 2844 | (GNUTLS_VERSION_MAJOR * 10000 |
| 2841 | + GNUTLS_VERSION_MINOR * 100 | 2845 | + GNUTLS_VERSION_MINOR * 100 |
| 2842 | + GNUTLS_VERSION_PATCH) | 2846 | + GNUTLS_VERSION_PATCH) |
| 2843 | #else | 2847 | #else |
| 2844 | make_fixnum (-1) | 2848 | (-1) |
| 2845 | #endif | 2849 | #endif |
| 2846 | ); | 2850 | ; |
| 2851 | |||
| 2847 | #ifdef HAVE_GNUTLS | 2852 | #ifdef HAVE_GNUTLS |
| 2848 | gnutls_global_initialized = 0; | 2853 | gnutls_global_initialized = 0; |
| 2849 | PDUMPER_IGNORE (gnutls_global_initialized); | 2854 | PDUMPER_IGNORE (gnutls_global_initialized); |
diff --git a/src/intervals.c b/src/intervals.c index a66594ceea2..594d8924ebc 100644 --- a/src/intervals.c +++ b/src/intervals.c | |||
| @@ -298,7 +298,7 @@ rotate_right (INTERVAL A) | |||
| 298 | set_interval_parent (c, A); | 298 | set_interval_parent (c, A); |
| 299 | 299 | ||
| 300 | /* A's total length is decreased by the length of B and its left child. */ | 300 | /* A's total length is decreased by the length of B and its left child. */ |
| 301 | A->total_length -= B->total_length - TOTAL_LENGTH (c); | 301 | A->total_length -= TOTAL_LENGTH (B) - TOTAL_LENGTH0 (c); |
| 302 | eassert (TOTAL_LENGTH (A) > 0); | 302 | eassert (TOTAL_LENGTH (A) > 0); |
| 303 | eassert (LENGTH (A) > 0); | 303 | eassert (LENGTH (A) > 0); |
| 304 | 304 | ||
| @@ -349,7 +349,7 @@ rotate_left (INTERVAL A) | |||
| 349 | set_interval_parent (c, A); | 349 | set_interval_parent (c, A); |
| 350 | 350 | ||
| 351 | /* A's total length is decreased by the length of B and its right child. */ | 351 | /* A's total length is decreased by the length of B and its right child. */ |
| 352 | A->total_length -= B->total_length - TOTAL_LENGTH (c); | 352 | A->total_length -= TOTAL_LENGTH (B) - TOTAL_LENGTH0 (c); |
| 353 | eassert (TOTAL_LENGTH (A) > 0); | 353 | eassert (TOTAL_LENGTH (A) > 0); |
| 354 | eassert (LENGTH (A) > 0); | 354 | eassert (LENGTH (A) > 0); |
| 355 | 355 | ||
| @@ -723,13 +723,13 @@ previous_interval (register INTERVAL interval) | |||
| 723 | i->position - LEFT_TOTAL_LENGTH (i) \ | 723 | i->position - LEFT_TOTAL_LENGTH (i) \ |
| 724 | - LENGTH (INTERVAL_PARENT (i)) | 724 | - LENGTH (INTERVAL_PARENT (i)) |
| 725 | 725 | ||
| 726 | /* Find the interval containing POS, given some non-NULL INTERVAL in | 726 | /* Find the interval containing POS, given some interval I in |
| 727 | the same tree. Note that we update interval->position in each | 727 | the same tree. Note that we update interval->position in each |
| 728 | interval we traverse, assuming it is already correctly set for the | 728 | interval we traverse, assuming it is already correctly set for the |
| 729 | argument I. We don't assume that any other interval already has a | 729 | argument I. We don't assume that any other interval already has a |
| 730 | correctly set ->position. */ | 730 | correctly set ->position. */ |
| 731 | INTERVAL | 731 | INTERVAL |
| 732 | update_interval (register INTERVAL i, ptrdiff_t pos) | 732 | update_interval (INTERVAL i, ptrdiff_t pos) |
| 733 | { | 733 | { |
| 734 | if (!i) | 734 | if (!i) |
| 735 | return NULL; | 735 | return NULL; |
| @@ -739,7 +739,7 @@ update_interval (register INTERVAL i, ptrdiff_t pos) | |||
| 739 | if (pos < i->position) | 739 | if (pos < i->position) |
| 740 | { | 740 | { |
| 741 | /* Move left. */ | 741 | /* Move left. */ |
| 742 | if (pos >= i->position - TOTAL_LENGTH (i->left)) | 742 | if (pos >= i->position - LEFT_TOTAL_LENGTH (i)) |
| 743 | { | 743 | { |
| 744 | i->left->position = i->position - TOTAL_LENGTH (i->left) | 744 | i->left->position = i->position - TOTAL_LENGTH (i->left) |
| 745 | + LEFT_TOTAL_LENGTH (i->left); | 745 | + LEFT_TOTAL_LENGTH (i->left); |
| @@ -757,7 +757,7 @@ update_interval (register INTERVAL i, ptrdiff_t pos) | |||
| 757 | else if (pos >= INTERVAL_LAST_POS (i)) | 757 | else if (pos >= INTERVAL_LAST_POS (i)) |
| 758 | { | 758 | { |
| 759 | /* Move right. */ | 759 | /* Move right. */ |
| 760 | if (pos < INTERVAL_LAST_POS (i) + TOTAL_LENGTH (i->right)) | 760 | if (pos < INTERVAL_LAST_POS (i) + RIGHT_TOTAL_LENGTH (i)) |
| 761 | { | 761 | { |
| 762 | i->right->position = INTERVAL_LAST_POS (i) | 762 | i->right->position = INTERVAL_LAST_POS (i) |
| 763 | + LEFT_TOTAL_LENGTH (i->right); | 763 | + LEFT_TOTAL_LENGTH (i->right); |
diff --git a/src/intervals.h b/src/intervals.h index a93b10e9fff..9a7ba910a10 100644 --- a/src/intervals.h +++ b/src/intervals.h | |||
| @@ -96,24 +96,27 @@ struct interval | |||
| 96 | /* True if this interval has both left and right children. */ | 96 | /* True if this interval has both left and right children. */ |
| 97 | #define BOTH_KIDS_P(i) ((i)->left != NULL && (i)->right != NULL) | 97 | #define BOTH_KIDS_P(i) ((i)->left != NULL && (i)->right != NULL) |
| 98 | 98 | ||
| 99 | /* The total size of all text represented by this interval and all its | 99 | /* The total size of all text represented by the nonnull interval I |
| 100 | children in the tree. This is zero if the interval is null. */ | 100 | and all its children in the tree. */ |
| 101 | #define TOTAL_LENGTH(i) ((i) == NULL ? 0 : (i)->total_length) | 101 | #define TOTAL_LENGTH(i) ((i)->total_length) |
| 102 | |||
| 103 | /* Likewise, but also defined to be zero if I is null. */ | ||
| 104 | #define TOTAL_LENGTH0(i) ((i) ? TOTAL_LENGTH (i) : 0) | ||
| 102 | 105 | ||
| 103 | /* The size of text represented by this interval alone. */ | 106 | /* The size of text represented by this interval alone. */ |
| 104 | #define LENGTH(i) ((i)->total_length \ | 107 | #define LENGTH(i) (TOTAL_LENGTH (i) \ |
| 105 | - TOTAL_LENGTH ((i)->right) \ | 108 | - RIGHT_TOTAL_LENGTH (i) \ |
| 106 | - TOTAL_LENGTH ((i)->left)) | 109 | - LEFT_TOTAL_LENGTH (i)) |
| 107 | 110 | ||
| 108 | /* The position of the character just past the end of I. Note that | 111 | /* The position of the character just past the end of I. Note that |
| 109 | the position cache i->position must be valid for this to work. */ | 112 | the position cache i->position must be valid for this to work. */ |
| 110 | #define INTERVAL_LAST_POS(i) ((i)->position + LENGTH (i)) | 113 | #define INTERVAL_LAST_POS(i) ((i)->position + LENGTH (i)) |
| 111 | 114 | ||
| 112 | /* The total size of the left subtree of this interval. */ | 115 | /* The total size of the left subtree of this interval. */ |
| 113 | #define LEFT_TOTAL_LENGTH(i) ((i)->left ? (i)->left->total_length : 0) | 116 | #define LEFT_TOTAL_LENGTH(i) TOTAL_LENGTH0 ((i)->left) |
| 114 | 117 | ||
| 115 | /* The total size of the right subtree of this interval. */ | 118 | /* The total size of the right subtree of this interval. */ |
| 116 | #define RIGHT_TOTAL_LENGTH(i) ((i)->right ? (i)->right->total_length : 0) | 119 | #define RIGHT_TOTAL_LENGTH(i) TOTAL_LENGTH0 ((i)->right) |
| 117 | 120 | ||
| 118 | /* These macros are for dealing with the interval properties. */ | 121 | /* These macros are for dealing with the interval properties. */ |
| 119 | 122 | ||
| @@ -234,7 +237,7 @@ set_interval_plist (INTERVAL i, Lisp_Object plist) | |||
| 234 | 237 | ||
| 235 | /* Declared in alloc.c. */ | 238 | /* Declared in alloc.c. */ |
| 236 | 239 | ||
| 237 | extern INTERVAL make_interval (void); | 240 | extern INTERVAL make_interval (void) ATTRIBUTE_RETURNS_NONNULL; |
| 238 | 241 | ||
| 239 | /* Declared in intervals.c. */ | 242 | /* Declared in intervals.c. */ |
| 240 | 243 | ||
| @@ -246,7 +249,8 @@ extern void traverse_intervals (INTERVAL, ptrdiff_t, | |||
| 246 | Lisp_Object); | 249 | Lisp_Object); |
| 247 | extern void traverse_intervals_noorder (INTERVAL, | 250 | extern void traverse_intervals_noorder (INTERVAL, |
| 248 | void (*) (INTERVAL, void *), void *); | 251 | void (*) (INTERVAL, void *), void *); |
| 249 | extern INTERVAL split_interval_right (INTERVAL, ptrdiff_t); | 252 | extern INTERVAL split_interval_right (INTERVAL, ptrdiff_t) |
| 253 | ATTRIBUTE_RETURNS_NONNULL; | ||
| 250 | extern INTERVAL split_interval_left (INTERVAL, ptrdiff_t); | 254 | extern INTERVAL split_interval_left (INTERVAL, ptrdiff_t); |
| 251 | extern INTERVAL find_interval (INTERVAL, ptrdiff_t); | 255 | extern INTERVAL find_interval (INTERVAL, ptrdiff_t); |
| 252 | extern INTERVAL next_interval (INTERVAL); | 256 | extern INTERVAL next_interval (INTERVAL); |
diff --git a/src/nsterm.m b/src/nsterm.m index 8e256149220..851a5617d7b 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -1141,6 +1141,7 @@ ns_update_end (struct frame *f) | |||
| 1141 | 1141 | ||
| 1142 | #ifdef NS_DRAW_TO_BUFFER | 1142 | #ifdef NS_DRAW_TO_BUFFER |
| 1143 | [NSGraphicsContext setCurrentContext:nil]; | 1143 | [NSGraphicsContext setCurrentContext:nil]; |
| 1144 | [view setNeedsDisplay:YES]; | ||
| 1144 | #else | 1145 | #else |
| 1145 | block_input (); | 1146 | block_input (); |
| 1146 | 1147 | ||
| @@ -1194,12 +1195,6 @@ ns_focus (struct frame *f, NSRect *r, int n) | |||
| 1194 | /* clipping */ | 1195 | /* clipping */ |
| 1195 | if (r) | 1196 | if (r) |
| 1196 | { | 1197 | { |
| 1197 | #ifdef NS_IMPL_COCOA | ||
| 1198 | int i; | ||
| 1199 | for (i = 0 ; i < n ; i++) | ||
| 1200 | [view setNeedsDisplayInRect:r[i]]; | ||
| 1201 | #endif | ||
| 1202 | |||
| 1203 | [[NSGraphicsContext currentContext] saveGraphicsState]; | 1198 | [[NSGraphicsContext currentContext] saveGraphicsState]; |
| 1204 | if (n == 2) | 1199 | if (n == 2) |
| 1205 | NSRectClipList (r, 2); | 1200 | NSRectClipList (r, 2); |
| @@ -1224,7 +1219,9 @@ ns_unfocus (struct frame *f) | |||
| 1224 | gsaved = NO; | 1219 | gsaved = NO; |
| 1225 | } | 1220 | } |
| 1226 | 1221 | ||
| 1227 | #ifdef NS_IMPL_GNUSTEP | 1222 | #ifdef NS_DRAW_TO_BUFFER |
| 1223 | [FRAME_NS_VIEW (f) setNeedsDisplay:YES]; | ||
| 1224 | #else | ||
| 1228 | if (f != ns_updating_frame) | 1225 | if (f != ns_updating_frame) |
| 1229 | { | 1226 | { |
| 1230 | if (focus_view != NULL) | 1227 | if (focus_view != NULL) |
diff --git a/src/pdumper.c b/src/pdumper.c index 4ecdea14538..2e2220a9b29 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -3692,14 +3692,12 @@ dump_unwind_cleanup (void *data) | |||
| 3692 | Vprocess_environment = ctx->old_process_environment; | 3692 | Vprocess_environment = ctx->old_process_environment; |
| 3693 | } | 3693 | } |
| 3694 | 3694 | ||
| 3695 | /* Return DUMP_OFFSET, making sure it is within the heap. */ | 3695 | /* Check that DUMP_OFFSET is within the heap. */ |
| 3696 | static dump_off | 3696 | static void |
| 3697 | dump_check_dump_off (struct dump_context *ctx, dump_off dump_offset) | 3697 | dump_check_dump_off (struct dump_context *ctx, dump_off dump_offset) |
| 3698 | { | 3698 | { |
| 3699 | eassert (dump_offset > 0); | 3699 | eassert (dump_offset > 0); |
| 3700 | if (ctx) | 3700 | eassert (!ctx || dump_offset < ctx->end_heap); |
| 3701 | eassert (dump_offset < ctx->end_heap); | ||
| 3702 | return dump_offset; | ||
| 3703 | } | 3701 | } |
| 3704 | 3702 | ||
| 3705 | static void | 3703 | static void |
| @@ -3822,6 +3820,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc) | |||
| 3822 | } | 3820 | } |
| 3823 | else | 3821 | else |
| 3824 | { | 3822 | { |
| 3823 | eassume (ctx); /* Pacify GCC 9.2.1 -O3 -Wnull-dereference. */ | ||
| 3825 | eassert (!dump_object_emacs_ptr (target_value)); | 3824 | eassert (!dump_object_emacs_ptr (target_value)); |
| 3826 | reloc.u.dump_offset = dump_recall_object (ctx, target_value); | 3825 | reloc.u.dump_offset = dump_recall_object (ctx, target_value); |
| 3827 | if (reloc.u.dump_offset <= 0) | 3826 | if (reloc.u.dump_offset <= 0) |
diff --git a/src/process.c b/src/process.c index 91d426103d8..e4e5e57aeee 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -8277,19 +8277,6 @@ init_process_emacs (int sockfd) | |||
| 8277 | memset (datagram_address, 0, sizeof datagram_address); | 8277 | memset (datagram_address, 0, sizeof datagram_address); |
| 8278 | #endif | 8278 | #endif |
| 8279 | 8279 | ||
| 8280 | #if defined (DARWIN_OS) | ||
| 8281 | /* PTYs are broken on Darwin < 6, but are sometimes useful for interactive | ||
| 8282 | processes. As such, we only change the default value. */ | ||
| 8283 | if (initialized) | ||
| 8284 | { | ||
| 8285 | char const *release = (STRINGP (Voperating_system_release) | ||
| 8286 | ? SSDATA (Voperating_system_release) | ||
| 8287 | : 0); | ||
| 8288 | if (!release || !release[0] || (release[0] < '7' && release[1] == '.')) { | ||
| 8289 | Vprocess_connection_type = Qnil; | ||
| 8290 | } | ||
| 8291 | } | ||
| 8292 | #endif | ||
| 8293 | #endif /* subprocesses */ | 8280 | #endif /* subprocesses */ |
| 8294 | kbd_is_on_hold = 0; | 8281 | kbd_is_on_hold = 0; |
| 8295 | } | 8282 | } |
diff --git a/src/sysdep.c b/src/sysdep.c index e8e8bbfb502..149d80f19ec 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -2752,21 +2752,6 @@ emacs_perror (char const *message) | |||
| 2752 | errno = err; | 2752 | errno = err; |
| 2753 | } | 2753 | } |
| 2754 | 2754 | ||
| 2755 | /* Set the access and modification time stamps of FD (a.k.a. FILE) to be | ||
| 2756 | ATIME and MTIME, respectively. | ||
| 2757 | FD must be either negative -- in which case it is ignored -- | ||
| 2758 | or a file descriptor that is open on FILE. | ||
| 2759 | If FD is nonnegative, then FILE can be NULL. */ | ||
| 2760 | int | ||
| 2761 | set_file_times (int fd, const char *filename, | ||
| 2762 | struct timespec atime, struct timespec mtime) | ||
| 2763 | { | ||
| 2764 | struct timespec timespec[2]; | ||
| 2765 | timespec[0] = atime; | ||
| 2766 | timespec[1] = mtime; | ||
| 2767 | return fdutimens (fd, filename, timespec); | ||
| 2768 | } | ||
| 2769 | |||
| 2770 | /* Rename directory SRCFD's entry SRC to directory DSTFD's entry DST. | 2755 | /* Rename directory SRCFD's entry SRC to directory DSTFD's entry DST. |
| 2771 | This is like renameat except that it fails if DST already exists, | 2756 | This is like renameat except that it fails if DST already exists, |
| 2772 | or if this operation is not supported atomically. Return 0 if | 2757 | or if this operation is not supported atomically. Return 0 if |
diff --git a/src/systime.h b/src/systime.h index 00ca4a1c58d..b59a3d1c690 100644 --- a/src/systime.h +++ b/src/systime.h | |||
| @@ -67,9 +67,6 @@ timespec_valid_p (struct timespec t) | |||
| 67 | return t.tv_nsec >= 0; | 67 | return t.tv_nsec >= 0; |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | /* defined in sysdep.c */ | ||
| 71 | extern int set_file_times (int, const char *, struct timespec, struct timespec); | ||
| 72 | |||
| 73 | /* defined in keyboard.c */ | 70 | /* defined in keyboard.c */ |
| 74 | extern void set_waiting_for_input (struct timespec *); | 71 | extern void set_waiting_for_input (struct timespec *); |
| 75 | 72 | ||
diff --git a/src/timefns.c b/src/timefns.c index 0aa8775f9ff..404ce4973b7 100644 --- a/src/timefns.c +++ b/src/timefns.c | |||
| @@ -421,6 +421,9 @@ decode_float_time (double t, struct lisp_time *result) | |||
| 421 | else if (flt_radix_power_size <= scale) | 421 | else if (flt_radix_power_size <= scale) |
| 422 | return isnan (t) ? EDOM : EOVERFLOW; | 422 | return isnan (t) ? EDOM : EOVERFLOW; |
| 423 | 423 | ||
| 424 | /* Compute TICKS, HZ such that TICKS / HZ exactly equals T, where HZ is | ||
| 425 | T's frequency or 1, whichever is greater. Here, “frequency” means | ||
| 426 | 1/precision. Cache HZ values in flt_radix_power. */ | ||
| 424 | double scaled = scalbn (t, scale); | 427 | double scaled = scalbn (t, scale); |
| 425 | eassert (trunc (scaled) == scaled); | 428 | eassert (trunc (scaled) == scaled); |
| 426 | ticks = double_to_integer (scaled); | 429 | ticks = double_to_integer (scaled); |
| @@ -442,6 +445,7 @@ decode_float_time (double t, struct lisp_time *result) | |||
| 442 | static Lisp_Object | 445 | static Lisp_Object |
| 443 | ticks_hz_list4 (Lisp_Object ticks, Lisp_Object hz) | 446 | ticks_hz_list4 (Lisp_Object ticks, Lisp_Object hz) |
| 444 | { | 447 | { |
| 448 | /* mpz[0] = floor ((ticks * trillion) / hz). */ | ||
| 445 | mpz_t const *zticks = bignum_integer (&mpz[0], ticks); | 449 | mpz_t const *zticks = bignum_integer (&mpz[0], ticks); |
| 446 | #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX | 450 | #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX |
| 447 | mpz_mul_ui (mpz[0], *zticks, TRILLION); | 451 | mpz_mul_ui (mpz[0], *zticks, TRILLION); |
| @@ -449,6 +453,9 @@ ticks_hz_list4 (Lisp_Object ticks, Lisp_Object hz) | |||
| 449 | mpz_mul (mpz[0], *zticks, ztrillion); | 453 | mpz_mul (mpz[0], *zticks, ztrillion); |
| 450 | #endif | 454 | #endif |
| 451 | mpz_fdiv_q (mpz[0], mpz[0], *bignum_integer (&mpz[1], hz)); | 455 | mpz_fdiv_q (mpz[0], mpz[0], *bignum_integer (&mpz[1], hz)); |
| 456 | |||
| 457 | /* mpz[0] = floor (mpz[0] / trillion), with US = the high six digits of the | ||
| 458 | 12-digit remainder, and PS = the low six digits. */ | ||
| 452 | #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX | 459 | #if FASTER_TIMEFNS && TRILLION <= ULONG_MAX |
| 453 | unsigned long int fullps = mpz_fdiv_q_ui (mpz[0], mpz[0], TRILLION); | 460 | unsigned long int fullps = mpz_fdiv_q_ui (mpz[0], mpz[0], TRILLION); |
| 454 | int us = fullps / 1000000; | 461 | int us = fullps / 1000000; |
| @@ -458,11 +465,14 @@ ticks_hz_list4 (Lisp_Object ticks, Lisp_Object hz) | |||
| 458 | int ps = mpz_fdiv_q_ui (mpz[1], mpz[1], 1000000); | 465 | int ps = mpz_fdiv_q_ui (mpz[1], mpz[1], 1000000); |
| 459 | int us = mpz_get_ui (mpz[1]); | 466 | int us = mpz_get_ui (mpz[1]); |
| 460 | #endif | 467 | #endif |
| 468 | |||
| 469 | /* mpz[0] = floor (mpz[0] / 1 << LO_TIME_BITS), with lo = remainder. */ | ||
| 461 | unsigned long ulo = mpz_get_ui (mpz[0]); | 470 | unsigned long ulo = mpz_get_ui (mpz[0]); |
| 462 | if (mpz_sgn (mpz[0]) < 0) | 471 | if (mpz_sgn (mpz[0]) < 0) |
| 463 | ulo = -ulo; | 472 | ulo = -ulo; |
| 464 | int lo = ulo & ((1 << LO_TIME_BITS) - 1); | 473 | int lo = ulo & ((1 << LO_TIME_BITS) - 1); |
| 465 | mpz_fdiv_q_2exp (mpz[0], mpz[0], LO_TIME_BITS); | 474 | mpz_fdiv_q_2exp (mpz[0], mpz[0], LO_TIME_BITS); |
| 475 | |||
| 466 | return list4 (make_integer_mpz (), make_fixnum (lo), | 476 | return list4 (make_integer_mpz (), make_fixnum (lo), |
| 467 | make_fixnum (us), make_fixnum (ps)); | 477 | make_fixnum (us), make_fixnum (ps)); |
| 468 | } | 478 | } |
| @@ -482,6 +492,7 @@ mpz_set_time (mpz_t rop, time_t t) | |||
| 482 | static void | 492 | static void |
| 483 | timespec_mpz (struct timespec t) | 493 | timespec_mpz (struct timespec t) |
| 484 | { | 494 | { |
| 495 | /* mpz[0] = sec * TIMESPEC_HZ + nsec. */ | ||
| 485 | mpz_set_ui (mpz[0], t.tv_nsec); | 496 | mpz_set_ui (mpz[0], t.tv_nsec); |
| 486 | mpz_set_time (mpz[1], t.tv_sec); | 497 | mpz_set_time (mpz[1], t.tv_sec); |
| 487 | mpz_addmul_ui (mpz[0], mpz[1], TIMESPEC_HZ); | 498 | mpz_addmul_ui (mpz[0], mpz[1], TIMESPEC_HZ); |
| @@ -491,11 +502,14 @@ timespec_mpz (struct timespec t) | |||
| 491 | static Lisp_Object | 502 | static Lisp_Object |
| 492 | timespec_ticks (struct timespec t) | 503 | timespec_ticks (struct timespec t) |
| 493 | { | 504 | { |
| 505 | /* For speed, use intmax_t arithmetic if it will do. */ | ||
| 494 | intmax_t accum; | 506 | intmax_t accum; |
| 495 | if (FASTER_TIMEFNS | 507 | if (FASTER_TIMEFNS |
| 496 | && !INT_MULTIPLY_WRAPV (t.tv_sec, TIMESPEC_HZ, &accum) | 508 | && !INT_MULTIPLY_WRAPV (t.tv_sec, TIMESPEC_HZ, &accum) |
| 497 | && !INT_ADD_WRAPV (t.tv_nsec, accum, &accum)) | 509 | && !INT_ADD_WRAPV (t.tv_nsec, accum, &accum)) |
| 498 | return make_int (accum); | 510 | return make_int (accum); |
| 511 | |||
| 512 | /* Fall back on bignum arithmetic. */ | ||
| 499 | timespec_mpz (t); | 513 | timespec_mpz (t); |
| 500 | return make_integer_mpz (); | 514 | return make_integer_mpz (); |
| 501 | } | 515 | } |
| @@ -505,12 +519,19 @@ timespec_ticks (struct timespec t) | |||
| 505 | static Lisp_Object | 519 | static Lisp_Object |
| 506 | lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) | 520 | lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) |
| 507 | { | 521 | { |
| 522 | /* The idea is to return the floor of ((T.ticks * HZ) / T.hz). */ | ||
| 523 | |||
| 524 | /* For speed, just return T.ticks if T.hz == HZ. */ | ||
| 508 | if (FASTER_TIMEFNS && EQ (t.hz, hz)) | 525 | if (FASTER_TIMEFNS && EQ (t.hz, hz)) |
| 509 | return t.ticks; | 526 | return t.ticks; |
| 527 | |||
| 528 | /* Check HZ for validity. */ | ||
| 510 | if (FIXNUMP (hz)) | 529 | if (FIXNUMP (hz)) |
| 511 | { | 530 | { |
| 512 | if (XFIXNUM (hz) <= 0) | 531 | if (XFIXNUM (hz) <= 0) |
| 513 | invalid_hz (hz); | 532 | invalid_hz (hz); |
| 533 | |||
| 534 | /* For speed, use intmax_t arithmetic if it will do. */ | ||
| 514 | intmax_t ticks; | 535 | intmax_t ticks; |
| 515 | if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz) | 536 | if (FASTER_TIMEFNS && FIXNUMP (t.ticks) && FIXNUMP (t.hz) |
| 516 | && !INT_MULTIPLY_WRAPV (XFIXNUM (t.ticks), XFIXNUM (hz), &ticks)) | 537 | && !INT_MULTIPLY_WRAPV (XFIXNUM (t.ticks), XFIXNUM (hz), &ticks)) |
| @@ -520,6 +541,7 @@ lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) | |||
| 520 | else if (! (BIGNUMP (hz) && 0 < mpz_sgn (*xbignum_val (hz)))) | 541 | else if (! (BIGNUMP (hz) && 0 < mpz_sgn (*xbignum_val (hz)))) |
| 521 | invalid_hz (hz); | 542 | invalid_hz (hz); |
| 522 | 543 | ||
| 544 | /* Fall back on bignum arithmetic. */ | ||
| 523 | mpz_mul (mpz[0], | 545 | mpz_mul (mpz[0], |
| 524 | *bignum_integer (&mpz[0], t.ticks), | 546 | *bignum_integer (&mpz[0], t.ticks), |
| 525 | *bignum_integer (&mpz[1], hz)); | 547 | *bignum_integer (&mpz[1], hz)); |
| @@ -531,11 +553,17 @@ lisp_time_hz_ticks (struct lisp_time t, Lisp_Object hz) | |||
| 531 | static Lisp_Object | 553 | static Lisp_Object |
| 532 | lisp_time_seconds (struct lisp_time t) | 554 | lisp_time_seconds (struct lisp_time t) |
| 533 | { | 555 | { |
| 556 | /* The idea is to return the floor of T.ticks / T.hz. */ | ||
| 557 | |||
| 534 | if (!FASTER_TIMEFNS) | 558 | if (!FASTER_TIMEFNS) |
| 535 | return lisp_time_hz_ticks (t, make_fixnum (1)); | 559 | return lisp_time_hz_ticks (t, make_fixnum (1)); |
| 560 | |||
| 561 | /* For speed, use EMACS_INT arithmetic if it will do. */ | ||
| 536 | if (FIXNUMP (t.ticks) && FIXNUMP (t.hz)) | 562 | if (FIXNUMP (t.ticks) && FIXNUMP (t.hz)) |
| 537 | return make_fixnum (XFIXNUM (t.ticks) / XFIXNUM (t.hz) | 563 | return make_fixnum (XFIXNUM (t.ticks) / XFIXNUM (t.hz) |
| 538 | - (XFIXNUM (t.ticks) % XFIXNUM (t.hz) < 0)); | 564 | - (XFIXNUM (t.ticks) % XFIXNUM (t.hz) < 0)); |
| 565 | |||
| 566 | /* For speed, inline what lisp_time_hz_ticks would do. */ | ||
| 539 | mpz_fdiv_q (mpz[0], | 567 | mpz_fdiv_q (mpz[0], |
| 540 | *bignum_integer (&mpz[0], t.ticks), | 568 | *bignum_integer (&mpz[0], t.ticks), |
| 541 | *bignum_integer (&mpz[1], t.hz)); | 569 | *bignum_integer (&mpz[1], t.hz)); |
| @@ -577,6 +605,7 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) | |||
| 577 | && intmax_numerator % intmax_denominator == 0) | 605 | && intmax_numerator % intmax_denominator == 0) |
| 578 | return intmax_numerator / intmax_denominator; | 606 | return intmax_numerator / intmax_denominator; |
| 579 | 607 | ||
| 608 | /* Compute number of base-FLT_RADIX digits in numerator and denominator. */ | ||
| 580 | mpz_t const *n = bignum_integer (&mpz[0], numerator); | 609 | mpz_t const *n = bignum_integer (&mpz[0], numerator); |
| 581 | mpz_t const *d = bignum_integer (&mpz[1], denominator); | 610 | mpz_t const *d = bignum_integer (&mpz[1], denominator); |
| 582 | ptrdiff_t ndig = mpz_sizeinbase (*n, FLT_RADIX); | 611 | ptrdiff_t ndig = mpz_sizeinbase (*n, FLT_RADIX); |
| @@ -588,7 +617,8 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) | |||
| 588 | /* Scale with SCALE when doing integer division. That is, compute | 617 | /* Scale with SCALE when doing integer division. That is, compute |
| 589 | (N * FLT_RADIX**SCALE) / D [or, if SCALE is negative, N / (D * | 618 | (N * FLT_RADIX**SCALE) / D [or, if SCALE is negative, N / (D * |
| 590 | FLT_RADIX**-SCALE)] as a bignum, convert the bignum to double, | 619 | FLT_RADIX**-SCALE)] as a bignum, convert the bignum to double, |
| 591 | then divide the double by FLT_RADIX**SCALE. */ | 620 | then divide the double by FLT_RADIX**SCALE. First scale N |
| 621 | (or scale D, if SCALE is negative) ... */ | ||
| 592 | ptrdiff_t scale = ddig - ndig + DBL_MANT_DIG; | 622 | ptrdiff_t scale = ddig - ndig + DBL_MANT_DIG; |
| 593 | if (scale < 0) | 623 | if (scale < 0) |
| 594 | { | 624 | { |
| @@ -603,12 +633,12 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) | |||
| 603 | mpz_mul_2exp (mpz[0], *n, scale * LOG2_FLT_RADIX); | 633 | mpz_mul_2exp (mpz[0], *n, scale * LOG2_FLT_RADIX); |
| 604 | n = &mpz[0]; | 634 | n = &mpz[0]; |
| 605 | } | 635 | } |
| 606 | 636 | /* ... and then divide, with quotient Q and remainder R. */ | |
| 607 | mpz_t *q = &mpz[2]; | 637 | mpz_t *q = &mpz[2]; |
| 608 | mpz_t *r = &mpz[3]; | 638 | mpz_t *r = &mpz[3]; |
| 609 | mpz_tdiv_qr (*q, *r, *n, *d); | 639 | mpz_tdiv_qr (*q, *r, *n, *d); |
| 610 | 640 | ||
| 611 | /* The amount to add to the absolute value of *Q so that truncating | 641 | /* The amount to add to the absolute value of Q so that truncating |
| 612 | it to double will round correctly. */ | 642 | it to double will round correctly. */ |
| 613 | int incr; | 643 | int incr; |
| 614 | 644 | ||
| @@ -647,6 +677,7 @@ frac_to_double (Lisp_Object numerator, Lisp_Object denominator) | |||
| 647 | if (!FASTER_TIMEFNS || incr != 0) | 677 | if (!FASTER_TIMEFNS || incr != 0) |
| 648 | (mpz_sgn (*n) < 0 ? mpz_sub_ui : mpz_add_ui) (*q, *q, incr); | 678 | (mpz_sgn (*n) < 0 ? mpz_sub_ui : mpz_add_ui) (*q, *q, incr); |
| 649 | 679 | ||
| 680 | /* Rescale the integer Q back to double. This step does not round. */ | ||
| 650 | return scalbn (mpz_get_d (*q), -scale); | 681 | return scalbn (mpz_get_d (*q), -scale); |
| 651 | } | 682 | } |
| 652 | 683 | ||
| @@ -895,6 +926,10 @@ lisp_to_timespec (struct lisp_time t) | |||
| 895 | mpz_t *q = &mpz[0]; | 926 | mpz_t *q = &mpz[0]; |
| 896 | mpz_t const *qt = q; | 927 | mpz_t const *qt = q; |
| 897 | 928 | ||
| 929 | /* Floor-divide (T.ticks * TIMESPEC_HZ) by T.hz, | ||
| 930 | yielding quotient Q (tv_sec) and remainder NS (tv_nsec). | ||
| 931 | Return an invalid timespec if Q does not fit in time_t. | ||
| 932 | For speed, prefer fixnum arithmetic if it works. */ | ||
| 898 | if (FASTER_TIMEFNS && EQ (t.hz, timespec_hz)) | 933 | if (FASTER_TIMEFNS && EQ (t.hz, timespec_hz)) |
| 899 | { | 934 | { |
| 900 | if (FIXNUMP (t.ticks)) | 935 | if (FIXNUMP (t.ticks)) |
| @@ -938,8 +973,8 @@ lisp_to_timespec (struct lisp_time t) | |||
| 938 | ns = mpz_fdiv_q_ui (*q, *q, TIMESPEC_HZ); | 973 | ns = mpz_fdiv_q_ui (*q, *q, TIMESPEC_HZ); |
| 939 | } | 974 | } |
| 940 | 975 | ||
| 941 | /* With some versions of MinGW, tv_sec is a 64-bit type, whereas | 976 | /* Check that Q fits in time_t, not merely in T.tv_sec. With some versions |
| 942 | time_t is a 32-bit type. */ | 977 | of MinGW, tv_sec is a 64-bit type, whereas time_t is a 32-bit type. */ |
| 943 | time_t sec; | 978 | time_t sec; |
| 944 | if (mpz_time (*qt, &sec)) | 979 | if (mpz_time (*qt, &sec)) |
| 945 | { | 980 | { |
| @@ -1019,10 +1054,14 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1019 | { | 1054 | { |
| 1020 | if (EQ (b, make_fixnum (0))) | 1055 | if (EQ (b, make_fixnum (0))) |
| 1021 | return a; | 1056 | return a; |
| 1057 | |||
| 1058 | /* For speed, use EMACS_INT arithmetic if it will do. */ | ||
| 1022 | if (FIXNUMP (a)) | 1059 | if (FIXNUMP (a)) |
| 1023 | return make_int (subtract | 1060 | return make_int (subtract |
| 1024 | ? XFIXNUM (a) - XFIXNUM (b) | 1061 | ? XFIXNUM (a) - XFIXNUM (b) |
| 1025 | : XFIXNUM (a) + XFIXNUM (b)); | 1062 | : XFIXNUM (a) + XFIXNUM (b)); |
| 1063 | |||
| 1064 | /* For speed, use mpz_add_ui/mpz_sub_ui if it will do. */ | ||
| 1026 | if (eabs (XFIXNUM (b)) <= ULONG_MAX) | 1065 | if (eabs (XFIXNUM (b)) <= ULONG_MAX) |
| 1027 | { | 1066 | { |
| 1028 | ((XFIXNUM (b) < 0) == subtract ? mpz_add_ui : mpz_sub_ui) | 1067 | ((XFIXNUM (b) < 0) == subtract ? mpz_add_ui : mpz_sub_ui) |
| @@ -1031,6 +1070,7 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1031 | } | 1070 | } |
| 1032 | } | 1071 | } |
| 1033 | 1072 | ||
| 1073 | /* Fall back on bignum arithmetic if necessary. */ | ||
| 1034 | if (!mpz_done) | 1074 | if (!mpz_done) |
| 1035 | (subtract ? mpz_sub : mpz_add) (mpz[0], | 1075 | (subtract ? mpz_sub : mpz_add) (mpz[0], |
| 1036 | *bignum_integer (&mpz[0], a), | 1076 | *bignum_integer (&mpz[0], a), |
| @@ -1039,9 +1079,7 @@ lispint_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1039 | } | 1079 | } |
| 1040 | 1080 | ||
| 1041 | /* Given Lisp operands A and B, add their values, and return the | 1081 | /* Given Lisp operands A and B, add their values, and return the |
| 1042 | result as a Lisp timestamp that is in (TICKS . HZ) form if either A | 1082 | result as a Lisp timestamp. Subtract instead of adding if SUBTRACT. */ |
| 1043 | or B are in that form or are floats, (HI LO US PS) form otherwise. | ||
| 1044 | Subtract instead of adding if SUBTRACT. */ | ||
| 1045 | static Lisp_Object | 1083 | static Lisp_Object |
| 1046 | time_arith (Lisp_Object a, Lisp_Object b, bool subtract) | 1084 | time_arith (Lisp_Object a, Lisp_Object b, bool subtract) |
| 1047 | { | 1085 | { |
| @@ -1124,21 +1162,22 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1124 | (subtract ? mpz_submul : mpz_addmul) (*iticks, *fa, *nb); | 1162 | (subtract ? mpz_submul : mpz_addmul) (*iticks, *fa, *nb); |
| 1125 | 1163 | ||
| 1126 | /* Normalize iticks/ihz by dividing both numerator and | 1164 | /* Normalize iticks/ihz by dividing both numerator and |
| 1127 | denominator by ig = gcd (iticks, ihz). However, if that | 1165 | denominator by ig = gcd (iticks, ihz). For speed, though, |
| 1128 | would cause the denominator to become less than hzmin, | 1166 | skip this division if ihz = 1. */ |
| 1129 | rescale the denominator upwards from its ordinary value by | ||
| 1130 | multiplying numerator and denominator so that the denominator | ||
| 1131 | becomes at least hzmin. This rescaling avoids returning a | ||
| 1132 | timestamp that is less precise than both a and b, or a | ||
| 1133 | timestamp that looks obsolete when that might be a problem. */ | ||
| 1134 | mpz_t *ig = &mpz[3]; | 1167 | mpz_t *ig = &mpz[3]; |
| 1135 | mpz_gcd (*ig, *iticks, *ihz); | 1168 | mpz_gcd (*ig, *iticks, *ihz); |
| 1136 | |||
| 1137 | if (!FASTER_TIMEFNS || mpz_cmp_ui (*ig, 1) > 0) | 1169 | if (!FASTER_TIMEFNS || mpz_cmp_ui (*ig, 1) > 0) |
| 1138 | { | 1170 | { |
| 1139 | mpz_divexact (*iticks, *iticks, *ig); | 1171 | mpz_divexact (*iticks, *iticks, *ig); |
| 1140 | mpz_divexact (*ihz, *ihz, *ig); | 1172 | mpz_divexact (*ihz, *ihz, *ig); |
| 1141 | 1173 | ||
| 1174 | /* However, if dividing the denominator by ig would cause the | ||
| 1175 | denominator to become less than hzmin, rescale the denominator | ||
| 1176 | upwards by multiplying the normalized numerator and denominator | ||
| 1177 | so that the resulting denominator becomes at least hzmin. | ||
| 1178 | This rescaling avoids returning a timestamp that is less precise | ||
| 1179 | than both a and b, or a timestamp that looks obsolete when that | ||
| 1180 | might be a problem. */ | ||
| 1142 | if (!FASTER_TIMEFNS || mpz_cmp (*ihz, *hzmin) < 0) | 1181 | if (!FASTER_TIMEFNS || mpz_cmp (*ihz, *hzmin) < 0) |
| 1143 | { | 1182 | { |
| 1144 | /* Rescale straightforwardly. Although this might not | 1183 | /* Rescale straightforwardly. Although this might not |
| @@ -1152,6 +1191,8 @@ time_arith (Lisp_Object a, Lisp_Object b, bool subtract) | |||
| 1152 | mpz_mul (*ihz, *ihz, *rescale); | 1191 | mpz_mul (*ihz, *ihz, *rescale); |
| 1153 | } | 1192 | } |
| 1154 | } | 1193 | } |
| 1194 | |||
| 1195 | /* mpz[0] and iticks now correspond to the (HZ . TICKS) pair. */ | ||
| 1155 | hz = make_integer_mpz (); | 1196 | hz = make_integer_mpz (); |
| 1156 | mpz_swap (mpz[0], *iticks); | 1197 | mpz_swap (mpz[0], *iticks); |
| 1157 | ticks = make_integer_mpz (); | 1198 | ticks = make_integer_mpz (); |
| @@ -1213,6 +1254,8 @@ time_cmp (Lisp_Object a, Lisp_Object b) | |||
| 1213 | if (EQ (a, b)) | 1254 | if (EQ (a, b)) |
| 1214 | return 0; | 1255 | return 0; |
| 1215 | 1256 | ||
| 1257 | /* Compare (ATICKS . AZ) to (BTICKS . BHZ) by comparing | ||
| 1258 | ATICKS * BHZ to BTICKS * AHZ. */ | ||
| 1216 | struct lisp_time tb = lisp_time_struct (b, 0); | 1259 | struct lisp_time tb = lisp_time_struct (b, 0); |
| 1217 | mpz_t const *za = bignum_integer (&mpz[0], ta.ticks); | 1260 | mpz_t const *za = bignum_integer (&mpz[0], ta.ticks); |
| 1218 | mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks); | 1261 | mpz_t const *zb = bignum_integer (&mpz[1], tb.ticks); |
| @@ -1490,6 +1533,7 @@ SEC is always an integer between 0 and 59.) | |||
| 1490 | usage: (decode-time &optional TIME ZONE FORM) */) | 1533 | usage: (decode-time &optional TIME ZONE FORM) */) |
| 1491 | (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form) | 1534 | (Lisp_Object specified_time, Lisp_Object zone, Lisp_Object form) |
| 1492 | { | 1535 | { |
| 1536 | /* Compute broken-down local time LOCAL_TM from SPECIFIED_TIME and ZONE. */ | ||
| 1493 | struct lisp_time lt = lisp_time_struct (specified_time, 0); | 1537 | struct lisp_time lt = lisp_time_struct (specified_time, 0); |
| 1494 | struct timespec ts = lisp_to_timespec (lt); | 1538 | struct timespec ts = lisp_to_timespec (lt); |
| 1495 | if (! timespec_valid_p (ts)) | 1539 | if (! timespec_valid_p (ts)) |
| @@ -1504,6 +1548,7 @@ usage: (decode-time &optional TIME ZONE FORM) */) | |||
| 1504 | if (!tm) | 1548 | if (!tm) |
| 1505 | time_error (localtime_errno); | 1549 | time_error (localtime_errno); |
| 1506 | 1550 | ||
| 1551 | /* Let YEAR = LOCAL_TM.tm_year + TM_YEAR_BASE. */ | ||
| 1507 | Lisp_Object year; | 1552 | Lisp_Object year; |
| 1508 | if (FASTER_TIMEFNS | 1553 | if (FASTER_TIMEFNS |
| 1509 | && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year | 1554 | && MOST_NEGATIVE_FIXNUM - TM_YEAR_BASE <= local_tm.tm_year |
| @@ -1520,12 +1565,15 @@ usage: (decode-time &optional TIME ZONE FORM) */) | |||
| 1520 | year = make_integer_mpz (); | 1565 | year = make_integer_mpz (); |
| 1521 | } | 1566 | } |
| 1522 | 1567 | ||
| 1568 | /* Compute SEC from LOCAL_TM.tm_sec and HZ. */ | ||
| 1523 | Lisp_Object hz = lt.hz, sec; | 1569 | Lisp_Object hz = lt.hz, sec; |
| 1524 | if (EQ (hz, make_fixnum (1)) || !EQ (form, Qt)) | 1570 | if (EQ (hz, make_fixnum (1)) || !EQ (form, Qt)) |
| 1525 | sec = make_fixnum (local_tm.tm_sec); | 1571 | sec = make_fixnum (local_tm.tm_sec); |
| 1526 | else | 1572 | else |
| 1527 | { | 1573 | { |
| 1528 | Lisp_Object ticks; /* hz * tm_sec + mod (lt.ticks, hz) */ | 1574 | /* Let TICKS = HZ * LOCAL_TM.tm_sec + mod (LT.ticks, HZ) |
| 1575 | and SEC = (TICKS . HZ). */ | ||
| 1576 | Lisp_Object ticks; | ||
| 1529 | intmax_t n; | 1577 | intmax_t n; |
| 1530 | if (FASTER_TIMEFNS && FIXNUMP (lt.ticks) && FIXNUMP (hz) | 1578 | if (FASTER_TIMEFNS && FIXNUMP (lt.ticks) && FIXNUMP (hz) |
| 1531 | && !INT_MULTIPLY_WRAPV (XFIXNUM (hz), local_tm.tm_sec, &n) | 1579 | && !INT_MULTIPLY_WRAPV (XFIXNUM (hz), local_tm.tm_sec, &n) |
| @@ -1655,6 +1703,7 @@ usage: (encode-time TIME &rest OBSOLESCENT-ARGUMENTS) */) | |||
| 1655 | yeararg = args[5]; | 1703 | yeararg = args[5]; |
| 1656 | } | 1704 | } |
| 1657 | 1705 | ||
| 1706 | /* Let SEC = floor (LT.ticks / HZ), with SUBSECTICKS the remainder. */ | ||
| 1658 | struct lisp_time lt; | 1707 | struct lisp_time lt; |
| 1659 | decode_lisp_time (secarg, 0, <, 0); | 1708 | decode_lisp_time (secarg, 0, <, 0); |
| 1660 | Lisp_Object hz = lt.hz, sec, subsecticks; | 1709 | Lisp_Object hz = lt.hz, sec, subsecticks; |
| @@ -3178,18 +3178,9 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2]) | |||
| 3178 | return _futime (fd, &_ut); | 3178 | return _futime (fd, &_ut); |
| 3179 | } | 3179 | } |
| 3180 | else | 3180 | else |
| 3181 | { | 3181 | return utimensat (fd, file, timespec, 0); |
| 3182 | struct utimbuf ut; | ||
| 3183 | |||
| 3184 | ut.actime = timespec[0].tv_sec; | ||
| 3185 | ut.modtime = timespec[1].tv_sec; | ||
| 3186 | /* Call 'utime', which is implemented below, not the MS library | ||
| 3187 | function, which fails on directories. */ | ||
| 3188 | return utime (file, &ut); | ||
| 3189 | } | ||
| 3190 | } | 3182 | } |
| 3191 | 3183 | ||
| 3192 | |||
| 3193 | /* ------------------------------------------------------------------------- */ | 3184 | /* ------------------------------------------------------------------------- */ |
| 3194 | /* IO support and wrapper functions for the Windows API. */ | 3185 | /* IO support and wrapper functions for the Windows API. */ |
| 3195 | /* ------------------------------------------------------------------------- */ | 3186 | /* ------------------------------------------------------------------------- */ |
| @@ -4970,7 +4961,7 @@ convert_time (FILETIME ft) | |||
| 4970 | } | 4961 | } |
| 4971 | 4962 | ||
| 4972 | static void | 4963 | static void |
| 4973 | convert_from_time_t (time_t time, FILETIME * pft) | 4964 | convert_from_timespec (struct timespec time, FILETIME * pft) |
| 4974 | { | 4965 | { |
| 4975 | ULARGE_INTEGER tmp; | 4966 | ULARGE_INTEGER tmp; |
| 4976 | 4967 | ||
| @@ -4981,7 +4972,8 @@ convert_from_time_t (time_t time, FILETIME * pft) | |||
| 4981 | } | 4972 | } |
| 4982 | 4973 | ||
| 4983 | /* time in 100ns units since 1-Jan-1601 */ | 4974 | /* time in 100ns units since 1-Jan-1601 */ |
| 4984 | tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base; | 4975 | tmp.QuadPart = |
| 4976 | (ULONGLONG) time.tv_sec * 10000000L + time.tv_nsec / 100 + utc_base; | ||
| 4985 | pft->dwHighDateTime = tmp.HighPart; | 4977 | pft->dwHighDateTime = tmp.HighPart; |
| 4986 | pft->dwLowDateTime = tmp.LowPart; | 4978 | pft->dwLowDateTime = tmp.LowPart; |
| 4987 | } | 4979 | } |
| @@ -5648,8 +5640,8 @@ fstatat (int fd, char const *name, struct stat *st, int flags) | |||
| 5648 | return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW)); | 5640 | return stat_worker (name, st, ! (flags & AT_SYMLINK_NOFOLLOW)); |
| 5649 | } | 5641 | } |
| 5650 | 5642 | ||
| 5651 | /* Provide fstat and utime as well as stat for consistent handling of | 5643 | /* Provide fstat and utimensat as well as stat for consistent handling |
| 5652 | file timestamps. */ | 5644 | of file timestamps. */ |
| 5653 | int | 5645 | int |
| 5654 | fstat (int desc, struct stat * buf) | 5646 | fstat (int desc, struct stat * buf) |
| 5655 | { | 5647 | { |
| @@ -5760,23 +5752,65 @@ fstat (int desc, struct stat * buf) | |||
| 5760 | return 0; | 5752 | return 0; |
| 5761 | } | 5753 | } |
| 5762 | 5754 | ||
| 5763 | /* A version of 'utime' which handles directories as well as | 5755 | /* Emulate utimensat. */ |
| 5764 | files. */ | ||
| 5765 | 5756 | ||
| 5766 | int | 5757 | int |
| 5767 | utime (const char *name, struct utimbuf *times) | 5758 | utimensat (int fd, const char *name, const struct timespec times[2], int flag) |
| 5768 | { | 5759 | { |
| 5769 | struct utimbuf deftime; | 5760 | struct timespec ltimes[2]; |
| 5770 | HANDLE fh; | 5761 | HANDLE fh; |
| 5771 | FILETIME mtime; | 5762 | FILETIME mtime; |
| 5772 | FILETIME atime; | 5763 | FILETIME atime; |
| 5764 | DWORD flags_and_attrs = FILE_FLAG_BACKUP_SEMANTICS; | ||
| 5765 | |||
| 5766 | /* Rely on a hack: an open directory is modeled as file descriptor 0. | ||
| 5767 | This is good enough for the current usage in Emacs, but is fragile. | ||
| 5768 | |||
| 5769 | FIXME: Add proper support for utimensat. | ||
| 5770 | Gnulib does this and can serve as a model. */ | ||
| 5771 | char fullname[MAX_UTF8_PATH]; | ||
| 5772 | |||
| 5773 | if (fd != AT_FDCWD) | ||
| 5774 | { | ||
| 5775 | char lastc = dir_pathname[strlen (dir_pathname) - 1]; | ||
| 5776 | |||
| 5777 | if (_snprintf (fullname, sizeof fullname, "%s%s%s", | ||
| 5778 | dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name) | ||
| 5779 | < 0) | ||
| 5780 | { | ||
| 5781 | errno = ENAMETOOLONG; | ||
| 5782 | return -1; | ||
| 5783 | } | ||
| 5784 | name = fullname; | ||
| 5785 | } | ||
| 5773 | 5786 | ||
| 5774 | if (times == NULL) | 5787 | if (times == NULL) |
| 5775 | { | 5788 | { |
| 5776 | deftime.modtime = deftime.actime = time (NULL); | 5789 | memset (ltimes, 0, sizeof (ltimes)); |
| 5777 | times = &deftime; | 5790 | ltimes[0] = ltimes[1] = current_timespec (); |
| 5791 | } | ||
| 5792 | else | ||
| 5793 | { | ||
| 5794 | if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) | ||
| 5795 | return 0; /* nothing to do */ | ||
| 5796 | if ((times[0].tv_nsec != UTIME_NOW && times[0].tv_nsec != UTIME_OMIT | ||
| 5797 | && !(0 <= times[0].tv_nsec && times[0].tv_nsec < 1000000000)) | ||
| 5798 | || (times[1].tv_nsec != UTIME_NOW && times[1].tv_nsec != UTIME_OMIT | ||
| 5799 | && !(0 <= times[1].tv_nsec && times[1].tv_nsec < 1000000000))) | ||
| 5800 | { | ||
| 5801 | errno = EINVAL; /* reject invalid timespec values */ | ||
| 5802 | return -1; | ||
| 5803 | } | ||
| 5804 | |||
| 5805 | memcpy (ltimes, times, sizeof (ltimes)); | ||
| 5806 | if (ltimes[0].tv_nsec == UTIME_NOW) | ||
| 5807 | ltimes[0] = current_timespec (); | ||
| 5808 | if (ltimes[1].tv_nsec == UTIME_NOW) | ||
| 5809 | ltimes[1] = current_timespec (); | ||
| 5778 | } | 5810 | } |
| 5779 | 5811 | ||
| 5812 | if (flag == AT_SYMLINK_NOFOLLOW) | ||
| 5813 | flags_and_attrs |= FILE_FLAG_OPEN_REPARSE_POINT; | ||
| 5780 | if (w32_unicode_filenames) | 5814 | if (w32_unicode_filenames) |
| 5781 | { | 5815 | { |
| 5782 | wchar_t name_utf16[MAX_PATH]; | 5816 | wchar_t name_utf16[MAX_PATH]; |
| @@ -5790,7 +5824,7 @@ utime (const char *name, struct utimbuf *times) | |||
| 5790 | allows other processes to delete files inside it, | 5824 | allows other processes to delete files inside it, |
| 5791 | while we have the directory open. */ | 5825 | while we have the directory open. */ |
| 5792 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | 5826 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 5793 | 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | 5827 | 0, OPEN_EXISTING, flags_and_attrs, NULL); |
| 5794 | } | 5828 | } |
| 5795 | else | 5829 | else |
| 5796 | { | 5830 | { |
| @@ -5801,13 +5835,26 @@ utime (const char *name, struct utimbuf *times) | |||
| 5801 | 5835 | ||
| 5802 | fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES, | 5836 | fh = CreateFileA (name_ansi, FILE_WRITE_ATTRIBUTES, |
| 5803 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | 5837 | FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
| 5804 | 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | 5838 | 0, OPEN_EXISTING, flags_and_attrs, NULL); |
| 5805 | } | 5839 | } |
| 5806 | if (fh != INVALID_HANDLE_VALUE) | 5840 | if (fh != INVALID_HANDLE_VALUE) |
| 5807 | { | 5841 | { |
| 5808 | convert_from_time_t (times->actime, &atime); | 5842 | FILETIME *patime, *pmtime; |
| 5809 | convert_from_time_t (times->modtime, &mtime); | 5843 | if (ltimes[0].tv_nsec == UTIME_OMIT) |
| 5810 | if (!SetFileTime (fh, NULL, &atime, &mtime)) | 5844 | patime = NULL; |
| 5845 | else | ||
| 5846 | { | ||
| 5847 | convert_from_timespec (ltimes[0], &atime); | ||
| 5848 | patime = &atime; | ||
| 5849 | } | ||
| 5850 | if (ltimes[1].tv_nsec == UTIME_OMIT) | ||
| 5851 | pmtime = NULL; | ||
| 5852 | else | ||
| 5853 | { | ||
| 5854 | convert_from_timespec (ltimes[1], &mtime); | ||
| 5855 | pmtime = &mtime; | ||
| 5856 | } | ||
| 5857 | if (!SetFileTime (fh, NULL, patime, pmtime)) | ||
| 5811 | { | 5858 | { |
| 5812 | CloseHandle (fh); | 5859 | CloseHandle (fh); |
| 5813 | errno = EACCES; | 5860 | errno = EACCES; |
| @@ -6726,16 +6773,16 @@ w32_copy_file (const char *from, const char *to, | |||
| 6726 | FIXME? */ | 6773 | FIXME? */ |
| 6727 | else if (!keep_time) | 6774 | else if (!keep_time) |
| 6728 | { | 6775 | { |
| 6729 | struct timespec now; | 6776 | struct timespec tnow[2]; |
| 6730 | DWORD attributes; | 6777 | DWORD attributes; |
| 6731 | 6778 | ||
| 6779 | tnow[0] = tnow[1] = current_timespec (); | ||
| 6732 | if (w32_unicode_filenames) | 6780 | if (w32_unicode_filenames) |
| 6733 | { | 6781 | { |
| 6734 | /* Ensure file is writable while its times are set. */ | 6782 | /* Ensure file is writable while its times are set. */ |
| 6735 | attributes = GetFileAttributesW (to_w); | 6783 | attributes = GetFileAttributesW (to_w); |
| 6736 | SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY); | 6784 | SetFileAttributesW (to_w, attributes & ~FILE_ATTRIBUTE_READONLY); |
| 6737 | now = current_timespec (); | 6785 | if (utimensat (AT_FDCWD, to, tnow, 0)) |
| 6738 | if (set_file_times (-1, to, now, now)) | ||
| 6739 | { | 6786 | { |
| 6740 | /* Restore original attributes. */ | 6787 | /* Restore original attributes. */ |
| 6741 | SetFileAttributesW (to_w, attributes); | 6788 | SetFileAttributesW (to_w, attributes); |
| @@ -6750,8 +6797,7 @@ w32_copy_file (const char *from, const char *to, | |||
| 6750 | { | 6797 | { |
| 6751 | attributes = GetFileAttributesA (to_a); | 6798 | attributes = GetFileAttributesA (to_a); |
| 6752 | SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY); | 6799 | SetFileAttributesA (to_a, attributes & ~FILE_ATTRIBUTE_READONLY); |
| 6753 | now = current_timespec (); | 6800 | if (utimensat (AT_FDCWD, to, tnow, 0)) |
| 6754 | if (set_file_times (-1, to, now, now)) | ||
| 6755 | { | 6801 | { |
| 6756 | SetFileAttributesA (to_a, attributes); | 6802 | SetFileAttributesA (to_a, attributes); |
| 6757 | if (acl) | 6803 | if (acl) |
diff --git a/src/w32term.c b/src/w32term.c index 4eb5045fc5b..f515f5604d6 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -4701,6 +4701,10 @@ static short temp_buffer[100]; | |||
| 4701 | /* Temporarily store lead byte of DBCS input sequences. */ | 4701 | /* Temporarily store lead byte of DBCS input sequences. */ |
| 4702 | static char dbcs_lead = 0; | 4702 | static char dbcs_lead = 0; |
| 4703 | 4703 | ||
| 4704 | /* Temporarily store pending UTF-16 high surrogate unit and the modifiers. */ | ||
| 4705 | static unsigned short utf16_high; | ||
| 4706 | static DWORD utf16_high_modifiers; | ||
| 4707 | |||
| 4704 | /** | 4708 | /** |
| 4705 | mouse_or_wdesc_frame: When not dropping and the mouse was grabbed | 4709 | mouse_or_wdesc_frame: When not dropping and the mouse was grabbed |
| 4706 | for DPYINFO, return the frame where the mouse was seen last. If | 4710 | for DPYINFO, return the frame where the mouse was seen last. If |
| @@ -4912,9 +4916,45 @@ w32_read_socket (struct terminal *terminal, | |||
| 4912 | XSETFRAME (inev.frame_or_window, f); | 4916 | XSETFRAME (inev.frame_or_window, f); |
| 4913 | inev.timestamp = msg.msg.time; | 4917 | inev.timestamp = msg.msg.time; |
| 4914 | 4918 | ||
| 4919 | if (utf16_high | ||
| 4920 | && (msg.msg.message != WM_UNICHAR | ||
| 4921 | || UTF_16_HIGH_SURROGATE_P (msg.msg.wParam))) | ||
| 4922 | { | ||
| 4923 | /* Flush the pending high surrogate if the low one | ||
| 4924 | isn't coming. (This should never happen, but I | ||
| 4925 | have paranoia about this stuff.) */ | ||
| 4926 | struct input_event inev1; | ||
| 4927 | inev1.modifiers = utf16_high_modifiers; | ||
| 4928 | inev1.code = utf16_high; | ||
| 4929 | inev1.timestamp = inev.timestamp; | ||
| 4930 | inev1.arg = Qnil; | ||
| 4931 | kbd_buffer_store_event_hold (&inev1, hold_quit); | ||
| 4932 | utf16_high = 0; | ||
| 4933 | utf16_high_modifiers = 0; | ||
| 4934 | } | ||
| 4935 | |||
| 4915 | if (msg.msg.message == WM_UNICHAR) | 4936 | if (msg.msg.message == WM_UNICHAR) |
| 4916 | { | 4937 | { |
| 4917 | inev.code = msg.msg.wParam; | 4938 | /* Handle UTF-16 encoded codepoint above the BMP. |
| 4939 | This is needed to support Emoji input from input | ||
| 4940 | panel popped up by "Win+." shortcut. */ | ||
| 4941 | if (UTF_16_HIGH_SURROGATE_P (msg.msg.wParam)) | ||
| 4942 | { | ||
| 4943 | utf16_high = msg.msg.wParam; | ||
| 4944 | utf16_high_modifiers = inev.modifiers; | ||
| 4945 | inev.kind = NO_EVENT; | ||
| 4946 | break; | ||
| 4947 | } | ||
| 4948 | else if (UTF_16_LOW_SURROGATE_P (msg.msg.wParam) | ||
| 4949 | && utf16_high) | ||
| 4950 | { | ||
| 4951 | inev.code = surrogates_to_codepoint (msg.msg.wParam, | ||
| 4952 | utf16_high); | ||
| 4953 | utf16_high = 0; | ||
| 4954 | utf16_high_modifiers = 0; | ||
| 4955 | } | ||
| 4956 | else | ||
| 4957 | inev.code = msg.msg.wParam; | ||
| 4918 | } | 4958 | } |
| 4919 | else if (msg.msg.wParam < 256) | 4959 | else if (msg.msg.wParam < 256) |
| 4920 | { | 4960 | { |
diff --git a/src/xdisp.c b/src/xdisp.c index c2aa314c1ad..3c594b54add 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -31441,6 +31441,10 @@ show_mouse_face (Mouse_HLInfo *hlinfo, enum draw_glyphs_face draw) | |||
| 31441 | struct window *w = XWINDOW (hlinfo->mouse_face_window); | 31441 | struct window *w = XWINDOW (hlinfo->mouse_face_window); |
| 31442 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | 31442 | struct frame *f = XFRAME (WINDOW_FRAME (w)); |
| 31443 | 31443 | ||
| 31444 | /* Don't bother doing anything if we are on a wrong frame. */ | ||
| 31445 | if (f != hlinfo->mouse_face_mouse_frame) | ||
| 31446 | return; | ||
| 31447 | |||
| 31444 | if (/* If window is in the process of being destroyed, don't bother | 31448 | if (/* If window is in the process of being destroyed, don't bother |
| 31445 | to do anything. */ | 31449 | to do anything. */ |
| 31446 | w->current_matrix != NULL | 31450 | w->current_matrix != NULL |