소스 검색

ft: 修改为二进制匹配

master
SisMaker 4 년 전
부모
커밋
705a69440b
1개의 변경된 파일194개의 추가작업 그리고 183개의 파일을 삭제
  1. +194
    -183
      src/eFmtFormat.erl

+ 194
- 183
src/eFmtFormat.erl 파일 보기

@ -36,40 +36,19 @@ fwrite(Format, Args) ->
fwrite(Format, Args, Options) ->
build(scan(Format, Args), Options).
%% Build the output text for a pre-parsed format list.
-spec build(FormatList :: [char() | eFmt:format_spec()]) -> eFmt:chars().
build(Cs) ->
build(Cs, []).
-spec build(FormatList :: [char() | eFmt:format_spec()], Options :: [{'chars_limit', CharsLimit :: integer()}]) -> eFmt:chars().
build(Cs, Options) ->
CharsLimit = getOpt(chars_limit, Options, -1),
Res1 = build_small(Cs),
{P, S, W, Other} = count_small(Res1, 0, 0, 0, 0),
case P + S + W of
0 ->
Res1;
NumOfLimited ->
RemainingChars = sub(CharsLimit, Other),
build_limited(Res1, P, NumOfLimited, RemainingChars, 0)
end.
%% Parse all control sequences in the format string.
-spec scan(Format :: io:format(), Data :: [term()]) -> FormatList :: [char() | eFmt:fmtSpec()].
-spec scan(Format, Data) -> FormatList when
Format :: io:format(),
Data :: [term()],
FormatList :: [char() | eFmt:format_spec()].
%% ~F.P.PadModC
scan(Format, Args) ->
if
is_atom(Format) ->
collect(atom_to_binary(Format, utf8), Args);
doCollect(atom_to_binary(Format, utf8), Args, []);
is_list(Format) ->
collect(list_to_binary(Format), Args);
doCollect(list_to_binary(Format), Args, []);
true ->
collect(Format, Args)
doCollect(Format, Args, [])
end.
doCollect(FmtBinStr, Args, Acc) ->
@ -77,109 +56,201 @@ doCollect(FmtBinStr, Args, Acc) ->
[NotMatch] ->
[NotMatch | Acc];
[FPart, LPart] ->
doCollectList(LPart, Args, [FPart | Acc]).
end,
doCollWidth(LPart, Args, 0, left, [FPart | Acc])
end.
%% ~F.P.PadModC
doCollectList(<<>>, _Args, Acc) ->
doCollWidth(<<>>, _Args, _Width, _Adjust, Acc) ->
Acc;
doCollectList(LPart, Args, Acc) ->
doCollWidth(LPart, Args, Width, Adjust, Acc) ->
%%
case LPart of
<<"-", FBin/binary>> ->
<<"-*", LeftLPart/binary>> ->
[WidthArgs | LeftArgs] = Args,
doCollPrecision(LeftLPart, LeftArgs, WidthArgs, left, Acc);
<<"-", LeftLPart/binary>> ->
doCollWidth(LeftLPart, Args, Width, left, Acc);
<<"*", LeftLPart/binary>> ->
[WidthArgs | LeftArgs] = Args,
doCollPrecision(LeftLPart, LeftArgs, WidthArgs, right, Acc);
<<WidthInt:8/integer, LeftLPart/binary>> ->
case WidthInt >= $0 andalso WidthInt =< $9 of
true ->
doCollWidth(LeftLPart, Args, 10 * Width + (WidthInt - $0), Adjust, Acc);
_ ->
doCollPrecision(LeftLPart, Args, Width, Adjust, Acc)
end
end.
doCollPrecision(LPart, Args, Width, Adjust, Acc) ->
case LPart of
<<".", LeftLPart/binary>> ->
doCollPrecision(LeftLPart, Args, Width, Adjust, 0, Acc);
_ ->
doCollPadChar(LPart, Args, Width, Adjust, none, Acc)
end.
doCollPrecision(LPart, Args, Width, Adjust, Precision, Acc) ->
case LPart of
<<"*", LeftLPart/binary>> ->
[PrecisionArgs | LeftArgs] = Args,
doCollPadChar(LeftLPart, LeftArgs, Width, Adjust, PrecisionArgs, Acc);
<<PrecisionInt:8/integer, LeftLPart/binary>> ->
case PrecisionInt >= $0 andalso PrecisionInt =< $9 of
true ->
doCollPrecision(LeftLPart, Args, Width, Adjust, 10 * Precision + (PrecisionInt - $0));
_ ->
case Precision == 0 of
true ->
doCollPadChar(LPart, Args, Width, Adjust, none, Acc);
_ ->
doCollPadChar(LPart, Args, Width, Adjust, Precision, Acc)
end
end
end.
doCollPadChar(LPart, Args, Width, Adjust, Precision, Acc) ->
case LPart of
<<".*", LeftLPart/binary>> ->
[PadChar | LeftArgs] = Args,
doCollEncoding(LeftLPart, LeftArgs, Width, Adjust, Precision, PadChar, Acc);
<<".", PadChar:8/integer, LeftLPart/binary>> ->
doCollEncoding(LeftLPart, Args, Width, Adjust, Precision, PadChar, Acc);
_ ->
doCollEncoding(LPart, Args, Width, Adjust, Precision, 32, Acc)
end.
doCollEncoding(LPart, Args, Width, Adjust, Precision, PadChar, Acc) ->
case LPart of
<<"t", Char:8/integer, LeftLPart/binary>> ->
true = Char =/= $l,
doCollStrings(LeftLPart, Args, Width, Adjust, Precision, PadChar, unicode, Acc);
_ ->
doCollStrings(LPart, Args, Width, Adjust, Precision, PadChar, latin1, Acc)
end.
doCollStrings(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, Acc) ->
case LPart of
<<"l", Char:8/integer, LeftLPart/binary>> ->
true = Char =/= $t,
doCollCA(LeftLPart, Args, Width, Adjust, Precision, PadChar, Encoding, false, Acc);
_ ->
doCollCA(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, true, Acc)
end.
doCollCA(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, Acc) ->
<<Char:8/integer, LeftLPart/binary>> = LPart,
[OneArgs | LeftArgs] = Args,
case Char of
$w -> As = OneArgs, NextArgs = LeftArgs;
$p -> As = OneArgs, NextArgs = LeftArgs;
$W -> [Depth | LastArgs] = LeftArgs, As = [OneArgs, Depth], NextArgs = LastArgs;
$P -> [Depth | LastArgs] = LeftArgs, As = [OneArgs, Depth], NextArgs = LastArgs;
$s -> As = OneArgs, NextArgs = LeftArgs;
$e -> As = OneArgs, NextArgs = LeftArgs;
$f -> As = OneArgs, NextArgs = LeftArgs;
$g -> As = OneArgs, NextArgs = LeftArgs;
$b -> As = OneArgs, NextArgs = LeftArgs;
$B -> As = OneArgs, NextArgs = LeftArgs;
$x -> [Prefix | LastArgs] = LeftArgs, As = [OneArgs, Prefix], NextArgs = LastArgs;
$X -> [Prefix | LastArgs] = LeftArgs, As = [OneArgs, Prefix], NextArgs = LastArgs;
$+ -> As = OneArgs, NextArgs = LeftArgs;
$# -> As = [OneArgs, NextArgs = LeftArgs;
$c -> As = OneArgs, NextArgs = LeftArgs;
$~ -> As = undefined, NextArgs = LeftArgs;
$n -> As = undefined, NextArgs = LeftArgs;
$i -> As = OneArgs, NextArgs = LeftArgs
end,
FmtSpec = #fmtSpec{ctlChar = Char, args = As, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings},
doCollect(LeftLPart, NextArgs, [FmtSpec | Acc]).
%% Build the output text for a pre-parsed format list.
-spec build(FormatList :: [char() | eFmt:fmtSpec()]) -> eFmt:chars().
build(Cs) ->
build(Cs, []).
-spec build(FormatList :: [char() | eFmt:fmtSpec()], Options :: [{'chars_limit', CharsLimit :: integer()}]) -> eFmt:chars().
build(Cs, Options) ->
CharsLimit = getOpt(chars_limit, Options, -1),
Res1 = buildSmall(Cs, []),
{P, S, W, Other} = count_small(Res1, 0, 0, 0, 0),
case P + S + W of
0 ->
Res1;
NumOfLimited ->
RemainingChars = sub(CharsLimit, Other),
build_limited(Res1, P, NumOfLimited, RemainingChars, 0)
end.
%% build_small([Control]) -> eFmt:chars().
%% Interpret the control structures, but only the small ones. The big ones are saved for later.
%% build_limited([Control], NumberOfPps, NumberOfLimited, CharsLimit, Indentation)
%% Interpret the control structures. Count the number of print
%% remaining and only calculate indentation when necessary. Must also
%% be smart when calculating indentation for characters in format.
buildSmall([], Acc) -> Acc;
buildSmall([OneCA | Cs], Acc) ->
case OneCA of
#fmtSpec{ctlChar = C, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding} ->
case ctlSmall(C, Args, Width, Adjust, Precision, PadChar, Encoding) of
not_small -> buildSmall(Cs, [OneCA | Acc]);
S -> buildSmall(Cs, [S | Acc])
end;
_ ->
buildSmall(Cs, [OneCA | Acc])
end.
ok.
collect([$~ | Fmt0], Args0) ->
{C, Fmt1, Args1} = collect_cseq(Fmt0, Args0),
[C | collect(Fmt1, Args1)];
collect([C | Fmt], Args) ->
[C | collect(Fmt, Args)];
collect([], []) -> [].
collect_cseq(Fmt0, Args0) ->
{F, Ad, Fmt1, Args1} = field_width(Fmt0, Args0),
{P, Fmt2, Args2} = precision(Fmt1, Args1),
{Pad, Fmt3, Args3} = pad_char(Fmt2, Args2),
Spec0 = #{width => F,
adjust => Ad,
precision => P,
pad_char => Pad,
encoding => latin1,
strings => true},
{Spec1, Fmt4} = modifiers(Fmt3, Spec0),
{C, As, Fmt5, Args4} = collect_cc(Fmt4, Args3),
Spec2 = Spec1#{control_char => C, args => As},
{Spec2, Fmt5, Args4}.
modifiers([$t | Fmt], Spec) ->
modifiers(Fmt, Spec#{encoding => unicode});
modifiers([$l | Fmt], Spec) ->
modifiers(Fmt, Spec#{strings => false});
modifiers(Fmt, Spec) ->
{Spec, Fmt}.
field_width([$- | Fmt0], Args0) ->
{F, Fmt, Args} = field_value(Fmt0, Args0),
field_width(-F, Fmt, Args);
field_width(Fmt0, Args0) ->
{F, Fmt, Args} = field_value(Fmt0, Args0),
field_width(F, Fmt, Args).
field_width(F, Fmt, Args) when F < 0 ->
{-F, left, Fmt, Args};
field_width(F, Fmt, Args) when F >= 0 ->
{F, right, Fmt, Args}.
precision([$. | Fmt], Args) ->
field_value(Fmt, Args);
precision(Fmt, Args) ->
{none, Fmt, Args}.
field_value([$* | Fmt], [A | Args]) when is_integer(A) ->
{A, Fmt, Args};
field_value([C | Fmt], Args) when is_integer(C), C >= $0, C =< $9 ->
field_value([C | Fmt], Args, 0);
field_value(Fmt, Args) ->
{none, Fmt, Args}.
field_value([C | Fmt], Args, F) when is_integer(C), C >= $0, C =< $9 ->
field_value(Fmt, Args, 10 * F + (C - $0));
field_value(Fmt, Args, F) -> %Default case
{F, Fmt, Args}.
pad_char([$., $* | Fmt], [Pad | Args]) -> {Pad, Fmt, Args};
pad_char([$., Pad | Fmt], Args) -> {Pad, Fmt, Args};
pad_char(Fmt, Args) -> {$\s, Fmt, Args}.
%% collect_cc([FormatChar], [Argument]) ->
%% {Control,[ControlArg],[FormatChar],[Arg]}.
%% Here we collect the argments for each control character.
%% Be explicit to cause failure early.
collect_cc([$w | Fmt], [A | Args]) -> {$w, [A], Fmt, Args};
collect_cc([$p | Fmt], [A | Args]) -> {$p, [A], Fmt, Args};
collect_cc([$W | Fmt], [A, Depth | Args]) -> {$W, [A, Depth], Fmt, Args};
collect_cc([$P | Fmt], [A, Depth | Args]) -> {$P, [A, Depth], Fmt, Args};
collect_cc([$s | Fmt], [A | Args]) -> {$s, [A], Fmt, Args};
collect_cc([$e | Fmt], [A | Args]) -> {$e, [A], Fmt, Args};
collect_cc([$f | Fmt], [A | Args]) -> {$f, [A], Fmt, Args};
collect_cc([$g | Fmt], [A | Args]) -> {$g, [A], Fmt, Args};
collect_cc([$b | Fmt], [A | Args]) -> {$b, [A], Fmt, Args};
collect_cc([$B | Fmt], [A | Args]) -> {$B, [A], Fmt, Args};
collect_cc([$x | Fmt], [A, Prefix | Args]) -> {$x, [A, Prefix], Fmt, Args};
collect_cc([$X | Fmt], [A, Prefix | Args]) -> {$X, [A, Prefix], Fmt, Args};
collect_cc([$+ | Fmt], [A | Args]) -> {$+, [A], Fmt, Args};
collect_cc([$# | Fmt], [A | Args]) -> {$#, [A], Fmt, Args};
collect_cc([$c | Fmt], [A | Args]) -> {$c, [A], Fmt, Args};
collect_cc([$~ | Fmt], Args) when is_list(Args) -> {$~, [], Fmt, Args};
collect_cc([$n | Fmt], Args) when is_list(Args) -> {$n, [], Fmt, Args};
collect_cc([$i | Fmt], [A | Args]) -> {$i, [A], Fmt, Args}.
%% control_small(FormatChar, [Argument], FieldWidth, Adjust, Precision,
%% PadChar, Encoding) -> String
%% control_limited(FormatChar, [Argument], FieldWidth, Adjust, Precision,
%% PadChar, Encoding, StringP, ChrsLim, Indentation) -> String
%% These are the dispatch functions for the various formatting controls.
ctlSmall($s, A, F, Adj, P, Pad, latin1 = Enc) when is_atom(A) ->
L = iolist_to_chars(atom_to_list(A)),
string(L, F, Adj, P, Pad, Enc);
ctlSmall($s, A, F, Adj, P, Pad, unicode = Enc) when is_atom(A) ->
string(atom_to_list(A), F, Adj, P, Pad, Enc);
ctlSmall($e, A, F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_e(A, F, Adj, P, Pad);
ctlSmall($f, A, F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_f(A, F, Adj, P, Pad);
ctlSmall($g, A, F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_g(A, F, Adj, P, Pad);
ctlSmall($b, A, F, Adj, P, Pad, _Enc) when is_integer(A) ->
unprefixed_integer(A, F, Adj, base(P), Pad, true);
ctlSmall($B, A, F, Adj, P, Pad, _Enc) when is_integer(A) ->
unprefixed_integer(A, F, Adj, base(P), Pad, false);
ctlSmall($x, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A),
is_atom(Prefix) ->
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), true);
ctlSmall($x, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A) ->
true = eFmt:deep_char_list(Prefix), %Check if Prefix a character list
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, true);
ctlSmall($X, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A),
is_atom(Prefix) ->
prefixed_integer(A, F, Adj, base(P), Pad, atom_to_list(Prefix), false);
ctlSmall($X, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A) ->
true = eFmt:deep_char_list(Prefix), %Check if Prefix a character list
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, false);
ctlSmall($+, A, F, Adj, P, Pad, _Enc) when is_integer(A) ->
Base = base(P),
Prefix = [integer_to_list(Base), $#],
prefixed_integer(A, F, Adj, Base, Pad, Prefix, true);
ctlSmall($#, A, F, Adj, P, Pad, _Enc) when is_integer(A) ->
Base = base(P),
Prefix = [integer_to_list(Base), $#],
prefixed_integer(A, F, Adj, Base, Pad, Prefix, false);
ctlSmall($c, A, F, Adj, P, Pad, unicode) when is_integer(A) ->
char(A, F, Adj, P, Pad);
ctlSmall($c, A, F, Adj, P, Pad, _Enc) when is_integer(A) ->
char(A band 255, F, Adj, P, Pad);
ctlSmall($~, _A, F, Adj, P, Pad, _Enc) -> char($~, F, Adj, P, Pad);
ctlSmall($n, _A, F, Adj, P, Pad, _Enc) -> newline(F, Adj, P, Pad);
ctlSmall($i, _A, _F, _Adj, _P, _Pad, _Enc) -> [];
ctlSmall(_C, _A, _F, _Adj, _P, _Pad, _Enc) -> not_small.
%% count_small[ControlC]->pPwWsS
count_small([#{control_char := $p} | Cs], P, S, W, Other) ->
@ -199,20 +270,8 @@ count_small([C | Cs], P, S, W, Other) when is_integer(C) ->
count_small([], P, S, W, Other) ->
{P, S, W, Other}.
%% build_small([Control]) -> eFmt:chars().
%% Interpret the control structures, but only the small ones. The big ones are saved for later.
%% build_limited([Control], NumberOfPps, NumberOfLimited, CharsLimit, Indentation)
%% Interpret the control structures. Count the number of print
%% remaining and only calculate indentation when necessary. Must also
%% 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]) ->
case control_small(C, As, F, Ad, P, Pad, Enc) of
not_small -> [CC | build_small(Cs)];
S -> lists:flatten(S) ++ build_small(Cs)
end;
build_small([C | Cs]) -> [C | build_small(Cs)];
build_small([]) -> [].
build_limited([#{control_char := C, args := As, width := F, adjust := Ad, precision := P, pad_char := Pad, encoding := Enc, strings := Str} | Cs], NumOfPs0, Count0, MaxLen0, I) ->
MaxChars = if
@ -261,55 +320,7 @@ indentation([C | Cs], I) ->
indentation(Cs, indentation(C, I));
indentation([], I) -> I.
%% control_small(FormatChar, [Argument], FieldWidth, Adjust, Precision,
%% PadChar, Encoding) -> String
%% control_limited(FormatChar, [Argument], FieldWidth, Adjust, Precision,
%% PadChar, Encoding, StringP, ChrsLim, Indentation) -> String
%% These are the dispatch functions for the various formatting controls.
control_small($s, [A], F, Adj, P, Pad, latin1 = Enc) when is_atom(A) ->
L = iolist_to_chars(atom_to_list(A)),
string(L, F, Adj, P, Pad, Enc);
control_small($s, [A], F, Adj, P, Pad, unicode = Enc) when is_atom(A) ->
string(atom_to_list(A), F, Adj, P, Pad, Enc);
control_small($e, [A], F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_e(A, F, Adj, P, Pad);
control_small($f, [A], F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_f(A, F, Adj, P, Pad);
control_small($g, [A], F, Adj, P, Pad, _Enc) when is_float(A) ->
fwrite_g(A, F, Adj, P, Pad);
control_small($b, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
unprefixed_integer(A, F, Adj, base(P), Pad, true);
control_small($B, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
unprefixed_integer(A, F, Adj, base(P), Pad, false);
control_small($x, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A),
is_atom(Prefix) ->
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) ->
true = eFmt:deep_char_list(Prefix), %Check if Prefix a character list
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, true);
control_small($X, [A, Prefix], F, Adj, P, Pad, _Enc) when is_integer(A),
is_atom(Prefix) ->
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) ->
true = eFmt:deep_char_list(Prefix), %Check if Prefix a character list
prefixed_integer(A, F, Adj, base(P), Pad, Prefix, false);
control_small($+, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
Base = base(P),
Prefix = [integer_to_list(Base), $#],
prefixed_integer(A, F, Adj, Base, Pad, Prefix, true);
control_small($#, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
Base = base(P),
Prefix = [integer_to_list(Base), $#],
prefixed_integer(A, F, Adj, Base, Pad, Prefix, false);
control_small($c, [A], F, Adj, P, Pad, unicode) when is_integer(A) ->
char(A, F, Adj, P, Pad);
control_small($c, [A], F, Adj, P, Pad, _Enc) when is_integer(A) ->
char(A band 255, F, Adj, P, Pad);
control_small($~, [], F, Adj, P, Pad, _Enc) -> char($~, F, Adj, P, Pad);
control_small($n, [], F, Adj, P, Pad, _Enc) -> newline(F, Adj, P, Pad);
control_small($i, [_A], _F, _Adj, _P, _Pad, _Enc) -> [];
control_small(_C, _As, _F, _Adj, _P, _Pad, _Enc) -> not_small.
control_limited($s, [L0], F, Adj, P, Pad, latin1 = Enc, _Str, CL, _I) ->
L = iolist_to_chars(L0, F, CL),

불러오는 중...
취소
저장