|
|
@ -40,8 +40,9 @@ format(String, Args, Max) -> |
|
|
|
Maxlen = Max - length(String), |
|
|
|
format(Parts, Args, Maxlen, [], []). |
|
|
|
|
|
|
|
format([], _Args, _Max, Acc, ArgAcc) -> |
|
|
|
io_lib:format(lists:flatten(lists:reverse(Acc)), lists:reverse(ArgAcc)); |
|
|
|
format([], _Args, Max, Acc, ArgAcc) -> |
|
|
|
FmtArgs = resolve_futures(Max, ArgAcc), |
|
|
|
io_lib:format(lists:flatten(lists:reverse(Acc)), lists:reverse(FmtArgs)); |
|
|
|
format([[] | T], Args, Max, Acc, ArgAcc) -> |
|
|
|
% discard the null list generated by split |
|
|
|
format(T, Args, Max, Acc, ArgAcc); |
|
|
@ -62,21 +63,21 @@ format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) when length(H) == 1 -> |
|
|
|
case H of |
|
|
|
_ when H == "p"; H == "w"; H == "s" -> |
|
|
|
%okay, these are prime candidates for rewriting |
|
|
|
{String, Length} = case print(AH, Max) of |
|
|
|
case print(AH, Max) of |
|
|
|
{_Res, Max} when AT /= [] -> |
|
|
|
% this isn't the last argument, but it consumed all available space, give it half instead |
|
|
|
print(AH, Max div 2); |
|
|
|
{Res, Len} -> |
|
|
|
{Res, Len} |
|
|
|
end, |
|
|
|
{Value, RealLen} = case H of |
|
|
|
"s" -> |
|
|
|
% strip off the doublequotes |
|
|
|
{string:substr(String, 2, length(String) -2), Length -2}; |
|
|
|
_ -> |
|
|
|
{String, Length} |
|
|
|
end, |
|
|
|
format(T, AT, Max + 2 - RealLen, ["~s" | Acc], [Value | ArgAcc]); |
|
|
|
% this isn't the last argument, but it consumed all available space |
|
|
|
% delay calculating the print size until the end |
|
|
|
format(T, AT, Max + 2, ["~s" | Acc], [{future, AH} | ArgAcc]); |
|
|
|
{String, Length} -> |
|
|
|
{Value, RealLen} = case H of |
|
|
|
"s" -> |
|
|
|
% strip off the doublequotes |
|
|
|
{string:substr(String, 2, length(String) -2), Length -2}; |
|
|
|
_ -> |
|
|
|
{String, Length} |
|
|
|
end, |
|
|
|
format(T, AT, Max + 2 - RealLen, ["~s" | Acc], [Value | ArgAcc]) |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
% whatever, just pass them on through |
|
|
|
format(T, AT, Max, [[$~ | H], Acc], [AH | ArgAcc]) |
|
|
@ -87,22 +88,26 @@ format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) -> |
|
|
|
case re:run(H, "^(?:-??(\\d+|\\*)\\.|)(?:-??(\\d+|\\*)\\.|)(-??\\d+|\\*|)(t|)([cfegswpWPBX#bx+ni])$", [{capture, all_but_first, list}]) of |
|
|
|
{match, [_F, _P, _Pad, _Mod, C]} when C == "p"; C=="w"; C=="s" -> |
|
|
|
%okay, these are prime candidates for rewriting |
|
|
|
{String, Length} = case print(AH, Max) of |
|
|
|
case print(AH, Max) of |
|
|
|
{_Res, Max} when AT /= [] -> |
|
|
|
% this isn't the last argument, but it consumed all available space, give it half instead |
|
|
|
print(AH, Max div 2); |
|
|
|
{Res, Len} -> |
|
|
|
{Res, Len} |
|
|
|
end, |
|
|
|
{Value, RealLen} = case H of |
|
|
|
"s" -> |
|
|
|
% strip off the doublequotes |
|
|
|
{string:substr(String, 2, length(String) -2), Length -2}; |
|
|
|
_ -> |
|
|
|
{String, Length} |
|
|
|
end, |
|
|
|
format(T, AT, Max + length(H) + 1 - RealLen, ["~s" | Acc], [Value | ArgAcc]); |
|
|
|
% this isn't the last argument, but it consumed all available space |
|
|
|
% delay calculating the print size until the end |
|
|
|
format(T, AT, Max + length(H) + 1, ["~s" | Acc], [{future, AH} | ArgAcc]); |
|
|
|
{String, Length} -> |
|
|
|
{Value, RealLen} = case H of |
|
|
|
"s" -> |
|
|
|
% strip off the doublequotes |
|
|
|
{string:substr(String, 2, length(String) -2), Length -2}; |
|
|
|
_ -> |
|
|
|
{String, Length} |
|
|
|
end, |
|
|
|
format(T, AT, Max + length(H) + 1 - RealLen, ["~s" | Acc], [Value | ArgAcc]) |
|
|
|
end; |
|
|
|
{match, [_F, _P, _Pad, _Mod, C]} when C == "P"; C=="W" -> |
|
|
|
% these crazy ones consume TWO arguments, just pass them through |
|
|
|
% because W and P implicitly limit size so we trust the user knows |
|
|
|
% what they're doing. Unfortunately we can't change Max at all because |
|
|
|
% depth based limits are not of known length. |
|
|
|
[AH2 | AT2] = AT, |
|
|
|
format(T, AT2, Max, [[$~|H]|Acc], [AH2, AH |ArgAcc]); |
|
|
|
{match, _} -> |
|
|
@ -114,6 +119,17 @@ format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) -> |
|
|
|
format([H | T], Args, Max, Acc, ArgAcc) -> |
|
|
|
format(T, Args, Max, [H | Acc], ArgAcc). |
|
|
|
|
|
|
|
%% for all the really big terms encountered in a format/3 call, try to give each of them an equal share |
|
|
|
resolve_futures(Max, Args) -> |
|
|
|
Count = length(lists:filter(fun({future, _}) -> true; (_) -> false end, Args)), |
|
|
|
case Count of |
|
|
|
0 -> |
|
|
|
Args; |
|
|
|
_ -> |
|
|
|
SingleFmt = Max div Count, |
|
|
|
lists:map(fun({future, Value}) -> element(1, print(Value, SingleFmt)); (X) -> X end, Args) |
|
|
|
end. |
|
|
|
|
|
|
|
%% @doc Returns an flattened list containing the ASCII representation of the given |
|
|
|
%% term. |
|
|
|
-spec fprint(term(), pos_integer()) -> string(). |
|
|
|