patch 7.4.2291
Problem:    printf() handles floats wrong when there is a sign.
Solution:   Fix placing the sign.  Add tests. (Dominique Pelle)
diff --git a/src/message.c b/src/message.c
index 92e7353..264d15a 100644
--- a/src/message.c
+++ b/src/message.c
@@ -4030,7 +4030,7 @@
  * 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 @@
 		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 @@
 
 # ifdef FEAT_FLOAT
 	    case 'f':
+	    case 'F':
 	    case 'e':
 	    case 'E':
 	    case 'g':
@@ -4740,13 +4740,13 @@
 			 * "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 @@
 		    }
 		    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 @@
 			    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 @@
 			    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 @@
 			    }
 			}
 		    }
+		    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;
 		}
diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim
index 11ca288..3097daf 100644
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -162,21 +162,44 @@
   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 @@
 
 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 @@
     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 @@
     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 @@
     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 @@
     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))
diff --git a/src/version.c b/src/version.c
index 3cae92d..0d97662 100644
--- a/src/version.c
+++ b/src/version.c
@@ -764,6 +764,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2291,
+/**/
     2290,
 /**/
     2289,