|
@ -8,10 +8,8 @@ |
|
|
-export([ |
|
|
-export([ |
|
|
fwrite/2 |
|
|
fwrite/2 |
|
|
, fwrite/3 |
|
|
, fwrite/3 |
|
|
, fwrite_g/1 |
|
|
|
|
|
, indentation/2 |
|
|
|
|
|
|
|
|
, floatG/1 |
|
|
, scan/2 |
|
|
, scan/2 |
|
|
, unscan/1 |
|
|
|
|
|
, build/1 |
|
|
, build/1 |
|
|
, build/2 |
|
|
, build/2 |
|
|
]). |
|
|
]). |
|
@ -215,9 +213,9 @@ buildSmall([OneCA | Cs], Acc) -> |
|
|
ctlSmall($s, Args, Width, Adjust, Precision, PadChar, Encoding) when is_atom(Args) -> |
|
|
ctlSmall($s, Args, Width, Adjust, Precision, PadChar, Encoding) when is_atom(Args) -> |
|
|
case Encoding of |
|
|
case Encoding of |
|
|
latin1 -> |
|
|
latin1 -> |
|
|
AtomBinStr = atom_to_binary(Args, latin1); |
|
|
|
|
|
|
|
|
AtomBinStr = eFmt:writeAtom(Args, latin1); |
|
|
_ -> |
|
|
_ -> |
|
|
AtomBinStr = atom_to_binary(Args, uft8) |
|
|
|
|
|
|
|
|
AtomBinStr = eFmt:writeAtom(Args, uft8) |
|
|
end, |
|
|
end, |
|
|
string(AtomBinStr, Width, Adjust, Precision, PadChar, Encoding); |
|
|
string(AtomBinStr, Width, Adjust, Precision, PadChar, Encoding); |
|
|
ctlSmall($e, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_float(Args) -> |
|
|
ctlSmall($e, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_float(Args) -> |
|
@ -291,45 +289,23 @@ buildLimited([OneCA | Cs], NumOfPs, Count, MaxLen, I, Acc) -> |
|
|
case OneCA of |
|
|
case OneCA of |
|
|
#fmtSpec{ctlChar = CtlChar, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings} -> |
|
|
#fmtSpec{ctlChar = CtlChar, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings} -> |
|
|
MaxChars = if MaxLen < 0 -> MaxLen; true -> MaxLen div Count end, |
|
|
MaxChars = if MaxLen < 0 -> MaxLen; true -> MaxLen div Count end, |
|
|
S = ctlLimited(CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I), |
|
|
|
|
|
NewNumOfPs = decr_pc(CtlChar, NumOfPs), |
|
|
|
|
|
|
|
|
IoListStr = ctlLimited(CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I), |
|
|
|
|
|
NewNumOfPs = decrPc(CtlChar, NumOfPs), |
|
|
NewCount = Count - 1, |
|
|
NewCount = Count - 1, |
|
|
MaxLen = if |
|
|
|
|
|
MaxLen < 0 -> % optimization |
|
|
|
|
|
MaxLen; |
|
|
|
|
|
true -> |
|
|
|
|
|
Len = eFmt:charsLen(S), |
|
|
|
|
|
remainChars(MaxLen, Len) |
|
|
|
|
|
end, |
|
|
|
|
|
|
|
|
MaxLen = ?IIF(MaxLen < 0, MaxLen, remainChars(MaxLen, eFmt:charsLen(IoListStr))), |
|
|
if |
|
|
if |
|
|
NewNumOfPs > 0 -> [S | buildLimited(Cs, NewNumOfPs, NewCount, |
|
|
|
|
|
MaxLen, indentation(S, I))]; |
|
|
|
|
|
true -> [S | buildLimited(Cs, NewNumOfPs, NewCount, MaxLen, I)] |
|
|
|
|
|
|
|
|
NewNumOfPs > 0 -> |
|
|
|
|
|
buildLimited(Cs, NewNumOfPs, NewCount, MaxLen, I, [IoListStr | Acc]); |
|
|
|
|
|
true -> |
|
|
|
|
|
buildLimited(Cs, NewNumOfPs, NewCount, MaxLen, I, [IoListStr | Acc]) |
|
|
end; |
|
|
end; |
|
|
_ -> |
|
|
_ -> |
|
|
buildLimited(Cs, NewNumOfPs, NewCount, MaxLen, I + 1, [OneCA | Acc]) |
|
|
|
|
|
|
|
|
buildLimited(Cs, NumOfPs, Count, MaxLen, I + 1, [OneCA | Acc]) |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
decr_pc($p, Pc) -> Pc - 1; |
|
|
|
|
|
decr_pc($P, Pc) -> Pc - 1; |
|
|
|
|
|
decr_pc(_, Pc) -> Pc. |
|
|
|
|
|
|
|
|
|
|
|
%% Calculate the indentation of the end of a string given its start |
|
|
|
|
|
%% indentation. We assume tabs at 8 cols. |
|
|
|
|
|
|
|
|
|
|
|
-spec indentation(String, StartIndent) -> integer() when |
|
|
|
|
|
String :: eFmt:chars(), |
|
|
|
|
|
StartIndent :: integer(). |
|
|
|
|
|
|
|
|
|
|
|
indentation([$\n | Cs], _I) -> indentation(Cs, 0); |
|
|
|
|
|
indentation([$\t | Cs], I) -> indentation(Cs, ((I + 8) div 8) * 8); |
|
|
|
|
|
indentation([C | Cs], I) when is_integer(C) -> |
|
|
|
|
|
indentation(Cs, I + 1); |
|
|
|
|
|
indentation([C | Cs], I) -> |
|
|
|
|
|
indentation(Cs, indentation(C, I)); |
|
|
|
|
|
indentation([], I) -> I. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
decrPc($p, Pc) -> Pc - 1; |
|
|
|
|
|
decrPc($P, Pc) -> Pc - 1; |
|
|
|
|
|
decrPc(_, Pc) -> Pc. |
|
|
|
|
|
|
|
|
%% (CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I) |
|
|
%% (CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I) |
|
|
ctlLimited($s, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) -> |
|
|
ctlLimited($s, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) -> |
|
@ -346,26 +322,16 @@ ctlLimited($s, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, Char |
|
|
TemBinStr = strToChars(BinStr, Width, CharsLimit), |
|
|
TemBinStr = strToChars(BinStr, Width, CharsLimit), |
|
|
string(TemBinStr, ?IIF(CharsLimit < 0 orelse Width =:= none, Width, max(3, min(Width, CharsLimit))), Adjust, Precision, PadChar, Encoding); |
|
|
string(TemBinStr, ?IIF(CharsLimit < 0 orelse Width =:= none, Width, max(3, min(Width, CharsLimit))), Adjust, Precision, PadChar, Encoding); |
|
|
ctlLimited($w, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) -> |
|
|
ctlLimited($w, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) -> |
|
|
Chars = eFmt:write(Args, [{depth, -1}, {encoding, Encoding}, {chars_limit, CharsLimit}]), |
|
|
|
|
|
|
|
|
Chars = eFmt:doWrite(Args, -1, Encoding, CharsLimit), |
|
|
term(Chars, Width, Adjust, Precision, PadChar); |
|
|
term(Chars, Width, Adjust, Precision, PadChar); |
|
|
ctlLimited($p, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I) -> |
|
|
ctlLimited($p, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I) -> |
|
|
print(Args, -1, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I); |
|
|
print(Args, -1, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I); |
|
|
ctlLimited($W, [Args, Depth], Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) |
|
|
|
|
|
when is_integer(Depth) -> |
|
|
|
|
|
Chars = eFmt:write(Args, [{depth, Depth}, {encoding, Encoding}, {chars_limit, CharsLimit}]), |
|
|
|
|
|
|
|
|
ctlLimited($W, [Args, Depth], Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) -> |
|
|
|
|
|
Chars = eFmt:doWrite(Args, Depth, Encoding, CharsLimit), |
|
|
term(Chars, Width, Adjust, Precision, PadChar); |
|
|
term(Chars, Width, Adjust, Precision, PadChar); |
|
|
ctlLimited($P, [Args, Depth], Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I) |
|
|
|
|
|
when is_integer(Depth) -> |
|
|
|
|
|
|
|
|
ctlLimited($P, [Args, Depth], Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I) -> |
|
|
print(Args, Depth, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I). |
|
|
print(Args, Depth, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I). |
|
|
|
|
|
|
|
|
-ifdef(UNICODE_AS_BINARIES). |
|
|
|
|
|
uniconv(C) -> |
|
|
|
|
|
unicode:characters_to_binary(C, unicode). |
|
|
|
|
|
-else. |
|
|
|
|
|
uniconv(C) -> |
|
|
|
|
|
C. |
|
|
|
|
|
-endif. |
|
|
|
|
|
|
|
|
|
|
|
%% term(TermList, Field, Adjust, Precision, PadChar) |
|
|
%% term(TermList, Field, Adjust, Precision, PadChar) |
|
|
%% Output the characters in a term. |
|
|
%% Output the characters in a term. |
|
|
%% Adjust the characters within the field if length less than Max padding |
|
|
%% Adjust the characters within the field if length less than Max padding |
|
@ -453,216 +419,8 @@ floatG(Float, Width, Adjust, Precision, PadChar) -> |
|
|
floatE(Float, Width, Adjust, Precision, PadChar) |
|
|
floatE(Float, Width, Adjust, Precision, PadChar) |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%% Writes the shortest, correctly rounded string that converts |
|
|
|
|
|
%% to Float when read back with list_to_float/1. |
|
|
|
|
|
%% |
|
|
|
|
|
%% See also "Printing Floating-Point Numbers Quickly and Accurately" |
|
|
|
|
|
%% in Proceedings of the SIGPLAN '96 Conference on Programming |
|
|
|
|
|
%% Language Design and Implementation. |
|
|
|
|
|
|
|
|
|
|
|
-spec fwrite_g(float()) -> string(). |
|
|
|
|
|
|
|
|
|
|
|
fwrite_g(0.0) -> |
|
|
|
|
|
"0.0"; |
|
|
|
|
|
fwrite_g(Float) when is_float(Float) -> |
|
|
|
|
|
{Frac, Exp} = mantissa_exponent(Float), |
|
|
|
|
|
{Place, Digits} = fwrite_g_1(Float, Exp, Frac), |
|
|
|
|
|
R = insert_decimal(Place, [$0 + D || D <- Digits]), |
|
|
|
|
|
[$- || true <- [Float < 0.0]] ++ R. |
|
|
|
|
|
|
|
|
|
|
|
-define(BIG_POW, (1 bsl 52)). |
|
|
|
|
|
-define(MIN_EXP, (-1074)). |
|
|
|
|
|
|
|
|
|
|
|
mantissa_exponent(F) -> |
|
|
|
|
|
case <<F:64/float>> of |
|
|
|
|
|
<<_S:1, 0:11, M:52>> -> % denormalized |
|
|
|
|
|
E = log2floor(M), |
|
|
|
|
|
{M bsl (53 - E), E - 52 - 1075}; |
|
|
|
|
|
<<_S:1, BE:11, M:52>> when BE < 2047 -> |
|
|
|
|
|
{M + ?BIG_POW, BE - 1075} |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
fwrite_g_1(Float, Exp, Frac) -> |
|
|
|
|
|
Round = (Frac band 1) =:= 0, |
|
|
|
|
|
if |
|
|
|
|
|
Exp >= 0 -> |
|
|
|
|
|
BExp = 1 bsl Exp, |
|
|
|
|
|
if |
|
|
|
|
|
Frac =:= ?BIG_POW -> |
|
|
|
|
|
scale(Frac * BExp * 4, 4, BExp * 2, BExp, |
|
|
|
|
|
Round, Round, Float); |
|
|
|
|
|
true -> |
|
|
|
|
|
scale(Frac * BExp * 2, 2, BExp, BExp, |
|
|
|
|
|
Round, Round, Float) |
|
|
|
|
|
end; |
|
|
|
|
|
Exp < ?MIN_EXP -> |
|
|
|
|
|
BExp = 1 bsl (?MIN_EXP - Exp), |
|
|
|
|
|
scale(Frac * 2, 1 bsl (1 - Exp), BExp, BExp, |
|
|
|
|
|
Round, Round, Float); |
|
|
|
|
|
Exp > ?MIN_EXP, Frac =:= ?BIG_POW -> |
|
|
|
|
|
scale(Frac * 4, 1 bsl (2 - Exp), 2, 1, |
|
|
|
|
|
Round, Round, Float); |
|
|
|
|
|
true -> |
|
|
|
|
|
scale(Frac * 2, 1 bsl (1 - Exp), 1, 1, |
|
|
|
|
|
Round, Round, Float) |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
scale(R, S, MPlus, MMinus, LowOk, HighOk, Float) -> |
|
|
|
|
|
Est = int_ceil(math:log10(abs(Float)) - 1.0e-10), |
|
|
|
|
|
%% Note that the scheme implementation uses a 326 element look-up |
|
|
|
|
|
%% table for int_pow(10, N) where we do not. |
|
|
|
|
|
if |
|
|
|
|
|
Est >= 0 -> |
|
|
|
|
|
fixup(R, S * int_pow(10, Est), MPlus, MMinus, Est, |
|
|
|
|
|
LowOk, HighOk); |
|
|
|
|
|
true -> |
|
|
|
|
|
Scale = int_pow(10, -Est), |
|
|
|
|
|
fixup(R * Scale, S, MPlus * Scale, MMinus * Scale, Est, |
|
|
|
|
|
LowOk, HighOk) |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
fixup(R, S, MPlus, MMinus, K, LowOk, HighOk) -> |
|
|
|
|
|
TooLow = if |
|
|
|
|
|
HighOk -> R + MPlus >= S; |
|
|
|
|
|
true -> R + MPlus > S |
|
|
|
|
|
end, |
|
|
|
|
|
case TooLow of |
|
|
|
|
|
true -> |
|
|
|
|
|
{K + 1, generate(R, S, MPlus, MMinus, LowOk, HighOk)}; |
|
|
|
|
|
false -> |
|
|
|
|
|
{K, generate(R * 10, S, MPlus * 10, MMinus * 10, LowOk, HighOk)} |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
generate(R0, S, MPlus, MMinus, LowOk, HighOk) -> |
|
|
|
|
|
D = R0 div S, |
|
|
|
|
|
R = R0 rem S, |
|
|
|
|
|
TC1 = if |
|
|
|
|
|
LowOk -> R =< MMinus; |
|
|
|
|
|
true -> R < MMinus |
|
|
|
|
|
end, |
|
|
|
|
|
TC2 = if |
|
|
|
|
|
HighOk -> R + MPlus >= S; |
|
|
|
|
|
true -> R + MPlus > S |
|
|
|
|
|
end, |
|
|
|
|
|
case {TC1, TC2} of |
|
|
|
|
|
{false, false} -> |
|
|
|
|
|
[D | generate(R * 10, S, MPlus * 10, MMinus * 10, LowOk, HighOk)]; |
|
|
|
|
|
{false, true} -> |
|
|
|
|
|
[D + 1]; |
|
|
|
|
|
{true, false} -> |
|
|
|
|
|
[D]; |
|
|
|
|
|
{true, true} when R * 2 < S -> |
|
|
|
|
|
[D]; |
|
|
|
|
|
{true, true} -> |
|
|
|
|
|
[D + 1] |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
insert_decimal(0, S) -> |
|
|
|
|
|
"0." ++ S; |
|
|
|
|
|
insert_decimal(Place, S) -> |
|
|
|
|
|
L = length(S), |
|
|
|
|
|
if |
|
|
|
|
|
Place < 0; |
|
|
|
|
|
Place >= L -> |
|
|
|
|
|
ExpL = integer_to_list(Place - 1), |
|
|
|
|
|
ExpDot = if L =:= 1 -> 2; true -> 1 end, |
|
|
|
|
|
ExpCost = length(ExpL) + 1 + ExpDot, |
|
|
|
|
|
if |
|
|
|
|
|
Place < 0 -> |
|
|
|
|
|
if |
|
|
|
|
|
2 - Place =< ExpCost -> |
|
|
|
|
|
"0." ++ lists:duplicate(-Place, $0) ++ S; |
|
|
|
|
|
true -> |
|
|
|
|
|
insert_exp(ExpL, S) |
|
|
|
|
|
end; |
|
|
|
|
|
true -> |
|
|
|
|
|
if |
|
|
|
|
|
Place - L + 2 =< ExpCost -> |
|
|
|
|
|
S ++ lists:duplicate(Place - L, $0) ++ ".0"; |
|
|
|
|
|
true -> |
|
|
|
|
|
insert_exp(ExpL, S) |
|
|
|
|
|
end |
|
|
|
|
|
end; |
|
|
|
|
|
true -> |
|
|
|
|
|
{S0, S1} = lists:split(Place, S), |
|
|
|
|
|
S0 ++ "." ++ S1 |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
insert_exp(ExpL, [C]) -> |
|
|
|
|
|
[C] ++ ".0e" ++ ExpL; |
|
|
|
|
|
insert_exp(ExpL, [C | S]) -> |
|
|
|
|
|
[C] ++ "." ++ S ++ "e" ++ ExpL. |
|
|
|
|
|
|
|
|
|
|
|
int_ceil(X) when is_float(X) -> |
|
|
|
|
|
T = trunc(X), |
|
|
|
|
|
case (X - T) of |
|
|
|
|
|
Neg when Neg < 0 -> T; |
|
|
|
|
|
Pos when Pos > 0 -> T + 1; |
|
|
|
|
|
_ -> T |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
int_pow(X, 0) when is_integer(X) -> |
|
|
|
|
|
1; |
|
|
|
|
|
int_pow(X, N) when is_integer(X), is_integer(N), N > 0 -> |
|
|
|
|
|
int_pow(X, N, 1). |
|
|
|
|
|
|
|
|
|
|
|
int_pow(X, N, R) when N < 2 -> |
|
|
|
|
|
R * X; |
|
|
|
|
|
int_pow(X, N, R) -> |
|
|
|
|
|
int_pow(X * X, N bsr 1, case N band 1 of 1 -> R * X; 0 -> R end). |
|
|
|
|
|
|
|
|
|
|
|
log2floor(Int) when is_integer(Int), Int > 0 -> |
|
|
|
|
|
log2floor(Int, 0). |
|
|
|
|
|
|
|
|
|
|
|
log2floor(0, N) -> |
|
|
|
|
|
N; |
|
|
|
|
|
log2floor(Int, N) -> |
|
|
|
|
|
log2floor(Int bsr 1, 1 + N). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iolist_to_chars(Cs, F, CharsLimit) when CharsLimit < 0; CharsLimit >= F -> |
|
|
|
|
|
iolist_to_chars(Cs); |
|
|
|
|
|
iolist_to_chars(Cs, _, CharsLimit) -> |
|
|
|
|
|
limit_iolist_to_chars(Cs, remainChars(CharsLimit, 3), [], normal). % three dots |
|
|
|
|
|
|
|
|
|
|
|
iolist_to_chars([C | Cs]) when is_integer(C), C >= $\000, C =< $\377 -> |
|
|
|
|
|
[C | iolist_to_chars(Cs)]; |
|
|
|
|
|
iolist_to_chars([I | Cs]) -> |
|
|
|
|
|
[iolist_to_chars(I) | iolist_to_chars(Cs)]; |
|
|
|
|
|
iolist_to_chars([]) -> |
|
|
|
|
|
[]; |
|
|
|
|
|
iolist_to_chars(B) when is_binary(B) -> |
|
|
|
|
|
binary_to_list(B). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
limit_iolist_to_chars(Cs, 0, S, normal) -> |
|
|
|
|
|
L = limit_iolist_to_chars(Cs, 4, S, final), |
|
|
|
|
|
case iolist_size(L) of |
|
|
|
|
|
N when N < 4 -> L; |
|
|
|
|
|
4 -> "..." |
|
|
|
|
|
end; |
|
|
|
|
|
limit_iolist_to_chars(_Cs, 0, _S, final) -> []; |
|
|
|
|
|
limit_iolist_to_chars([C | Cs], Limit, S, Mode) when C >= $\000, C =< $\377 -> |
|
|
|
|
|
[C | limit_iolist_to_chars(Cs, Limit - 1, S, Mode)]; |
|
|
|
|
|
limit_iolist_to_chars([I | Cs], Limit, S, Mode) -> |
|
|
|
|
|
limit_iolist_to_chars(I, Limit, [Cs | S], Mode); |
|
|
|
|
|
limit_iolist_to_chars([], _Limit, [], _Mode) -> |
|
|
|
|
|
[]; |
|
|
|
|
|
limit_iolist_to_chars([], Limit, [Cs | S], Mode) -> |
|
|
|
|
|
limit_iolist_to_chars(Cs, Limit, S, Mode); |
|
|
|
|
|
limit_iolist_to_chars(B, Limit, S, Mode) when is_binary(B) -> |
|
|
|
|
|
case byte_size(B) of |
|
|
|
|
|
Sz when Sz > Limit -> |
|
|
|
|
|
{B1, B2} = split_binary(B, Limit), |
|
|
|
|
|
[binary_to_list(B1) | limit_iolist_to_chars(B2, 0, S, Mode)]; |
|
|
|
|
|
Sz -> |
|
|
|
|
|
[binary_to_list(B) | limit_iolist_to_chars([], Limit - Sz, S, Mode)] |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
floatG(Float) -> |
|
|
|
|
|
float_to_binary(Float, [{decimals, 6}]). |
|
|
|
|
|
|
|
|
strToChars(BinStr, Width, CharsLimit) -> |
|
|
strToChars(BinStr, Width, CharsLimit) -> |
|
|
ByteSize = byte_size(BinStr), |
|
|
ByteSize = byte_size(BinStr), |
|
@ -680,37 +438,6 @@ strToChars(BinStr, Width, CharsLimit) -> |
|
|
<<(binary:part(BinStr, 0, CharsLimit))/binary, "...">> |
|
|
<<(binary:part(BinStr, 0, CharsLimit))/binary, "...">> |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
cdata_to_chars(Cs, F, CharsLimit) when CharsLimit < 0; CharsLimit >= F -> |
|
|
|
|
|
cdata_to_chars(Cs); |
|
|
|
|
|
cdata_to_chars(Cs, _, CharsLimit) -> |
|
|
|
|
|
limit_cdata_to_chars(Cs, remainChars(CharsLimit, 3), normal). % three dots |
|
|
|
|
|
|
|
|
|
|
|
limit_cdata_to_chars(Cs, 0, normal) -> |
|
|
|
|
|
L = limit_cdata_to_chars(Cs, 4, final), |
|
|
|
|
|
case string:length(L) of |
|
|
|
|
|
N when N < 4 -> L; |
|
|
|
|
|
4 -> "..." |
|
|
|
|
|
end; |
|
|
|
|
|
limit_cdata_to_chars(_Cs, 0, final) -> []; |
|
|
|
|
|
limit_cdata_to_chars(Cs, Limit, Mode) -> |
|
|
|
|
|
case string:next_grapheme(Cs) of |
|
|
|
|
|
{error, <<C, Cs1/binary>>} -> |
|
|
|
|
|
%% This is how ~ts handles Latin1 binaries with option |
|
|
|
|
|
%% chars_limit. |
|
|
|
|
|
[C | limit_cdata_to_chars(Cs1, Limit - 1, Mode)]; |
|
|
|
|
|
{error, [C | Cs1]} -> % not all versions of module string return this |
|
|
|
|
|
[C | limit_cdata_to_chars(Cs1, Limit - 1, Mode)]; |
|
|
|
|
|
[] -> |
|
|
|
|
|
[]; |
|
|
|
|
|
[GC | Cs1] -> |
|
|
|
|
|
[GC | limit_cdata_to_chars(Cs1, Limit - 1, Mode)] |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
limit_field(F, CharsLimit) when CharsLimit < 0; F =:= none -> |
|
|
|
|
|
F; |
|
|
|
|
|
limit_field(F, CharsLimit) -> |
|
|
|
|
|
max(3, min(F, CharsLimit)). |
|
|
|
|
|
|
|
|
|
|
|
string(Str, Width, Adjust, Precision, PadChar, Encoding) -> |
|
|
string(Str, Width, Adjust, Precision, PadChar, Encoding) -> |
|
|
if |
|
|
if |
|
|
Width == none andalso Precision == none -> |
|
|
Width == none andalso Precision == none -> |
|
@ -842,53 +569,6 @@ getOpt(Key, TupleList, Default) -> |
|
|
Default |
|
|
Default |
|
|
end. |
|
|
end. |
|
|
|
|
|
|
|
|
%% 将预先解析的格式列表还原为纯字符列表和参数列表。 |
|
|
|
|
|
-spec unscan(FormatList) -> {Format, Data} when |
|
|
|
|
|
FormatList :: [char() | eFmt:format_spec()], |
|
|
|
|
|
Format :: io:format(), |
|
|
|
|
|
Data :: [term()]. |
|
|
|
|
|
|
|
|
|
|
|
unscan(Cs) -> |
|
|
|
|
|
{print(Cs), args(Cs)}. |
|
|
|
|
|
|
|
|
|
|
|
args([#{args := As} | Cs]) -> |
|
|
|
|
|
As ++ args(Cs); |
|
|
|
|
|
args([_C | Cs]) -> |
|
|
|
|
|
args(Cs); |
|
|
|
|
|
args([]) -> |
|
|
|
|
|
[]. |
|
|
|
|
|
|
|
|
|
|
|
print([#{control_char := C, width := F, adjust := Ad, precision := P, |
|
|
|
|
|
pad_char := Pad, encoding := Encoding, strings := Strings} | Cs]) -> |
|
|
|
|
|
print(C, F, Ad, P, Pad, Encoding, Strings) ++ print(Cs); |
|
|
|
|
|
print([C | Cs]) -> |
|
|
|
|
|
[C | print(Cs)]; |
|
|
|
|
|
print([]) -> |
|
|
|
|
|
[]. |
|
|
|
|
|
|
|
|
|
|
|
print(C, F, Ad, P, Pad, Encoding, Strings) -> |
|
|
|
|
|
[$~] ++ print_field_width(F, Ad) ++ print_precision(P, Pad) ++ |
|
|
|
|
|
print_pad_char(Pad) ++ print_encoding(Encoding) ++ |
|
|
|
|
|
print_strings(Strings) ++ [C]. |
|
|
|
|
|
|
|
|
|
|
|
print_field_width(none, _Ad) -> ""; |
|
|
|
|
|
print_field_width(F, left) -> integer_to_list(-F); |
|
|
|
|
|
print_field_width(F, right) -> integer_to_list(F). |
|
|
|
|
|
|
|
|
|
|
|
print_precision(none, $\s) -> ""; |
|
|
|
|
|
print_precision(none, _Pad) -> "."; % pad must be second dot |
|
|
|
|
|
print_precision(P, _Pad) -> [$. | integer_to_list(P)]. |
|
|
|
|
|
|
|
|
|
|
|
print_pad_char($\s) -> ""; % default, no need to make explicit |
|
|
|
|
|
print_pad_char(Pad) -> [$., Pad]. |
|
|
|
|
|
|
|
|
|
|
|
print_encoding(unicode) -> "t"; |
|
|
|
|
|
print_encoding(latin1) -> "". |
|
|
|
|
|
|
|
|
|
|
|
print_strings(false) -> "l"; |
|
|
|
|
|
print_strings(true) -> "". |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
toLowerStr(BinStr) -> |
|
|
toLowerStr(BinStr) -> |
|
|
<< begin |
|
|
<< begin |
|
|
case C >= $A andalso C =< $Z of |
|
|
case C >= $A andalso C =< $Z of |
|
|