commit 0d55c44a9a00da3b8542e92586654adeb2bcf228 (HEAD, refs/remotes/origin/master) Author: Paul Eggert Date: Sat Mar 4 23:14:52 2017 -0800 Compare and round more carefully * etc/NEWS: Document this. * src/data.c (store_symval_forwarding): * src/sound.c (parse_sound): Do not botch NaN comparison. * src/data.c (cons_to_unsigned, cons_to_signed): Signal an error if a floating-point arg is not integral. * src/data.c (cons_to_unsigned, cons_to_signed): * src/fileio.c (file_offset): Use simpler overflow check. * src/dbusbind.c (xd_extract_signed, xd_extract_unsigned): Avoid rounding error in overflow check. (Fcar_less_than_car): Use arithcompare directly. * test/src/charset-tests.el: New file. diff --git a/etc/NEWS b/etc/NEWS index 9c995930fb..fe02236ecc 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -915,6 +915,11 @@ Emacs integers with %e, %f, or %g conversions. For example, on these hosts (eql N (string-to-number (format "%.0f" N))) now returns t for all Emacs integers N. +--- +** Calls that accept floating-point integers (for use on hosts with +limited integer range) now signal an error if arguments are not +integral. For example (decode-char 'ascii 0.5) now signals an error. + +++ ** The new function 'char-from-name' converts a Unicode name string to the corresponding character code. diff --git a/src/data.c b/src/data.c index 88d86697e4..66f4c9c738 100644 --- a/src/data.c +++ b/src/data.c @@ -1110,10 +1110,8 @@ store_symval_forwarding (union Lisp_Fwd *valcontents, register Lisp_Object newva else if ((prop = Fget (predicate, Qrange), !NILP (prop))) { Lisp_Object min = XCAR (prop), max = XCDR (prop); - - if (!NUMBERP (newval) - || !NILP (arithcompare (newval, min, ARITH_LESS)) - || !NILP (arithcompare (newval, max, ARITH_GRTR))) + if (! NUMBERP (newval) + || NILP (CALLN (Fleq, min, newval, max))) wrong_range (min, max, newval); } else if (FUNCTIONP (predicate)) @@ -2554,12 +2552,13 @@ uintbig_to_lisp (uintmax_t i) } /* Convert the cons-of-integers, integer, or float value C to an - unsigned value with maximum value MAX. Signal an error if C does not - have a valid format or is out of range. */ + unsigned value with maximum value MAX, where MAX is one less than a + power of 2. Signal an error if C does not have a valid format or + is out of range. */ uintmax_t cons_to_unsigned (Lisp_Object c, uintmax_t max) { - bool valid = 0; + bool valid = false; uintmax_t val; if (INTEGERP (c)) { @@ -2569,11 +2568,10 @@ cons_to_unsigned (Lisp_Object c, uintmax_t max) else if (FLOATP (c)) { double d = XFLOAT_DATA (c); - if (0 <= d - && d < (max == UINTMAX_MAX ? (double) UINTMAX_MAX + 1 : max + 1)) + if (0 <= d && d < 1.0 + max) { val = d; - valid = 1; + valid = val == d; } } else if (CONSP (c) && NATNUMP (XCAR (c))) @@ -2587,7 +2585,7 @@ cons_to_unsigned (Lisp_Object c, uintmax_t max) { uintmax_t mid = XFASTINT (XCAR (rest)); val = top << 24 << 16 | mid << 16 | XFASTINT (XCDR (rest)); - valid = 1; + valid = true; } else if (top <= UINTMAX_MAX >> 16) { @@ -2596,37 +2594,38 @@ cons_to_unsigned (Lisp_Object c, uintmax_t max) if (NATNUMP (rest) && XFASTINT (rest) < 1 << 16) { val = top << 16 | XFASTINT (rest); - valid = 1; + valid = true; } } } if (! (valid && val <= max)) - error ("Not an in-range integer, float, or cons of integers"); + error ("Not an in-range integer, integral float, or cons of integers"); return val; } /* Convert the cons-of-integers, integer, or float value C to a signed - value with extrema MIN and MAX. Signal an error if C does not have - a valid format or is out of range. */ + value with extrema MIN and MAX. MAX should be one less than a + power of 2, and MIN should be zero or the negative of a power of 2. + Signal an error if C does not have a valid format or is out of + range. */ intmax_t cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) { - bool valid = 0; + bool valid = false; intmax_t val; if (INTEGERP (c)) { val = XINT (c); - valid = 1; + valid = true; } else if (FLOATP (c)) { double d = XFLOAT_DATA (c); - if (min <= d - && d < (max == INTMAX_MAX ? (double) INTMAX_MAX + 1 : max + 1)) + if (min <= d && d < 1.0 + max) { val = d; - valid = 1; + valid = val == d; } } else if (CONSP (c) && INTEGERP (XCAR (c))) @@ -2640,7 +2639,7 @@ cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) { intmax_t mid = XFASTINT (XCAR (rest)); val = top << 24 << 16 | mid << 16 | XFASTINT (XCDR (rest)); - valid = 1; + valid = true; } else if (INTMAX_MIN >> 16 <= top && top <= INTMAX_MAX >> 16) { @@ -2649,13 +2648,13 @@ cons_to_signed (Lisp_Object c, intmax_t min, intmax_t max) if (NATNUMP (rest) && XFASTINT (rest) < 1 << 16) { val = top << 16 | XFASTINT (rest); - valid = 1; + valid = true; } } } if (! (valid && min <= val && val <= max)) - error ("Not an in-range integer, float, or cons of integers"); + error ("Not an in-range integer, integral float, or cons of integers"); return val; } diff --git a/src/dbusbind.c b/src/dbusbind.c index e7c3251c14..d2460fd886 100644 --- a/src/dbusbind.c +++ b/src/dbusbind.c @@ -526,7 +526,7 @@ xd_extract_signed (Lisp_Object x, intmax_t lo, intmax_t hi) else { double d = XFLOAT_DATA (x); - if (lo <= d && d <= hi) + if (lo <= d && d < 1.0 + hi) { intmax_t n = d; if (n == d) @@ -554,7 +554,7 @@ xd_extract_unsigned (Lisp_Object x, uintmax_t hi) else { double d = XFLOAT_DATA (x); - if (0 <= d && d <= hi) + if (0 <= d && d < 1.0 + hi) { uintmax_t n = d; if (n == d) diff --git a/src/fileio.c b/src/fileio.c index 3840062379..acbf76e0d8 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -3426,11 +3426,12 @@ file_offset (Lisp_Object val) if (FLOATP (val)) { double v = XFLOAT_DATA (val); - if (0 <= v - && (sizeof (off_t) < sizeof v - ? v <= TYPE_MAXIMUM (off_t) - : v < TYPE_MAXIMUM (off_t))) - return v; + if (0 <= v && v < 1.0 + TYPE_MAXIMUM (off_t)) + { + off_t o = v; + if (o == v) + return o; + } } wrong_type_argument (intern ("file-offset"), val); @@ -5163,7 +5164,7 @@ DEFUN ("car-less-than-car", Fcar_less_than_car, Scar_less_than_car, 2, 2, 0, doc: /* Return t if (car A) is numerically less than (car B). */) (Lisp_Object a, Lisp_Object b) { - return CALLN (Flss, Fcar (a), Fcar (b)); + return arithcompare (Fcar (a), Fcar (b), ARITH_LESS); } /* Build the complete list of annotations appropriate for writing out diff --git a/src/sound.c b/src/sound.c index 84754165db..4714ac1796 100644 --- a/src/sound.c +++ b/src/sound.c @@ -387,14 +387,14 @@ parse_sound (Lisp_Object sound, Lisp_Object *attrs) { if (INTEGERP (attrs[SOUND_VOLUME])) { - if (XINT (attrs[SOUND_VOLUME]) < 0 - || XINT (attrs[SOUND_VOLUME]) > 100) + EMACS_INT volume = XINT (attrs[SOUND_VOLUME]); + if (! (0 <= volume && volume <= 100)) return 0; } else if (FLOATP (attrs[SOUND_VOLUME])) { - if (XFLOAT_DATA (attrs[SOUND_VOLUME]) < 0 - || XFLOAT_DATA (attrs[SOUND_VOLUME]) > 1) + double volume = XFLOAT_DATA (attrs[SOUND_VOLUME]); + if (! (0 <= volume && volume <= 1)) return 0; } else diff --git a/test/src/charset-tests.el b/test/src/charset-tests.el new file mode 100644 index 0000000000..515a4eafe1 --- /dev/null +++ b/test/src/charset-tests.el @@ -0,0 +1,26 @@ +;;; charset-tests.el --- Tests for charset.c + +;; Copyright 2017 Free Software Foundation, Inc. + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Code: + +(require 'ert) + +(ert-deftest charset-decode-char () + "Test decode-char." + (should-error (decode-char 'ascii 0.5))) + +(provide 'charset-tests) commit 44e7ee2e356452139156e8175c46f646835d27ff Author: Paul Eggert Date: Sat Mar 4 23:14:52 2017 -0800 Fewer rounding errors with (format "%f" fixnum) * etc/NEWS: Document this. * src/editfns.c (styled_format): When formatting integers via a floating-point format, use long double instead of double conversion, if long double’s extra precision might help. diff --git a/etc/NEWS b/etc/NEWS index a8db54c51e..9c995930fb 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -907,6 +907,14 @@ compares their numerical values. According to this predicate, due to internal rounding errors. For example, (< most-positive-fixnum (+ 1.0 most-positive-fixnum)) now correctly returns t on 64-bit hosts. +--- +** On hosts like GNU/Linux x86-64 where a 'long double' fraction +contains at least EMACS_INT_WIDTH - 3 bits, 'format' no longer returns +incorrect answers due to internal rounding errors when formatting +Emacs integers with %e, %f, or %g conversions. For example, on these +hosts (eql N (string-to-number (format "%.0f" N))) now returns t for +all Emacs integers N. + +++ ** The new function 'char-from-name' converts a Unicode name string to the corresponding character code. diff --git a/src/editfns.c b/src/editfns.c index db9ad06690..612893c377 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -4145,6 +4145,9 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) } } + bool float_conversion + = conversion == 'e' || conversion == 'f' || conversion == 'g'; + if (conversion == 's') { /* handle case (precision[n] >= 0) */ @@ -4229,8 +4232,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) } } else if (! (conversion == 'c' || conversion == 'd' - || conversion == 'e' || conversion == 'f' - || conversion == 'g' || conversion == 'i' + || float_conversion || conversion == 'i' || conversion == 'o' || conversion == 'x' || conversion == 'X')) error ("Invalid format operation %%%c", @@ -4242,11 +4244,22 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) { enum { + /* Lower bound on the number of bits per + base-FLT_RADIX digit. */ + DIG_BITS_LBOUND = FLT_RADIX < 16 ? 1 : 4, + + /* 1 if integers should be formatted as long doubles, + because they may be so large that there is a rounding + error when converting them to double, and long doubles + are wider than doubles. */ + INT_AS_LDBL = (DIG_BITS_LBOUND * DBL_MANT_DIG < FIXNUM_BITS - 1 + && DBL_MANT_DIG < LDBL_MANT_DIG), + /* Maximum precision for a %f conversion such that the trailing output digit might be nonzero. Any precision larger than this will not yield useful information. */ USEFUL_PRECISION_MAX = - ((1 - DBL_MIN_EXP) + ((1 - LDBL_MIN_EXP) * (FLT_RADIX == 2 || FLT_RADIX == 10 ? 1 : FLT_RADIX == 16 ? 4 : -1)), @@ -4255,7 +4268,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) precision is no more than USEFUL_PRECISION_MAX. On all practical hosts, %f is the worst case. */ SPRINTF_BUFSIZE = - sizeof "-." + (DBL_MAX_10_EXP + 1) + USEFUL_PRECISION_MAX, + sizeof "-." + (LDBL_MAX_10_EXP + 1) + USEFUL_PRECISION_MAX, /* Length of pM (that is, of pMd without the trailing "d"). */ @@ -4269,9 +4282,10 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) /* Create the copy of the conversion specification, with any width and precision removed, with ".*" inserted, + with "L" possibly inserted for floating-point formats, and with pM inserted for integer formats. At most two flags F can be specified at once. */ - char convspec[sizeof "%FF.*d" + pMlen]; + char convspec[sizeof "%FF.*d" + max (INT_AS_LDBL, pMlen)]; { char *f = convspec; *f++ = '%'; @@ -4281,9 +4295,15 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) *f = '#'; f += sharp_flag; *f++ = '.'; *f++ = '*'; - if (conversion == 'd' || conversion == 'i' - || conversion == 'o' || conversion == 'x' - || conversion == 'X') + if (float_conversion) + { + if (INT_AS_LDBL) + { + *f = 'L'; + f += INTEGERP (args[n]); + } + } + else if (conversion != 'c') { memcpy (f, pMd, pMlen); f += pMlen; @@ -4310,9 +4330,20 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) not suitable here. */ char sprintf_buf[SPRINTF_BUFSIZE]; ptrdiff_t sprintf_bytes; - if (conversion == 'e' || conversion == 'f' || conversion == 'g') - sprintf_bytes = sprintf (sprintf_buf, convspec, prec, - XFLOATINT (args[n])); + if (float_conversion) + { + if (INT_AS_LDBL && INTEGERP (args[n])) + { + /* Although long double may have a rounding error if + DIG_BITS_LBOUND * LDBL_MANT_DIG < FIXNUM_BITS - 1, + it is more accurate than plain 'double'. */ + long double x = XINT (args[n]); + sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); + } + else + sprintf_bytes = sprintf (sprintf_buf, convspec, prec, + XFLOATINT (args[n])); + } else if (conversion == 'c') { /* Don't use sprintf here, as it might mishandle prec. */ @@ -4374,8 +4405,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) uintmax_t leading_zeros = 0, trailing_zeros = 0; if (excess_precision) { - if (conversion == 'e' || conversion == 'f' - || conversion == 'g') + if (float_conversion) { if ((conversion == 'g' && ! sharp_flag) || ! ('0' <= sprintf_buf[sprintf_bytes - 1] commit 207de3303076bff1bb392bd407fee0dea892fe40 Author: Paul Eggert Date: Sat Mar 4 23:14:51 2017 -0800 * src/floatfns.c (Fftruncate): Simplify via emacs_trunc. diff --git a/src/floatfns.c b/src/floatfns.c index 94da22a3ba..9ae810669e 100644 --- a/src/floatfns.c +++ b/src/floatfns.c @@ -534,10 +534,7 @@ Rounds the value toward zero. */) (Lisp_Object arg) { double d = extract_float (arg); - if (d >= 0.0) - d = floor (d); - else - d = ceil (d); + d = emacs_trunc (d); return make_float (d); } commit 1af7410a2333fdadc68edb9d4890434d75ebaf5e Author: Paul Eggert Date: Sat Mar 4 23:14:51 2017 -0800 * src/editfns.c (styled_format): Omit unnecessary code for "%0d" etc. diff --git a/src/editfns.c b/src/editfns.c index d50ea83141..db9ad06690 100644 --- a/src/editfns.c +++ b/src/editfns.c @@ -4270,16 +4270,15 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) /* Create the copy of the conversion specification, with any width and precision removed, with ".*" inserted, and with pM inserted for integer formats. - At most three flags F can be specified at once. */ - char convspec[sizeof "%FFF.*d" + pMlen]; + At most two flags F can be specified at once. */ + char convspec[sizeof "%FF.*d" + pMlen]; { char *f = convspec; *f++ = '%'; - /* MINUS_FLAG is dealt with later. */ + /* MINUS_FLAG and ZERO_FLAG are dealt with later. */ *f = '+'; f += plus_flag; *f = ' '; f += space_flag; *f = '#'; f += sharp_flag; - *f = '0'; f += zero_flag; *f++ = '.'; *f++ = '*'; if (conversion == 'd' || conversion == 'i' commit df0276b62f3df57cde3c049ca613a366c675209b Author: Michael Albinus Date: Sat Mar 4 20:32:39 2017 +0100 ; Fix typo in etc/PROBLEMS diff --git a/etc/PROBLEMS b/etc/PROBLEMS index 43f6617882..b892320101 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -741,7 +741,7 @@ instance if you are editing a text with a lot of math symbols, then installing a font like 'Symbola' should solve this problem. ** Emacs running on GNU/Linux system with the m17n library Ver.1.7.1 or the -earlier vesion has a problem with rendering Bengali script. +earlier version has a problem with rendering Bengali script. The problem can be fixed by installing the newer version of the m17n library (if any), or by following this procedure: commit c26005455bfa9dd4851d59c399615e523f80c5ad Author: Eli Zaretskii Date: Sat Mar 4 17:37:53 2017 +0200 Fix header shown by Info 'L' command * lisp/info.el (Info-history-find-node): A better heading for the list of visited nodes. (Bug#25876) diff --git a/lisp/info.el b/lisp/info.el index 5f4ae5f0b0..a023080c8d 100644 --- a/lisp/info.el +++ b/lisp/info.el @@ -2361,8 +2361,8 @@ If SAME-FILE is non-nil, do not move to a different Info file." "History-specific implementation of `Info-find-node-2'." (insert (format "\n\^_\nFile: %s, Node: %s, Up: (dir)\n\n" (or filename Info-current-file) nodename)) - (insert "Recently Visited Nodes\n") - (insert "**********************\n\n") + (insert "History of Visited Nodes\n") + (insert "************************\n\n") (insert "* Menu:\n\n") (let ((hl (remove '("*History*" "Top") Info-history-list))) (while hl commit 00f8369bbdd36b5b54249f2a729c8c93f632b440 Author: K. Handa Date: Sat Mar 4 22:56:50 2017 +0900 Add a section about incorrect Bengali rendering. diff --git a/etc/PROBLEMS b/etc/PROBLEMS index d033c7279b..43f6617882 100644 --- a/etc/PROBLEMS +++ b/etc/PROBLEMS @@ -740,6 +740,36 @@ The solution is to install the appropriate fonts on your machine. For instance if you are editing a text with a lot of math symbols, then installing a font like 'Symbola' should solve this problem. +** Emacs running on GNU/Linux system with the m17n library Ver.1.7.1 or the +earlier vesion has a problem with rendering Bengali script. + +The problem can be fixed by installing the newer version of the m17n +library (if any), or by following this procedure: + +1. Locate the file BENG-OTF.flt installed on your system as part of the +m17n library. Usually it is under the directory /usr/share/m17n. + +2. Apply the following patch to BENG-OTF.flt + +------------------------------------------------------------ +diff --git a/FLT/BENG-OTF.flt b/FLT/BENG-OTF.flt +index 45cc554..0cc5e76 100644 +--- a/FLT/BENG-OTF.flt ++++ b/FLT/BENG-OTF.flt +@@ -232,7 +232,7 @@ + (lang-forms + (cond + ("(.H)J" (1 :otf=beng=half+)) +- (".H" :otf=beng=blwf,half,vatu+) ++ (".+H" :otf=beng=blwf,half,vatu+) + ("." =))) + + (post +------------------------------------------------------------ + +If you can't modify that file directly, copy it to the directory +~/.m17n.d/ (create it if it doesn't exist), and apply the patch. + * Internationalization problems ** M-{ does not work on a Spanish PC keyboard. commit f2bd2c1e6476acc71e71f6cb2a1c56c5edd900ba Author: Eli Zaretskii Date: Sat Mar 4 13:23:52 2017 +0200 Fix minor problems with loaddefs autogeneration * admin/ldefs-clean.el (ldefs-clean): Bind coding-system-for-read and coding-system-for-write, to produce a UTF-8 file with Unix EOLs on MS-Windows. * lisp/ldefs-boot-manual.el (image-type): Add autoload cookie. diff --git a/admin/ldefs-clean.el b/admin/ldefs-clean.el index 91512b4bbb..33bc9e529f 100644 --- a/admin/ldefs-clean.el +++ b/admin/ldefs-clean.el @@ -57,6 +57,9 @@ (defun ldefs-clean () - (find-file "../lisp/ldefs-boot-auto.temp") + ;; Remove CR characters produced on MS-DOS/MS-Windows systems. + (let ((coding-system-for-read 'utf-8-dos)) + (find-file "../lisp/ldefs-boot-auto.temp")) (ldefs-clean-up) - (write-file "ldefs-boot-auto.el")) + (let ((coding-system-for-write 'utf-8-unix)) + (write-file "ldefs-boot-auto.el"))) diff --git a/lisp/ldefs-boot-manual.el b/lisp/ldefs-boot-manual.el index 2f6e3fd209..06b9738d5e 100644 --- a/lisp/ldefs-boot-manual.el +++ b/lisp/ldefs-boot-manual.el @@ -16,6 +16,9 @@ (autoload 'dos-convert-standard-filename "dos-fns.el" nil nil nil) (autoload 'w32-convert-standard-filename "w32-fns.el" nil nil nil) +;; This is needed on MS-Windows only, and won't be in +;; ldefs-boot-auto.el on other platforms. +(autoload 'image-type "image" nil nil nil) (load "ldefs-boot-auto.el") commit 43e792cd7f752cc0cff5845c5399cab1272670fa Author: David Bremner Date: Sat Mar 4 12:19:32 2017 +0200 Fix issues with dedicated windows in shr.el * lisp/net/shr.el (shr-pixel-buffer-width, shr-render-td-1): Make the window not dedicated, to avoid errors if it was, before setting its buffer temporarily. (Bug#25828) Copyright-paperwork-exempt: yes diff --git a/lisp/net/shr.el b/lisp/net/shr.el index b7c4828849..6ec647e802 100644 --- a/lisp/net/shr.el +++ b/lisp/net/shr.el @@ -2228,6 +2228,9 @@ flags that control whether to collect or render objects." (if (get-buffer-window) (car (window-text-pixel-size nil (point-min) (point-max))) (save-window-excursion + ;; Avoid errors if the selected window is a dedicated one, + ;; and they just want to insert a document into it. + (set-window-dedicated-p nil nil) (set-window-buffer nil (current-buffer)) (car (window-text-pixel-size nil (point-min) (point-max))))))) @@ -2271,6 +2274,9 @@ flags that control whether to collect or render objects." (shr-indentation 0)) (shr-descend dom)) (save-window-excursion + ;; Avoid errors if the selected window is a dedicated one, + ;; and they just want to insert a document into it. + (set-window-dedicated-p nil nil) (set-window-buffer nil (current-buffer)) (unless fill (setq natural-width