changeset 10038:7cf4e210cf3c v7.4.2291

commit https://github.com/vim/vim/commit/04186095346daa60e82e981dad114de2b641d672 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Aug 29 21:55:35 2016 +0200 patch 7.4.2291 Problem: printf() handles floats wrong when there is a sign. Solution: Fix placing the sign. Add tests. (Dominique Pelle)
author Christian Brabandt <cb@256bit.org>
date Mon, 29 Aug 2016 22:00:07 +0200
parents f359ee3f123e
children b0a7d1e90362
files runtime/doc/eval.txt src/message.c src/testdir/test_expr.vim src/version.c
diffstat 4 files changed, 107 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt*	For Vim version 7.4.  Last change: 2016 Aug 28
+*eval.txt*	For Vim version 7.4.  Last change: 2016 Aug 29
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -643,7 +643,7 @@ 2. Expression syntax					*expression-syn
 
 Expression syntax summary, from least to most significant:
 
-|expr1| expr2 ? expr1 : expr1	if-then-else
+|expr1|   expr2 ? expr1 : expr1	if-then-else
 
 |expr2|	expr3 || expr3 ..	logical OR
 
@@ -736,7 +736,9 @@ use in a variable such as "a:1".
 expr2 and expr3						*expr2* *expr3*
 ---------------
 
-					*expr-barbar* *expr-&&*
+expr3 || expr3 ..	logical OR		*expr-barbar*
+expr4 && expr4 ..	logical AND		*expr-&&*
+
 The "||" and "&&" operators take one argument on each side.  The arguments
 are (converted to) Numbers.  The result is:
 
@@ -1981,7 +1983,7 @@ assert_notmatch({pat}, {text} [, {msg}])
 assert_true({actual} [, {msg}])          none  assert {actual} is true
 asin({expr})			Float	arc sine of {expr}
 atan({expr})			Float	arc tangent of {expr}
-atan2({expr}, {expr})		Float	arc tangent of {expr1} / {expr2}
+atan2({expr1}, {expr2})		Float	arc tangent of {expr1} / {expr2}
 browse({save}, {title}, {initdir}, {default})
 				String	put up a file requester
 browsedir({title}, {initdir})	String	put up a directory requester
@@ -5905,9 +5907,10 @@ printf({fmt}, {expr1} ...)				*printf()*
 		  %X	hex number using upper case letters
 		  %o	octal number
 		  %08b	binary number padded with zeros to at least 8 chars
-		  %f	floating point number in the form 123.456
-		  %e	floating point number in the form 1.234e3
-		  %E	floating point number in the form 1.234E3
+		  %f	floating point number as 12.23, inf, -inf or nan
+		  %F	floating point number as 12.23, INF, -INF or NAN
+		  %e	floating point number as 1.23e3, inf, -inf or nan
+		  %E	floating point number as 1.23E3, INF, -INF or NAN
 		  %g	floating point number, as %f or %e depending on value
 		  %G	floating point number, as %f or %E depending on value
 		  %%	the % character itself
@@ -6039,8 +6042,9 @@ printf({fmt}, {expr1} ...)				*printf()*
 			digits after the decimal point.  When the precision is
 			zero the decimal point is omitted.  When the precision
 			is not specified 6 is used.  A really big number
-			(out of range or dividing by zero) results in "inf".
-			"0.0 / 0.0" results in "nan".
+			(out of range or dividing by zero) results in "inf"
+                        or "-inf" with %f (INF or -INF with %F).
+                        "0.0 / 0.0" results in "nan" with %f (NAN with %F).
 			Example: >
 				echo printf("%.2f", 12.115)
 <				12.12
@@ -7507,7 +7511,7 @@ system({expr} [, {input}])				*system()*
 
 		Pipes are not used, the 'shelltemp' option is not used.
 
-		When prepended by |:silent| the shell will not be set to
+		When prepended by |:silent| the terminal will not be set to
 		cooked mode.  This is meant to be used for commands that do
 		not need the user to type.  It avoids stray characters showing
 		up on the screen which require |CTRL-L| to remove. >
