From d16aa7f83af727f5495dd4883efb603dc8b941bb Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 9 Dec 2010 16:28:11 +0100 Subject: Fix ~F.Fs bug, add testcase and improve documentation --- lib/stdlib/doc/src/io.xml | 8 ++-- lib/stdlib/src/io_lib_format.erl | 42 +++++++++++--------- lib/stdlib/test/io_SUITE.erl | 84 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 109 insertions(+), 25 deletions(-) diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml index efbb1fc078..81fb5cad3d 100644 --- a/lib/stdlib/doc/src/io.xml +++ b/lib/stdlib/doc/src/io.xml @@ -464,9 +464,9 @@ ok

Prints the argument with the string syntax. The argument is, if no Unicode translation modifier is present, an I/O list, a binary, or an atom. If the Unicode translation modifier ('t') is in effect, the argument is chardata(), meaning that binaries are in UTF-8. The characters - are printed without quotes. In this format, the printed - argument is truncated to the given precision and field - width.

+ are printed without quotes. The string is first truncated + by the given precision and then padded and justified + to the given field width. The default precision is the field width.

This format can be used for printing any object and truncating the output so it fits a specified field:

@@ -475,6 +475,8 @@ ok
ok 4> io:fwrite("|~10s|~n", [io_lib:write({hey, hey, hey})]). |{hey,hey,h| +5> io:fwrite("|~-10.8s|~n", [io_lib:write({hey, hey, hey})]). +|{hey,hey | ok

A list with integers larger than 255 is considered an error if the Unicode translation modifier is not given:

diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 7c04d78ce8..49a00a4ec7 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %% 
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
 %% 
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -558,26 +558,30 @@ iolist_to_chars(B) when is_binary(B) ->
 
 string(S, none, _Adj, none, _Pad) -> S;
 string(S, F, Adj, none, Pad) ->
-    N = lists:flatlength(S),
-    if N > F  -> flat_trunc(S, F);
-       N =:= F -> S;
-       true   -> adjust(S, chars(Pad, F-N), Adj)
-    end;
+    string_field(S, F, Adj, lists:flatlength(S), Pad);
 string(S, none, _Adj, P, Pad) ->
+    string_field(S, P, left, lists:flatlength(S), Pad);
+string(S, F, Adj, P, Pad) when F >= P ->
     N = lists:flatlength(S),
-    if N > P  -> flat_trunc(S, P);
-       N =:= P -> S;
-       true   -> [S|chars(Pad, P-N)]
-    end;
-string(S, F, Adj, F, Pad) ->
-    string(S, none, Adj, F, Pad);
-string(S, F, Adj, P, Pad) when F > P ->
-    N = lists:flatlength(S),
-    if N > P   -> adjust(flat_trunc(S, P), chars(Pad, F-P), Adj);
-       N =:= P -> adjust(S, chars(Pad, F-P), Adj);
-       true    -> adjust([S|chars(Pad, P-N)], chars(Pad, F-P), Adj)
+    if F > P ->
+	    if N > P ->
+		    adjust(flat_trunc(S, P), chars(Pad, F-P), Adj);
+	       N < P ->
+		    adjust([S|chars(Pad, P-N)], chars(Pad, F-P), Adj);
+	       true -> % N == P
+		    adjust(S, chars(Pad, F-P), Adj)
+	    end;
+       true -> % F == P
+	    string_field(S, F, Adj, N, Pad)
     end.
 
+string_field(S, F, _Adj, N, _Pad) when N > F ->
+    flat_trunc(S, F);
+string_field(S, F, Adj, N, Pad) when N < F ->
+    adjust(S, chars(Pad, F-N), Adj);
+string_field(S, _, _, _, _) -> % N == F
+    S.
+
 %% unprefixed_integer(Int, Field, Adjust, Base, PadChar, Lowercase)
 %% -> [Char].
 
@@ -622,8 +626,8 @@ newline(F, right, _P, _Pad) -> chars($\n, F).
 %%
 
 adjust(Data, [], _) -> Data;
-adjust(Data, Pad, left) -> [Data,Pad];
-adjust(Data, Pad, right) -> [Pad,Data].
+adjust(Data, Pad, left) -> [Data|Pad];
+adjust(Data, Pad, right) -> [Pad|Data].
 
 %% Flatten and truncate a deep list to at most N elements.
 
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 497fd3c562..54a98985cd 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -1,7 +1,7 @@
 %%
 %% %CopyrightBegin%
 %% 
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
 %% 
 %% The contents of this file are subject to the Erlang Public License,
 %% Version 1.1, (the "License"); you may not use this file except in
@@ -27,7 +27,7 @@
          otp_6282/1, otp_6354/1, otp_6495/1, otp_6517/1, otp_6502/1,
          manpage/1, otp_6708/1, otp_7084/1, otp_7421/1,
 	 io_lib_collect_line_3_wb/1, cr_whitespace_in_string/1,
-	 io_fread_newlines/1]).
+	 io_fread_newlines/1, otp_8989/1]).
 
 %-define(debug, true).
 
