|
@ -12,55 +12,39 @@ |
|
|
, build/2 |
|
|
, build/2 |
|
|
]). |
|
|
]). |
|
|
|
|
|
|
|
|
%% Format the arguments in Args after string Format. Just generate |
|
|
|
|
|
%% an error if there is an error in the arguments. |
|
|
|
|
|
|
|
|
%% 在字符串格式之后将参数格式化为Args。刚产生 |
|
|
|
|
|
%% 如果参数中有错误,则为错误。 |
|
|
%% |
|
|
%% |
|
|
%% To do the printing command correctly we need to calculate the |
|
|
|
|
|
%% current indentation for everything before it. This may be very |
|
|
|
|
|
%% expensive, especially when it is not needed, so we first determine |
|
|
|
|
|
%% if, and for how long, we need to calculate the indentations. We do |
|
|
|
|
|
%% this by first collecting all the control sequences and |
|
|
|
|
|
%% corresponding arguments, then counting the print sequences and |
|
|
|
|
|
%% then building the output. This method has some drawbacks, it does |
|
|
|
|
|
%% two passes over the format string and creates more temporary data, |
|
|
|
|
|
%% and it also splits the handling of the control characters into two |
|
|
|
|
|
%% parts. |
|
|
|
|
|
|
|
|
|
|
|
-spec fwrite(Format, Data) -> io_lib:chars() when |
|
|
|
|
|
Format :: io:format(), |
|
|
|
|
|
Data :: [term()]. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%% 要正确执行打印命令,我们需要计算 |
|
|
|
|
|
%% 当前缩进的所有内容。这可能非常 |
|
|
|
|
|
%% 价格昂贵,尤其是在不需要时,因此我们首先确定 |
|
|
|
|
|
%% 是否以及需要多长时间来计算缩进。我们的确是 |
|
|
|
|
|
%% 首先收集所有控制序列,然后 |
|
|
|
|
|
%% 相应的参数,然后计算打印顺序,然后 |
|
|
|
|
|
%% 然后构建输出。这种方法有一些缺点,它确实 |
|
|
|
|
|
%% 在格式字符串上两次传递并创建更多临时数据, |
|
|
|
|
|
%% 并且还将控制字符的处理分为两个 |
|
|
|
|
|
%% 部分。 |
|
|
|
|
|
|
|
|
|
|
|
-spec fwrite(Format :: io:format(), Data :: [term()]) -> eFmt:chars(). |
|
|
fwrite(Format, Args) -> |
|
|
fwrite(Format, Args) -> |
|
|
build(scan(Format, Args)). |
|
|
build(scan(Format, Args)). |
|
|
|
|
|
|
|
|
-spec fwrite(Format, Data, Options) -> io_lib:chars() when |
|
|
|
|
|
Format :: io:format(), |
|
|
|
|
|
Data :: [term()], |
|
|
|
|
|
Options :: [Option], |
|
|
|
|
|
Option :: {'chars_limit', CharsLimit}, |
|
|
|
|
|
CharsLimit :: io_lib:chars_limit(). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-spec fwrite(Format :: io:format(), Data :: [term()], Options :: [{'chars_limit', CharsLimit :: integer()}]) -> eFmt:chars(). |
|
|
fwrite(Format, Args, Options) -> |
|
|
fwrite(Format, Args, Options) -> |
|
|
build(scan(Format, Args), Options). |
|
|
build(scan(Format, Args), Options). |
|
|
|
|
|
|
|
|
%% Build the output text for a pre-parsed format list. |
|
|
%% Build the output text for a pre-parsed format list. |
|
|
|
|
|
|
|
|
-spec build(FormatList) -> io_lib:chars() when |
|
|
|
|
|
FormatList :: [char() | io_lib:format_spec()]. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-spec build(FormatList :: [char() | eFmt:format_spec()]) -> eFmt:chars(). |
|
|
build(Cs) -> |
|
|
build(Cs) -> |
|
|
build(Cs, []). |
|
|
build(Cs, []). |
|
|
|
|
|
|
|
|
-spec build(FormatList, Options) -> io_lib:chars() when |
|
|
|
|
|
FormatList :: [char() | io_lib:format_spec()], |
|
|
|
|
|
Options :: [Option], |
|
|
|
|
|
Option :: {'chars_limit', CharsLimit}, |
|
|
|
|
|
CharsLimit :: io_lib:chars_limit(). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-spec build(FormatList :: [char() | eFmt:format_spec()], Options :: [{'chars_limit', CharsLimit :: integer()}]) -> eFmt:chars(). |
|
|
build(Cs, Options) -> |
|
|
build(Cs, Options) -> |
|
|
CharsLimit = get_option(chars_limit, Options, -1), |
|
|
|
|
|
|
|
|
CharsLimit = getOpt(chars_limit, Options, -1), |
|
|
Res1 = build_small(Cs), |
|
|
Res1 = build_small(Cs), |
|
|
{P, S, W, Other} = count_small(Res1), |
|
|
|
|
|
|
|
|
{P, S, W, Other} = count_small(Res1, 0, 0, 0, 0), |
|
|
case P + S + W of |
|
|
case P + S + W of |
|
|
0 -> |
|
|
0 -> |
|
|
Res1; |
|
|
Res1; |
|
@ -74,62 +58,17 @@ build(Cs, Options) -> |
|
|
-spec scan(Format, Data) -> FormatList when |
|
|
-spec scan(Format, Data) -> FormatList when |
|
|
Format :: io:format(), |
|
|
Format :: io:format(), |
|
|
Data :: [term()], |
|
|
Data :: [term()], |
|
|
FormatList :: [char() | io_lib:format_spec()]. |
|
|
|
|
|
|
|
|
FormatList :: [char() | eFmt:format_spec()]. |
|
|
|
|
|
|
|
|
scan(Format, Args) when is_atom(Format) -> |
|
|
|
|
|
scan(atom_to_list(Format), Args); |
|
|
|
|
|
scan(Format, Args) when is_binary(Format) -> |
|
|
|
|
|
scan(binary_to_list(Format), Args); |
|
|
|
|
|
scan(Format, Args) -> |
|
|
scan(Format, Args) -> |
|
|
collect(Format, Args). |
|
|
|
|
|
|
|
|
|
|
|
%% Revert a pre-parsed format list to a plain character list and a |
|
|
|
|
|
%% list of arguments. |
|
|
|
|
|
|
|
|
|
|
|
-spec unscan(FormatList) -> {Format, Data} when |
|
|
|
|
|
FormatList :: [char() | io_lib: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) -> "". |
|
|
|
|
|
|
|
|
if |
|
|
|
|
|
is_atom(Format) -> |
|
|
|
|
|
collect(atom_to_binary(Format, utf8), Args); |
|
|
|
|
|
is_list(Format) -> |
|
|
|
|
|
collect(list_to_binary(Format), Args); |
|
|
|
|
|
true -> |
|
|
|
|
|
collect(Format, Args) |
|
|
|
|
|
end. |
|
|
|
|
|
|
|
|
collect([$~ | Fmt0], Args0) -> |
|
|
collect([$~ | Fmt0], Args0) -> |
|
|
{C, Fmt1, Args1} = collect_cseq(Fmt0, Args0), |
|
|
{C, Fmt1, Args1} = collect_cseq(Fmt0, Args0), |
|
@ -217,32 +156,25 @@ collect_cc([$~ | Fmt], Args) when is_list(Args) -> {$~, [], Fmt, Args}; |
|
|
collect_cc([$n | Fmt], Args) when is_list(Args) -> {$n, [], Fmt, Args}; |
|
|
collect_cc([$n | Fmt], Args) when is_list(Args) -> {$n, [], Fmt, Args}; |
|
|
collect_cc([$i | Fmt], [A | Args]) -> {$i, [A], Fmt, Args}. |
|
|
collect_cc([$i | Fmt], [A | Args]) -> {$i, [A], Fmt, Args}. |
|
|
|
|
|
|
|
|
%% count_small([ControlC]) -> Count. |
|
|
|
|
|
%% Count the number of big (pPwWsS) print requests and |
|
|
|
|
|
%% number of characters of other print (small) requests. |
|
|
|
|
|
|
|
|
|
|
|
count_small(Cs) -> |
|
|
|
|
|
count_small(Cs, #{p => 0, s => 0, w => 0, other => 0}). |
|
|
|
|
|
|
|
|
|
|
|
count_small([#{control_char := $p} | Cs], #{p := P} = Cnts) -> |
|
|
|
|
|
count_small(Cs, Cnts#{p := P + 1}); |
|
|
|
|
|
count_small([#{control_char := $P} | Cs], #{p := P} = Cnts) -> |
|
|
|
|
|
count_small(Cs, Cnts#{p := P + 1}); |
|
|
|
|
|
count_small([#{control_char := $w} | Cs], #{w := W} = Cnts) -> |
|
|
|
|
|
count_small(Cs, Cnts#{w := W + 1}); |
|
|
|
|
|
count_small([#{control_char := $W} | Cs], #{w := W} = Cnts) -> |
|
|
|
|
|
count_small(Cs, Cnts#{w := W + 1}); |
|
|
|
|
|
count_small([#{control_char := $s} | Cs], #{w := W} = Cnts) -> |
|
|
|
|
|
count_small(Cs, Cnts#{w := W + 1}); |
|
|
|
|
|
count_small([S | Cs], #{other := Other} = Cnts) when is_list(S); |
|
|
|
|
|
is_binary(S) -> |
|
|
|
|
|
count_small(Cs, Cnts#{other := Other + io_lib:chars_length(S)}); |
|
|
|
|
|
count_small([C | Cs], #{other := Other} = Cnts) when is_integer(C) -> |
|
|
|
|
|
count_small(Cs, Cnts#{other := Other + 1}); |
|
|
|
|
|
count_small([], #{p := P, s := S, w := W, other := Other}) -> |
|
|
|
|
|
|
|
|
%% count_small([ControlC])->计数。计算大(pPwWsS)打印请求的数量和其他打印(小)请求的字符数。 |
|
|
|
|
|
count_small([#{control_char := $p} | Cs], P, S, W, Other) -> |
|
|
|
|
|
count_small(Cs, P + 1, S, W, Other); |
|
|
|
|
|
count_small([#{control_char := $P} | Cs], P, S, W, Other) -> |
|
|
|
|
|
count_small(Cs, P + 1, S, W, Other); |
|
|
|
|
|
count_small([#{control_char := $w} | Cs], P, S, W, Other) -> |
|
|
|
|
|
count_small(Cs, P, S, W + 1, Other); |
|
|
|
|
|
count_small([#{control_char := $W} | Cs], P, S, W, Other) -> |
|
|
|
|
|
count_small(Cs, P, S, W + 1, Other); |
|
|
|
|
|
count_small([#{control_char := $s} | Cs], P, S, W, Other) -> |
|
|
|
|
|
count_small(Cs, P, S, W + 1, Other); |
|
|
|
|
|
count_small([S | Cs], P, S, W, Other) when is_list(S);is_binary(S) -> |
|
|
|
|
|
count_small(Cs, P, S, W, Other + eFmt:chars_length(S)); |
|
|
|
|
|
count_small([C | Cs], P, S, W, Other) when is_integer(C) -> |
|
|
|
|
|
count_small(Cs, P, S, W, Other + 1); |
|
|
|
|
|
count_small([], P, S, W, Other) -> |
|
|
{P, S, W, Other}. |
|
|
{P, S, W, Other}. |
|
|
|
|
|
|
|
|
%% build_small([Control]) -> io_lib:chars(). |
|
|
|
|
|
|
|
|
%% build_small([Control]) -> eFmt:chars(). |
|
|
%% Interpret the control structures, but only the small ones. |
|
|
%% Interpret the control structures, but only the small ones. |
|
|
%% The big ones are saved for later. |
|
|
%% The big ones are saved for later. |
|
|
%% build_limited([Control], NumberOfPps, NumberOfLimited, |
|
|
%% build_limited([Control], NumberOfPps, NumberOfLimited, |
|
@ -251,8 +183,7 @@ count_small([], #{p := P, s := S, w := W, other := Other}) -> |
|
|
%% remaining and only calculate indentation when necessary. Must also |
|
|
%% remaining and only calculate indentation when necessary. Must also |
|
|
%% be smart when calculating indentation for characters in format. |
|
|
%% be smart when calculating indentation for characters in format. |
|
|
|
|
|
|
|
|
build_small([#{control_char := C, args := As, width := F, adjust := Ad, |
|
|
|
|
|
precision := P, pad_char := Pad, encoding := Enc} = CC | Cs]) -> |
|
|
|
|
|
|
|
|
build_small([#{control_char := C, args := As, width := F, adjust := Ad, precision := P, pad_char := Pad, encoding := Enc} = CC | Cs]) -> |
|
|
case control_small(C, As, F, Ad, P, Pad, Enc) of |
|
|
case control_small(C, As, F, Ad, P, Pad, Enc) of |
|
|
not_small -> [CC | build_small(Cs)]; |
|
|
not_small -> [CC | build_small(Cs)]; |
|
|
S -> lists:flatten(S) ++ build_small(Cs) |
|
|
S -> lists:flatten(S) ++ build_small(Cs) |
|
@ -274,7 +205,7 @@ build_limited([#{control_char := C, args := As, width := F, adjust := Ad, |
|
|
MaxLen0 < 0 -> % optimization |
|
|
MaxLen0 < 0 -> % optimization |
|
|
MaxLen0; |
|
|
MaxLen0; |
|
|
true -> |
|
|
true -> |
|
|
Len = io_lib:chars_length(S), |
|
|
|
|
|
|
|
|
Len = eFmt:chars_length(S), |
|
|
sub(MaxLen0, Len) |
|
|
sub(MaxLen0, Len) |
|
|
end, |
|
|
end, |
|
|
if |
|
|
if |
|
@ -298,7 +229,7 @@ decr_pc(_, Pc) -> Pc. |
|
|
%% indentation. We assume tabs at 8 cols. |
|
|
%% indentation. We assume tabs at 8 cols. |
|
|
|
|
|
|
|
|
-spec indentation(String, StartIndent) -> integer() when |
|
|
-spec indentation(String, StartIndent) -> integer() when |
|
|
String :: io_lib:chars(), |
|
|
|
|
|
|
|
|
String :: eFmt:chars(), |
|
|
StartIndent :: integer(). |
|
|
StartIndent :: integer(). |
|
|
|
|
|
|
|
|
indentation([$\n | Cs], _I) -> indentation(Cs, 0); |
|
|
indentation([$\n | Cs], _I) -> indentation(Cs, 0); |
|
@ -334,13 +265,13 @@ control_small($x, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A), |
|
|
is_atom(Prefix) -> |
|
|
is_atom(Prefix) -> |
|
|
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), true); |
|
|
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), true); |
|
|
control_small($x, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A) -> |
|
|
control_small($x, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A) -> |
|
|
true = io_lib:deep_char_list(Prefix), %Check if Prefix a character list |
|
|
|
|
|
|
|
|
true = eFmt:deep_char_list(Prefix), %Check if Prefix a character list |
|
|
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, true); |
|
|
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, true); |
|
|
control_small($X, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A), |
|
|
control_small($X, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A), |
|
|
is_atom(Prefix) -> |
|
|
is_atom(Prefix) -> |
|
|
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), false); |
|
|
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), false); |
|
|
control_small($X, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A) -> |
|
|
control_small($X, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A) -> |
|
|
true = io_lib:deep_char_list(Prefix), %Check if Prefix a character list |
|
|
|
|
|
|
|
|
true = eFmt:deep_char_list(Prefix), %Check if Prefix a character list |
|
|
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, false); |
|
|
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, false); |
|
|
control_small($+, [A], F, Adj, P, Pad, _Enc) when is_integer(A) -> |
|
|
control_small($+, [A], F, Adj, P, Pad, _Enc) when is_integer(A) -> |
|
|
Base = base(P), |
|
|
Base = base(P), |
|
@ -366,13 +297,13 @@ control_limited($s, [L0], F, Adj, P, Pad, unicode = Enc, _Str, CL, _I) -> |
|
|
L = cdata_to_chars(L0, F, CL), |
|
|
L = cdata_to_chars(L0, F, CL), |
|
|
uniconv(string(L, limit_field(F, CL), Adj, P, Pad, Enc)); |
|
|
uniconv(string(L, limit_field(F, CL), Adj, P, Pad, Enc)); |
|
|
control_limited($w, [A], F, Adj, P, Pad, Enc, _Str, CL, _I) -> |
|
|
control_limited($w, [A], F, Adj, P, Pad, Enc, _Str, CL, _I) -> |
|
|
Chars = io_lib:write(A, [{depth, -1}, {encoding, Enc}, {chars_limit, CL}]), |
|
|
|
|
|
|
|
|
Chars = eFmt:write(A, [{depth, -1}, {encoding, Enc}, {chars_limit, CL}]), |
|
|
term(Chars, F, Adj, P, Pad); |
|
|
term(Chars, F, Adj, P, Pad); |
|
|
control_limited($p, [A], F, Adj, P, Pad, Enc, Str, CL, I) -> |
|
|
control_limited($p, [A], F, Adj, P, Pad, Enc, Str, CL, I) -> |
|
|
print(A, -1, F, Adj, P, Pad, Enc, Str, CL, I); |
|
|
print(A, -1, F, Adj, P, Pad, Enc, Str, CL, I); |
|
|
control_limited($W, [A, Depth], F, Adj, P, Pad, Enc, _Str, CL, _I) |
|
|
control_limited($W, [A, Depth], F, Adj, P, Pad, Enc, _Str, CL, _I) |
|
|
when is_integer(Depth) -> |
|
|
when is_integer(Depth) -> |
|
|
Chars = io_lib:write(A, [{depth, Depth}, {encoding, Enc}, {chars_limit, CL}]), |
|
|
|
|
|
|
|
|
Chars = eFmt:write(A, [{depth, Depth}, {encoding, Enc}, {chars_limit, CL}]), |
|
|
term(Chars, F, Adj, P, Pad); |
|
|
term(Chars, F, Adj, P, Pad); |
|
|
control_limited($P, [A, Depth], F, Adj, P, Pad, Enc, Str, CL, I) |
|
|
control_limited($P, [A, Depth], F, Adj, P, Pad, Enc, Str, CL, I) |
|
|
when is_integer(Depth) -> |
|
|
when is_integer(Depth) -> |
|
@ -399,7 +330,7 @@ base(B) when is_integer(B) -> |
|
|
term(T, none, _Adj, none, _Pad) -> T; |
|
|
term(T, none, _Adj, none, _Pad) -> T; |
|
|
term(T, none, Adj, P, Pad) -> term(T, P, Adj, P, Pad); |
|
|
term(T, none, Adj, P, Pad) -> term(T, P, Adj, P, Pad); |
|
|
term(T, F, Adj, P0, Pad) -> |
|
|
term(T, F, Adj, P0, Pad) -> |
|
|
L = io_lib:chars_length(T), |
|
|
|
|
|
|
|
|
L = eFmt:chars_length(T), |
|
|
P = erlang:min(L, case P0 of none -> F; _ -> min(P0, F) end), |
|
|
P = erlang:min(L, case P0 of none -> F; _ -> min(P0, F) end), |
|
|
if |
|
|
if |
|
|
L > P -> |
|
|
L > P -> |
|
@ -424,7 +355,7 @@ print(T, D, F, right, P, _Pad, Enc, Str, ChLim, _I) -> |
|
|
{depth, D}, |
|
|
{depth, D}, |
|
|
{encoding, Enc}, |
|
|
{encoding, Enc}, |
|
|
{strings, Str}], |
|
|
{strings, Str}], |
|
|
io_lib_pretty:print(T, Options). |
|
|
|
|
|
|
|
|
eFmt_pretty:print(T, Options). |
|
|
|
|
|
|
|
|
%% fwrite_e(Float, Field, Adjust, Precision, PadChar) |
|
|
%% fwrite_e(Float, Field, Adjust, Precision, PadChar) |
|
|
|
|
|
|
|
@ -791,11 +722,11 @@ limit_field(F, CharsLimit) -> |
|
|
|
|
|
|
|
|
string(S, none, _Adj, none, _Pad, _Enc) -> S; |
|
|
string(S, none, _Adj, none, _Pad, _Enc) -> S; |
|
|
string(S, F, Adj, none, Pad, Enc) -> |
|
|
string(S, F, Adj, none, Pad, Enc) -> |
|
|
string_field(S, F, Adj, io_lib:chars_length(S), Pad, Enc); |
|
|
|
|
|
|
|
|
string_field(S, F, Adj, eFmt:chars_length(S), Pad, Enc); |
|
|
string(S, none, _Adj, P, Pad, Enc) -> |
|
|
string(S, none, _Adj, P, Pad, Enc) -> |
|
|
string_field(S, P, left, io_lib:chars_length(S), Pad, Enc); |
|
|
|
|
|
|
|
|
string_field(S, P, left, eFmt:chars_length(S), Pad, Enc); |
|
|
string(S, F, Adj, P, Pad, Enc) when F >= P -> |
|
|
string(S, F, Adj, P, Pad, Enc) when F >= P -> |
|
|
N = io_lib:chars_length(S), |
|
|
|
|
|
|
|
|
N = eFmt:chars_length(S), |
|
|
if F > P -> |
|
|
if F > P -> |
|
|
if N > P -> |
|
|
if N > P -> |
|
|
adjust(flat_trunc(S, P, Enc), chars(Pad, F - P), Adj); |
|
|
adjust(flat_trunc(S, P, Enc), chars(Pad, F - P), Adj); |
|
@ -909,9 +840,56 @@ sub(T, _) when T < 0 -> T; |
|
|
sub(T, E) when T >= E -> T - E; |
|
|
sub(T, E) when T >= E -> T - E; |
|
|
sub(_, _) -> 0. |
|
|
sub(_, _) -> 0. |
|
|
|
|
|
|
|
|
get_option(Key, TupleList, Default) -> |
|
|
|
|
|
|
|
|
getOpt(Key, TupleList, Default) -> |
|
|
case lists:keyfind(Key, 1, TupleList) of |
|
|
case lists:keyfind(Key, 1, TupleList) of |
|
|
false -> Default; |
|
|
|
|
|
{Key, Value} -> Value; |
|
|
|
|
|
_ -> Default |
|
|
|
|
|
|
|
|
{_, Value} -> |
|
|
|
|
|
Value; |
|
|
|
|
|
_ -> |
|
|
|
|
|
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) -> "". |