--- a/src/message.c
+++ b/src/message.c
@@ -4030,7 +4030,7 @@ infinity_str(int positive,
  * with flags: '-', '+', ' ', '0' and '#'.
  * An asterisk is supported for field width as well as precision.
  *
- * Limited support for floating point was added: 'f', 'e', 'E', 'g', 'G'.
+ * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'.
  *
  * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int)
  * are supported.
@@ -4286,7 +4286,6 @@ vim_vsnprintf(
 		case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
 		case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
 		case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
-		case 'F': fmt_spec = 'f'; break;
 		default: break;
 	    }
 
@@ -4715,6 +4714,7 @@ vim_vsnprintf(
 
 # ifdef FEAT_FLOAT
 	    case 'f':
+	    case 'F':
 	    case 'e':
 	    case 'E':
 	    case 'g':
@@ -4740,13 +4740,13 @@ vim_vsnprintf(
 			 * "1.0" as "1", we don't want that. */
 			if ((abs_f >= 0.001 && abs_f < 10000000.0)
 							      || abs_f == 0.0)
-			    fmt_spec = 'f';
+			    fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
 			else
 			    fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
 			remove_trailing_zeroes = TRUE;
 		    }
 
-		    if (fmt_spec == 'f' &&
+		    if ((fmt_spec == 'f' || fmt_spec == 'F') &&
 #  ifdef VAX
 			    abs_f > 1.0e38
 #  else
@@ -4762,23 +4762,6 @@ vim_vsnprintf(
 		    }
 		    else
 		    {
-			format[0] = '%';
-			l = 1;
-			if (precision_specified)
-			{
-			    size_t max_prec = TMP_LEN - 10;
-
-			    /* Make sure we don't get more digits than we
-			     * have room for. */
-			    if (fmt_spec == 'f' && abs_f > 1.0)
-				max_prec -= (size_t)log10(abs_f);
-			    if (precision > max_prec)
-				precision = max_prec;
-			    l += sprintf(format + 1, ".%d", (int)precision);
-			}
-			format[l] = fmt_spec;
-			format[l + 1] = NUL;
-
 			if (isnan(f))
 			{
 			    /* Not a number: nan or NAN */
@@ -4795,8 +4778,30 @@ vim_vsnprintf(
 			    zero_padding = 0;
 			}
 			else
+                        {
 			    /* Regular float number */
+			    format[0] = '%';
+			    l = 1;
+			    if (force_sign)
+				format[l++] = space_for_positive ? ' ' : '+';
+			    if (precision_specified)
+			    {
+				size_t max_prec = TMP_LEN - 10;
+
+				/* Make sure we don't get more digits than we
+				 * have room for. */
+				if ((fmt_spec == 'f' || fmt_spec == 'F')
+								&& abs_f > 1.0)
+				    max_prec -= (size_t)log10(abs_f);
+				if (precision > max_prec)
+				    precision = max_prec;
+				l += sprintf(format + l, ".%d", (int)precision);
+			    }
+			    format[l] = fmt_spec;
+			    format[l + 1] = NUL;
+
 			    str_arg_l = sprintf(tmp, format, f);
+                        }
 
 			if (remove_trailing_zeroes)
 			{
@@ -4804,7 +4809,7 @@ vim_vsnprintf(
 			    char *tp;
 
 			    /* Using %g or %G: remove superfluous zeroes. */
-			    if (fmt_spec == 'f')
+			    if (fmt_spec == 'f' || fmt_spec == 'F')
 				tp = tmp + str_arg_l - 1;
 			    else
 			    {
@@ -4861,6 +4866,13 @@ vim_vsnprintf(
 			    }
 			}
 		    }
+		    if (zero_padding && min_field_width > str_arg_l
+					      && (tmp[0] == '-' || force_sign))
+		    {
+			/* padding 0's should be inserted after the sign */
+			number_of_zeros_to_pad = min_field_width - str_arg_l;
+			zero_padding_insertion_ind = 1;
+		    }
 		    str_arg = tmp;
 		    break;
 		}
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -162,21 +162,44 @@ function Test_printf_misc()
   call assert_equal('  +123', printf('%+6d', 123))
   call assert_equal('   123', printf('% 6d', 123))
   call assert_equal('  -123', printf('% 6d', -123))
+
+  " Test left adjusted.
+  call assert_equal('123   ', printf('%-6d', 123))
   call assert_equal('+123  ', printf('%-+6d', 123))
   call assert_equal(' 123  ', printf('%- 6d', 123))
   call assert_equal('-123  ', printf('%- 6d', -123))
 
+  call assert_equal('  00123', printf('%7.5d', 123))
+  call assert_equal(' -00123', printf('%7.5d', -123))
+  call assert_equal(' +00123', printf('%+7.5d', 123))
+  " Precision field should not be used when combined with %0
+  call assert_equal('  00123', printf('%07.5d', 123))
+  call assert_equal(' -00123', printf('%07.5d', -123))
+
+  call assert_equal('  123', printf('%*d', 5, 123))
+  call assert_equal('123  ', printf('%*d', -5, 123))
   call assert_equal('00123', printf('%.*d', 5, 123))
   call assert_equal('  123', printf('% *d', 5, 123))
   call assert_equal(' +123', printf('%+ *d', 5, 123))
 
-  call assert_equal('123  ', printf('%-5d', 123))
+  " Simple quote (thousand grouping char) is ignored.
+  call assert_equal('+00123456', printf("%+'09d", 123456))
+
+  " Unrecognized format specifier kept as-is.
+  call assert_equal('_123', printf("%_%d", 123))
+
+  " Test alternate forms.
   call assert_equal('0x7b', printf('%#x', 123))
   call assert_equal('0X7B', printf('%#X', 123))
   call assert_equal('0173', printf('%#o', 123))
   call assert_equal('0173', printf('%#O', 123))
   call assert_equal('abc', printf('%#s', 'abc'))
   call assert_equal('abc', printf('%#S', 'abc'))
+  call assert_equal('  0173', printf('%#6o', 123))
+  call assert_equal(' 00173', printf('%#6.5o', 123))
+  call assert_equal('  0173', printf('%#6.2o', 123))
+  call assert_equal('  0173', printf('%#6.2o', 123))
+  call assert_equal('0173', printf('%#2.2o', 123))
 
   call assert_equal(' 00123', printf('%6.5d', 123))
   call assert_equal(' 0007b', printf('%6.5x', 123))
@@ -201,6 +224,7 @@ endfunc
 
 function Test_printf_float()
   if has('float')
+    call assert_equal('1.000000', printf('%f', 1))
     call assert_equal('1.230000', printf('%f', 1.23))
     call assert_equal('1.230000', printf('%F', 1.23))
     call assert_equal('9999999.9', printf('%g', 9999999.9))
@@ -215,10 +239,31 @@ function Test_printf_float()
     call assert_equal('  0.33', printf('%6.2f', 1.0/3.0))
     call assert_equal(' -0.33', printf('%6.2f', -1.0/3.0))
     call assert_equal('000.33', printf('%06.2f', 1.0/3.0))
-    " FIXME: call assert_equal('-00.33', printf('%06.2f', -1.0/3.0))
-    " FIXME: call assert_equal('-00.33', printf('%+06.2f', -1.0/3.0))
-    " FIXME: call assert_equal('+00.33', printf('%+06.2f', 1.0/3.0))
-    " FIXME: call assert_equal(' 00.33', printf('% 06.2f', 1.0/3.0))
+    call assert_equal('-00.33', printf('%06.2f', -1.0/3.0))
+    call assert_equal('-00.33', printf('%+06.2f', -1.0/3.0))
+    call assert_equal('+00.33', printf('%+06.2f', 1.0/3.0))
+    call assert_equal(' 00.33', printf('% 06.2f', 1.0/3.0))
+    call assert_equal('000.33', printf('%06.2g', 1.0/3.0))
+    call assert_equal('-00.33', printf('%06.2g', -1.0/3.0))
+    call assert_equal('0.33', printf('%3.2f', 1.0/3.0))
+    call assert_equal('003.33e-01', printf('%010.2e', 1.0/3.0))
+    call assert_equal(' 03.33e-01', printf('% 010.2e', 1.0/3.0))
+    call assert_equal('+03.33e-01', printf('%+010.2e', 1.0/3.0))
+    call assert_equal('-03.33e-01', printf('%010.2e', -1.0/3.0))
+
+    " When precision is 0, the dot should be omitted.
+    call assert_equal('  2', printf('%3.f', 7.0/3.0))
+    call assert_equal('  2', printf('%3.g', 7.0/3.0))
+    call assert_equal('  2e+00', printf('%7.e', 7.0/3.0))
+
+    " Float zero can be signed.
+    call assert_equal('+0.000000', printf('%+f', 0.0))
+    call assert_equal('0.000000', printf('%f', 1.0/(1.0/0.0)))
+    call assert_equal('-0.000000', printf('%f', 1.0/(-1.0/0.0)))
+    call assert_equal('0.0', printf('%s', 1.0/(1.0/0.0)))
+    call assert_equal('-0.0', printf('%s', 1.0/(-1.0/0.0)))
+    call assert_equal('0.0', printf('%S', 1.0/(1.0/0.0)))
+    call assert_equal('-0.0', printf('%S', 1.0/(-1.0/0.0)))
 
     " Float infinity can be signed.
     call assert_equal('inf', printf('%f', 1.0/0.0))
@@ -227,6 +272,8 @@ function Test_printf_float()
     call assert_equal('-inf', printf('%g', -1.0/0.0))
     call assert_equal('inf', printf('%e', 1.0/0.0))
     call assert_equal('-inf', printf('%e', -1.0/0.0))
+    call assert_equal('INF', printf('%F', 1.0/0.0))
+    call assert_equal('-INF', printf('%F', -1.0/0.0))
     call assert_equal('INF', printf('%E', 1.0/0.0))
     call assert_equal('-INF', printf('%E', -1.0/0.0))
     call assert_equal('INF', printf('%E', 1.0/0.0))
@@ -245,6 +292,9 @@ function Test_printf_float()
     call assert_equal('-inf  ', printf('%-6f', -1.0/0.0))
     call assert_equal('+inf  ', printf('%-+6f', 1.0/0.0))
     call assert_equal(' inf  ', printf('%- 6f', 1.0/0.0))
+    call assert_equal('-INF  ', printf('%-6F', -1.0/0.0))
+    call assert_equal('+INF  ', printf('%-+6F', 1.0/0.0))
+    call assert_equal(' INF  ', printf('%- 6F', 1.0/0.0))
     call assert_equal('INF   ', printf('%-6G', 1.0/0.0))
     call assert_equal('-INF  ', printf('%-6G', -1.0/0.0))
     call assert_equal('INF   ', printf('%-6E', 1.0/0.0))
@@ -252,22 +302,16 @@ function Test_printf_float()
     call assert_equal('inf', printf('%s', 1.0/0.0))
     call assert_equal('-inf', printf('%s', -1.0/0.0))
 
-    " Float zero can be signed.
-    call assert_equal('0.000000', printf('%f', 1.0/(1.0/0.0)))
-    call assert_equal('-0.000000', printf('%f', 1.0/(-1.0/0.0)))
-    call assert_equal('0.0', printf('%s', 1.0/(1.0/0.0)))
-    call assert_equal('-0.0', printf('%s', 1.0/(-1.0/0.0)))
-    call assert_equal('0.0', printf('%S', 1.0/(1.0/0.0)))
-    call assert_equal('-0.0', printf('%S', 1.0/(-1.0/0.0)))
-
     " Float nan (not a number) has no sign.
     call assert_equal('nan', printf('%f', sqrt(-1.0)))
     call assert_equal('nan', printf('%f', 0.0/0.0))
     call assert_equal('nan', printf('%f', -0.0/0.0))
     call assert_equal('nan', printf('%g', 0.0/0.0))
     call assert_equal('nan', printf('%e', 0.0/0.0))
+    call assert_equal('NAN', printf('%F', 0.0/0.0))
     call assert_equal('NAN', printf('%G', 0.0/0.0))
     call assert_equal('NAN', printf('%E', 0.0/0.0))
+    call assert_equal('NAN', printf('%F', -0.0/0.0))
     call assert_equal('NAN', printf('%G', -0.0/0.0))
     call assert_equal('NAN', printf('%E', -0.0/0.0))
     call assert_equal('   nan', printf('%6f', 0.0/0.0))
--- a/src/version.c
+++ b/src/version.c
@@ -764,6 +764,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2291,
+/**/
     2290,
 /**/
     2289,