@@ -62,7 +62,7 @@ all() ->
      otp_6282, otp_6354, otp_6495, otp_6517, otp_6502,
      manpage, otp_6708, otp_7084, otp_7421,
      io_lib_collect_line_3_wb, cr_whitespace_in_string,
-     io_fread_newlines].
+     io_fread_newlines, otp_8989].
 
 groups() -> 
     [].
@@ -1917,3 +1917,81 @@ read_newlines(Fd, Acc, N0) ->
 	eof ->
 	    {lists:reverse(Acc),N0}
     end.
+
+
+
+otp_8989(doc) ->
+    "OTP-8989 io:format for ~F.Ps ignores P in some cases";
+otp_8989(Suite) when is_list(Suite) ->
+    Hello = "Hello",
+    ?line " Hello" = fmt("~6.6s", [Hello]),
+    ?line " Hello" = fmt("~*.6s", [6,Hello]),
+    ?line " Hello" = fmt("~6.*s", [6,Hello]),
+    ?line " Hello" = fmt("~*.*s", [6,6,Hello]),
+    %%
+    ?line " Hello" = fmt("~6.5s", [Hello]),
+    ?line " Hello" = fmt("~*.5s", [6,Hello]),
+    ?line " Hello" = fmt("~6.*s", [5,Hello]),
+    ?line " Hello" = fmt("~*.*s", [6,5,Hello]),
+    %%
+    ?line "  Hell" = fmt("~6.4s", [Hello]),
+    ?line "  Hell" = fmt("~*.4s", [6,Hello]),
+    ?line "  Hell" = fmt("~6.*s", [4,Hello]),
+    ?line "  Hell" = fmt("~*.*s", [6,4,Hello]),
+    %%
+    ?line "Hello" = fmt("~5.5s", [Hello]),
+    ?line "Hello" = fmt("~*.5s", [5,Hello]),
+    ?line "Hello" = fmt("~5.*s", [5,Hello]),
+    ?line "Hello" = fmt("~*.*s", [5,5,Hello]),
+    %%
+    ?line " Hell" = fmt("~5.4s", [Hello]),
+    ?line " Hell" = fmt("~*.4s", [5,Hello]),
+    ?line " Hell" = fmt("~5.*s", [4,Hello]),
+    ?line " Hell" = fmt("~*.*s", [5,4,Hello]),
+    %%
+    ?line "Hell" = fmt("~4.4s", [Hello]),
+    ?line "Hell" = fmt("~*.4s", [4,Hello]),
+    ?line "Hell" = fmt("~4.*s", [4,Hello]),
+    ?line "Hell" = fmt("~*.*s", [4,4,Hello]),
+    %%
+    ?line " Hel" = fmt("~4.3s", [Hello]),
+    ?line " Hel" = fmt("~*.3s", [4,Hello]),
+    ?line " Hel" = fmt("~4.*s", [3,Hello]),
+    ?line " Hel" = fmt("~*.*s", [4,3,Hello]),
+    %%
+    %%
+    ?line "Hello " = fmt("~-6.6s", [Hello]),
+    ?line "Hello " = fmt("~*.6s", [-6,Hello]),
+    ?line "Hello " = fmt("~-6.*s", [6,Hello]),
+    ?line "Hello " = fmt("~*.*s", [-6,6,Hello]),
+    %%
+    ?line "Hello " = fmt("~-6.5s", [Hello]),
+    ?line "Hello " = fmt("~*.5s", [-6,Hello]),
+    ?line "Hello " = fmt("~-6.*s", [5,Hello]),
+    ?line "Hello " = fmt("~*.*s", [-6,5,Hello]),
+    %%
+    ?line "Hell  " = fmt("~-6.4s", [Hello]),
+    ?line "Hell  " = fmt("~*.4s", [-6,Hello]),
+    ?line "Hell  " = fmt("~-6.*s", [4,Hello]),
+    ?line "Hell  " = fmt("~*.*s", [-6,4,Hello]),
+    %%
+    ?line "Hello" = fmt("~-5.5s", [Hello]),
+    ?line "Hello" = fmt("~*.5s", [-5,Hello]),
+    ?line "Hello" = fmt("~-5.*s", [5,Hello]),
+    ?line "Hello" = fmt("~*.*s", [-5,5,Hello]),
+    %%
+    ?line "Hell " = fmt("~-5.4s", [Hello]),
+    ?line "Hell " = fmt("~*.4s", [-5,Hello]),
+    ?line "Hell " = fmt("~-5.*s", [4,Hello]),
+    ?line "Hell " = fmt("~*.*s", [-5,4,Hello]),
+    %%
+    ?line "Hell" = fmt("~-4.4s", [Hello]),
+    ?line "Hell" = fmt("~*.4s", [-4,Hello]),
+    ?line "Hell" = fmt("~-4.*s", [4,Hello]),
+    ?line "Hell" = fmt("~*.*s", [-4,4,Hello]),
+    %%
+    ?line "Hel " = fmt("~-4.3s", [Hello]),
+    ?line "Hel " = fmt("~*.3s", [-4,Hello]),
+    ?line "Hel " = fmt("~-4.*s", [3,Hello]),
+    ?line "Hel " = fmt("~*.*s", [-4,3,Hello]),
+    ok.
-- 
cgit v1.2.3