您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

774 行
29 KiB

4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
4 年前
  1. -module(eFmt).
  2. -compile(inline).
  3. -compile({inline_size, 128}).
  4. -include("eFmt.hrl").
  5. -export([
  6. %% eFmt
  7. format/2
  8. , format/3
  9. , scan/2
  10. , build/1
  11. , build/2
  12. , print/1
  13. , print/4
  14. , write/1
  15. , write/2
  16. , write/3
  17. , write/4
  18. %% eFmtformat
  19. , fWrite/2
  20. , fWrite/3
  21. , fScan/2
  22. , fBuild/1
  23. , fBuild/2
  24. %% eFmtPretty
  25. %% utils
  26. , toLowerStr/1
  27. , toUpperStr/1
  28. , toBinary/1
  29. , charsLen/1
  30. ]).
  31. %% ********************************************** eFmt start ***********************************************************
  32. -type chars() :: [char() | chars() | binary()].
  33. -type depth() :: -1 | non_neg_integer().
  34. -type encoding() :: epp:source_encoding() | 'unicode'.
  35. -type charsLimit() :: integer().
  36. -type fmtSpec() :: #fmtSpec{}.
  37. -spec format(Format :: io:format(), Data :: [term()]) -> chars().
  38. format(Format, Args) ->
  39. try fWrite(Format, Args)
  40. catch
  41. _C:_R ->
  42. erlang:error(badarg, [Format, Args])
  43. end.
  44. -spec format(Format :: io:format(), Data :: [term()], Options :: [{charsLimit, CharsLimit :: charsLimit()}]) -> chars().
  45. format(Format, Args, Options) ->
  46. try fWrite(Format, Args, Options)
  47. catch
  48. _C:_R ->
  49. erlang:error(badarg, [Format, Args])
  50. end.
  51. -spec scan(Format :: io:format(), Data :: [term()]) -> FormatList :: [char() | fmtSpec()].
  52. scan(Format, Args) ->
  53. try fScan(Format, Args)
  54. catch
  55. _C:_R ->
  56. erlang:error(badarg, [Format, Args])
  57. end.
  58. -spec build(FormatList :: [char() | fmtSpec()]) -> chars().
  59. build(FormatList) ->
  60. try fBuild(FormatList)
  61. catch
  62. _C:_R ->
  63. erlang:error(badarg, [FormatList])
  64. end.
  65. -spec build(FormatList :: [char() | fmtSpec()], Options :: [{charsLimit, CharsLimit :: charsLimit()}]) -> chars().
  66. build(FormatList, Options) ->
  67. try fBuild(FormatList, Options)
  68. catch
  69. _C:_R ->
  70. erlang:error(badarg, [FormatList, Options])
  71. end.
  72. -spec print(Term :: term()) -> chars().
  73. print(Term) ->
  74. eFmtPretty:pPrint(Term).
  75. -spec print(Term :: term(), Column :: non_neg_integer(), LineLength :: non_neg_integer(), Depth :: depth()) -> chars().
  76. print(Term, Column, LineLength, Depth) ->
  77. eFmtPretty:pPrint(Term, Column, LineLength, Depth).
  78. -spec write(Term :: term()) -> chars().
  79. write(Term) ->
  80. writeTerm(Term, -1, latin1).
  81. -spec write(Term :: term(), Depth :: depth()) -> chars().
  82. write(Term, Depth) ->
  83. writeTerm(Term, Depth, latin1).
  84. -spec write(Term :: term(), Depth :: depth(), IsPretty :: boolean()) -> chars().
  85. write(Term, Depth, IsPretty) ->
  86. case IsPretty of
  87. true ->
  88. eFmtPretty:pPrint(Term, 1, 80, Depth);
  89. _ ->
  90. writeTerm(Term, Depth, latin1)
  91. end.
  92. -spec write(Term :: term(), Depth :: depth(), Encoding :: encoding(), CharsLimit :: charsLimit()) -> chars().
  93. write(Term, Depth, Encoding, CharsLimit) ->
  94. if
  95. Depth =:= 0 orelse CharsLimit =:= 0 ->
  96. <<"...">>;
  97. CharsLimit < 0 ->
  98. writeTerm(Term, Depth, Encoding);
  99. true ->
  100. RecDefFun = fun(_, _) -> no end,
  101. If = eFmtPretty:pIntermediate(Term, Depth, CharsLimit, RecDefFun, Encoding, _Str = false),
  102. eFmtPretty:pWrite(If)
  103. end.
  104. -define(writeInt(Int), integer_to_binary(Term)).
  105. -define(writeFloat(Float), floatG(Term)).
  106. -define(writeAtom(Atom, Encoding), <<"'", (atom_to_binary(Atom, Encoding))/binary, "'">>).
  107. -define(writePort(Port), list_to_binary(erlang:port_to_list(Port))).
  108. -define(writeRef(Ref), list_to_binary(erlang:ref_to_list(Ref))).
  109. -define(writePid(Ref), list_to_binary(erlang:pid_to_list(Ref))).
  110. -define(writeFun(Fun), list_to_binary(erlang:fun_to_list(Fun))).
  111. writeList([], _D, _E, BinAcc) ->
  112. <<BinAcc/binary, "]">>;
  113. writeList([One], D, E, BinAcc) ->
  114. <<BinAcc/binary, (writeTerm(One, D, E))/binary, "]">>;
  115. writeList([One | List], D, E, BinAcc) ->
  116. if
  117. D =:= 1 -> <<BinAcc, "|...]">>;
  118. true ->
  119. writeList(List, D - 1, E, <<BinAcc/binary, (writeTerm(One, D, E))/binary, ",">>)
  120. end;
  121. writeList(Other, D, E, BinAcc) ->
  122. <<BinAcc/binary, "|", (writeTerm(Other, D, E))/binary, "]">>.
  123. writeTuple(Tuple, D, E, Index, TupleSize, BinAcc) ->
  124. if
  125. D =:= 1 -> <<BinAcc/binary, "...}">>;
  126. true ->
  127. if
  128. Index < TupleSize ->
  129. writeTuple(Tuple, D - 1, E, Index + 1, TupleSize, <<BinAcc/binary, (writeTerm(element(Index, Tuple), D - 1, E))/binary, ",">>);
  130. Index == TupleSize ->
  131. <<BinAcc/binary, (writeTerm(element(Index, Tuple), D - 1, E))/binary, "}">>;
  132. true ->
  133. <<BinAcc/binary, "}">>
  134. end
  135. end.
  136. writeMap(Map, D, E, BinAcc) when is_integer(D) ->
  137. if
  138. D =:= 1 ->
  139. <<BinAcc/binary, "...}">>;
  140. true ->
  141. writeMapBody(maps:iterator(Map), D, E, BinAcc)
  142. end.
  143. writeMapBody(I, D, E, BinAcc) ->
  144. if
  145. D =:= 1 ->
  146. <<BinAcc/binary, " ...}">>;
  147. true ->
  148. case maps:next(I) of
  149. {K, V, none} ->
  150. <<BinAcc/binary, (writeTerm(K, -1, E))/binary, " => ", (writeTerm(V, D, E))/binary, "}">>;
  151. {K, V, NextI} ->
  152. writeMapBody(NextI, D - 1, E, <<BinAcc/binary, (writeTerm(K, -1, E))/binary, " => ", (writeTerm(V, D, E))/binary, ",">>);
  153. none ->
  154. <<BinAcc/binary, "}">>
  155. end
  156. end.
  157. writeBinary(Bin, D, BinAcc) ->
  158. if
  159. D == 1 ->
  160. <<BinAcc/binary, "...>>">>;
  161. true ->
  162. case Bin of
  163. <<>> ->
  164. <<BinAcc/binary, ">>">>;
  165. <<Int:8>> ->
  166. <<BinAcc/binary, (integer_to_binary(Int))/binary, ">>">>;
  167. <<Int:8, LeftBin/bitstring>> ->
  168. writeBinary(LeftBin, D - 1, <<BinAcc/binary, (integer_to_binary(Int))/binary, ",">>);
  169. _ ->
  170. L = bit_size(Bin),
  171. <<X:L>> = Bin,
  172. <<BinAcc/binary, (integer_to_binary(X))/binary, ":", (integer_to_binary(L))/binary, ">>">>
  173. end
  174. end.
  175. writeTerm(_Term, 0, _E) -> <<"...">>;
  176. writeTerm(Term, _D, _E) when is_integer(Term) -> ?writeInt(Term);
  177. writeTerm(Atom, _D, E) when is_atom(Atom) -> ?writeAtom(Atom, E);
  178. writeTerm(Term, D, E) when is_list(Term) -> writeList(Term, D, E, <<"[">>);
  179. writeTerm(Term, D, E) when is_map(Term) -> writeMap(Term, D, E, <<"#{">>);
  180. writeTerm(Term, D, E) when is_tuple(Term) -> writeTuple(Term, D, E, 1, tuple_size(Term), <<"{">>);
  181. writeTerm(Term, D, _E) when is_bitstring(Term) -> writeBinary(Term, D, <<"<<">>);
  182. writeTerm(Term, _D, _E) when is_pid(Term) -> ?writePid(Term);
  183. writeTerm(Term, _D, _E) when is_float(Term) -> ?writeFloat(Term);
  184. writeTerm(Term, _D, _E) when is_port(Term) -> ?writePort(Term);
  185. writeTerm(Term, _D, _E) when is_reference(Term) -> ?writeRef(Term);
  186. writeTerm(Term, _D, _E) when is_function(Term) -> ?writeFun(Term).
  187. %% ********************************************** eFmt end *************************************************************
  188. %% ********************************************** eFmtFormat start *****************************************************
  189. -spec fWrite(Format :: io:format(), Data :: [term()]) -> chars().
  190. fWrite(Format, Args) ->
  191. fBuild(fScan(Format, Args), []).
  192. -spec fWrite(Format :: io:format(), Data :: [term()], Options :: [{'chars_limit', CharsLimit :: integer()}]) -> chars().
  193. fWrite(Format, Args, Options) ->
  194. fBuild(fScan(Format, Args), Options).
  195. %% Parse all control sequences in the format string.
  196. -spec fScan(Format :: io:format(), Data :: [term()]) -> FormatList :: [char() | fmtSpec()].
  197. %% 格式 ~F.P.PadModC
  198. fScan(Format, Args) ->
  199. if
  200. is_atom(Format) ->
  201. doCollect(atom_to_binary(Format, utf8), Args, []);
  202. is_list(Format) ->
  203. doCollect(list_to_binary(Format), Args, []);
  204. true ->
  205. doCollect(Format, Args, [])
  206. end.
  207. doCollect(FmtBinStr, Args, Acc) ->
  208. case binary:split(FmtBinStr, <<"~">>) of
  209. [NotMatch] ->
  210. [NotMatch | Acc];
  211. [FPart, LPart] ->
  212. doCollWidth(LPart, Args, 0, right, [FPart | Acc])
  213. end.
  214. doCollWidth(<<>>, _Args, _Width, _Adjust, Acc) ->
  215. Acc;
  216. doCollWidth(LPart, Args, Width, Adjust, Acc) ->
  217. case LPart of
  218. <<"-*", LeftLPart/binary>> ->
  219. [WidthArgs | LeftArgs] = Args,
  220. doCollPrecision(LeftLPart, LeftArgs, WidthArgs, left, Acc);
  221. <<"-", LeftLPart/binary>> ->
  222. doCollWidth(LeftLPart, Args, Width, left, Acc);
  223. <<"*", LeftLPart/binary>> ->
  224. [WidthArgs | LeftArgs] = Args,
  225. doCollPrecision(LeftLPart, LeftArgs, WidthArgs, right, Acc);
  226. <<WidthInt:8/integer, LeftLPart/binary>> ->
  227. case WidthInt >= $0 andalso WidthInt =< $9 of
  228. true ->
  229. doCollWidth(LeftLPart, Args, 10 * Width + (WidthInt - $0), Adjust, Acc);
  230. _ ->
  231. case Width == 0 of
  232. true ->
  233. doCollPrecision(LPart, Args, none, left, Acc);
  234. _ ->
  235. doCollPrecision(LPart, Args, Width, Adjust, Acc)
  236. end
  237. end
  238. end.
  239. doCollPrecision(LPart, Args, Width, Adjust, Acc) ->
  240. case LPart of
  241. <<".", LeftLPart/binary>> ->
  242. doCollPrecision(LeftLPart, Args, Width, Adjust, 0, Acc);
  243. _ ->
  244. doCollPadChar(LPart, Args, Width, Adjust, none, Acc)
  245. end.
  246. doCollPrecision(LPart, Args, Width, Adjust, Precision, Acc) ->
  247. case LPart of
  248. <<"*", LeftLPart/binary>> ->
  249. [PrecisionArgs | LeftArgs] = Args,
  250. doCollPadChar(LeftLPart, LeftArgs, Width, Adjust, PrecisionArgs, Acc);
  251. <<PrecisionInt:8/integer, LeftLPart/binary>> ->
  252. case PrecisionInt >= $0 andalso PrecisionInt =< $9 of
  253. true ->
  254. doCollPrecision(LeftLPart, Args, Width, Adjust, 10 * Precision + (PrecisionInt - $0), Acc);
  255. _ ->
  256. case Precision == 0 of
  257. true ->
  258. doCollPadChar(LPart, Args, Width, Adjust, none, Acc);
  259. _ ->
  260. doCollPadChar(LPart, Args, Width, Adjust, Precision, Acc)
  261. end
  262. end
  263. end.
  264. doCollPadChar(LPart, Args, Width, Adjust, Precision, Acc) ->
  265. case LPart of
  266. <<".*", LeftLPart/binary>> ->
  267. [PadChar | LeftArgs] = Args,
  268. doCollEncoding(LeftLPart, LeftArgs, Width, Adjust, Precision, PadChar, Acc);
  269. <<".", PadChar:8/integer, LeftLPart/binary>> ->
  270. doCollEncoding(LeftLPart, Args, Width, Adjust, Precision, PadChar, Acc);
  271. _ ->
  272. doCollEncoding(LPart, Args, Width, Adjust, Precision, 32, Acc)
  273. end.
  274. doCollEncoding(LPart, Args, Width, Adjust, Precision, PadChar, Acc) ->
  275. case LPart of
  276. <<"t", LeftLPart/binary>> ->
  277. %true = Char =/= $l,
  278. doCollStrings(LeftLPart, Args, Width, Adjust, Precision, PadChar, unicode, Acc);
  279. _ ->
  280. doCollStrings(LPart, Args, Width, Adjust, Precision, PadChar, latin1, Acc)
  281. end.
  282. doCollStrings(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, Acc) ->
  283. case LPart of
  284. <<"l", LeftLPart/binary>> ->
  285. %true = Char =/= $t,
  286. doCollCA(LeftLPart, Args, Width, Adjust, Precision, PadChar, Encoding, false, Acc);
  287. _ ->
  288. doCollCA(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, true, Acc)
  289. end.
  290. doCollCA(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, Acc) ->
  291. <<CtlChar:8/integer, LeftLPart/binary>> = LPart,
  292. case CtlChar of
  293. $w -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  294. $p -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  295. $W -> [OneArgs | LeftArgs] = Args, [Depth | LastArgs] = LeftArgs, As = [OneArgs, Depth], NextArgs = LastArgs;
  296. $P -> [OneArgs | LeftArgs] = Args, [Depth | LastArgs] = LeftArgs, As = [OneArgs, Depth], NextArgs = LastArgs;
  297. $s -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  298. $e -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  299. $f -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  300. $g -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  301. $b -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  302. $B -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  303. $x -> [OneArgs | LeftArgs] = Args, [Prefix | LastArgs] = LeftArgs, As = [OneArgs, Prefix], NextArgs = LastArgs;
  304. $X -> [OneArgs | LeftArgs] = Args, [Prefix | LastArgs] = LeftArgs, As = [OneArgs, Prefix], NextArgs = LastArgs;
  305. $+ -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  306. $# -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  307. $c -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  308. $~ -> As = undefined, NextArgs = Args;
  309. $n -> As = undefined, NextArgs = Args;
  310. $i -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs
  311. end,
  312. FmtSpec = #fmtSpec{ctlChar = CtlChar, args = As, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings},
  313. doCollect(LeftLPart, NextArgs, [FmtSpec | Acc]).
  314. %% Build the output text for a pre-parsed format list.
  315. -spec fBuild(FormatList :: [char() | fmtSpec()]) -> chars().
  316. fBuild(Cs) ->
  317. fBuild(Cs, []).
  318. -spec fBuild(FormatList :: [char() | fmtSpec()], Options :: [{'chars_limit', CharsLimit :: integer()}]) -> chars().
  319. fBuild(Cs, Options) ->
  320. CharsLimit = getOpt(chars_limit, Options, -1),
  321. ResList = buildSmall(Cs, []),
  322. {P, S, W, Other} = cntSmall(ResList, 0, 0, 0, 0),
  323. NumOfLimited = P + S + W,
  324. case NumOfLimited of
  325. 0 ->
  326. ResList;
  327. _ ->
  328. RemainChars = remainChars(CharsLimit, Other),
  329. buildLimited(ResList, P, NumOfLimited, RemainChars, 0, [])
  330. end.
  331. buildSmall([], Acc) -> Acc;
  332. buildSmall([OneCA | Cs], Acc) ->
  333. case OneCA of
  334. #fmtSpec{ctlChar = CtlChar, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding} ->
  335. case ctlSmall(CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding) of
  336. not_small -> buildSmall(Cs, [OneCA | Acc]);
  337. ignore -> buildSmall(Cs, Acc);
  338. Str -> buildSmall(Cs, [Str | Acc])
  339. end;
  340. _ ->
  341. buildSmall(Cs, [OneCA | Acc])
  342. end.
  343. ctlSmall($s, Args, Width, Adjust, Precision, PadChar, Encoding) when is_atom(Args) ->
  344. case Encoding of
  345. latin1 ->
  346. AtomBinStr = ?writeAtom(Args, latin1);
  347. _ ->
  348. AtomBinStr = ?writeAtom(Args, uft8)
  349. end,
  350. string(AtomBinStr, Width, Adjust, Precision, PadChar, Encoding);
  351. ctlSmall($e, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_float(Args) ->
  352. floatE(Args, Width, Adjust, Precision, PadChar);
  353. ctlSmall($f, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_float(Args) ->
  354. floatF(Args, Width, Adjust, Precision, PadChar);
  355. ctlSmall($g, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_float(Args) ->
  356. floatG(Args, Width, Adjust, Precision, PadChar);
  357. ctlSmall($b, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  358. unPrefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, true);
  359. ctlSmall($B, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  360. unPrefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, false);
  361. ctlSmall($x, [Args, Prefix], Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args), is_atom(Prefix) ->
  362. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, atom_to_binary(Prefix, utf8), true);
  363. ctlSmall($x, [Args, Prefix], Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  364. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, Prefix, true);
  365. ctlSmall($X, [Args, Prefix], Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args), is_atom(Prefix) ->
  366. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, atom_to_binary(Prefix, utf8), false);
  367. ctlSmall($X, [Args, Prefix], Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  368. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, Prefix, false);
  369. ctlSmall($+, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  370. Base = ?base(Precision),
  371. prefixedInt(Args, Width, Adjust, Base, PadChar, integer_to_binary(Base), $#, true);
  372. ctlSmall($#, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  373. Base = ?base(Precision),
  374. prefixedInt(Args, Width, Adjust, Base, PadChar, integer_to_binary(Base), $#, false);
  375. ctlSmall($c, Args, Width, Adjust, Precision, PadChar, Encoding) when is_integer(Args) ->
  376. case Encoding of
  377. unicode ->
  378. char(Args, Width, Adjust, Precision, PadChar);
  379. _ ->
  380. char(Args band 255, Width, Adjust, Precision, PadChar)
  381. end;
  382. ctlSmall($~, _Args, Width, Adjust, Precision, PadChar, _Encoding) -> char($~, Width, Adjust, Precision, PadChar);
  383. ctlSmall($n, _Args, Width, Adjust, Precision, PadChar, _Encoding) -> newline(Width, Adjust, Precision, PadChar);
  384. ctlSmall($i, _Args, _Width, _Adjust, _Precision, _PadChar, _Encoding) -> ignore;
  385. ctlSmall(_C, _Args, _Width, _Adjust, _Precision, _PadChar, _Encoding) -> not_small.
  386. cntSmall([], P, S, W, Other) ->
  387. {P, S, W, Other};
  388. cntSmall([OneRes | Cs], P, S, W, Other) ->
  389. case OneRes of
  390. #fmtSpec{ctlChar = CtlChar} ->
  391. case CtlChar of
  392. $p ->
  393. cntSmall(Cs, P + 1, S, W, Other);
  394. $P ->
  395. cntSmall(Cs, P + 1, S, W, Other);
  396. $w ->
  397. cntSmall(Cs, P, S, W + 1, Other);
  398. $W ->
  399. cntSmall(Cs, P, S, W + 1, Other);
  400. $s ->
  401. cntSmall(Cs, P, S, W + 1, Other);
  402. _ ->
  403. cntSmall(Cs, P, S, W, Other)
  404. end;
  405. _ ->
  406. if
  407. is_binary(OneRes) orelse is_list(OneRes) ->
  408. cntSmall(Cs, P, S, W, Other + charsLen(OneRes));
  409. is_integer(OneRes) ->
  410. cntSmall(Cs, P, S, W, Other + 1);
  411. true ->
  412. cntSmall(Cs, P, S, W, Other)
  413. end
  414. end.
  415. buildLimited([], _, _, _, _, Acc) -> Acc;
  416. buildLimited([OneCA | Cs], NumOfPs, Count, MaxLen, I, Acc) ->
  417. case OneCA of
  418. #fmtSpec{ctlChar = CtlChar, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings} ->
  419. MaxChars = if MaxLen < 0 -> MaxLen; true -> MaxLen div Count end,
  420. IoListStr = ctlLimited(CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I),
  421. NewNumOfPs = decrPc(CtlChar, NumOfPs),
  422. NewCount = Count - 1,
  423. MaxLen = ?IIF(MaxLen < 0, MaxLen, remainChars(MaxLen, charsLen(IoListStr))),
  424. if
  425. NewNumOfPs > 0 ->
  426. buildLimited(Cs, NewNumOfPs, NewCount, MaxLen, I, [IoListStr | Acc]);
  427. true ->
  428. buildLimited(Cs, NewNumOfPs, NewCount, MaxLen, I, [IoListStr | Acc])
  429. end;
  430. _ ->
  431. buildLimited(Cs, NumOfPs, Count, MaxLen, I + 1, [OneCA | Acc])
  432. end.
  433. decrPc($p, Pc) -> Pc - 1;
  434. decrPc($P, Pc) -> Pc - 1;
  435. decrPc(_, Pc) -> Pc.
  436. %% (CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I)
  437. ctlLimited($s, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  438. case Encoding of
  439. latin1 ->
  440. BinStr = erlang:iolist_to_binary(Args);
  441. _ ->
  442. BinStr = case catch unicode:characters_to_binary(Args, unicode) of
  443. Str when is_binary(Str) -> Str;
  444. _ -> toBinary(Args)
  445. end
  446. end,
  447. TemBinStr = strToChars(BinStr, Width, CharsLimit),
  448. string(TemBinStr, ?IIF(CharsLimit < 0 orelse Width =:= none, Width, max(3, min(Width, CharsLimit))), Adjust, Precision, PadChar, Encoding);
  449. ctlLimited($w, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  450. Chars = write(Args, -1, Encoding, CharsLimit),
  451. term(Chars, Width, Adjust, Precision, PadChar);
  452. ctlLimited($p, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I) ->
  453. print(Args, -1, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I);
  454. ctlLimited($W, [Args, Depth], Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  455. Chars = write(Args, Depth, Encoding, CharsLimit),
  456. term(Chars, Width, Adjust, Precision, PadChar);
  457. ctlLimited($P, [Args, Depth], Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I) ->
  458. print(Args, Depth, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I).
  459. term(BinStrOrIoList, Width, Adjust, Precision, PadChar) ->
  460. if
  461. Width == none andalso Precision == none ->
  462. BinStrOrIoList;
  463. Width == none ->
  464. StrLen = charsLen(BinStrOrIoList),
  465. NewPrecision = erlang:min(StrLen, Precision),
  466. if
  467. StrLen > NewPrecision ->
  468. adjust(Adjust, makePadChars($*, NewPrecision, <<>>), <<>>);
  469. true ->
  470. adjust(Adjust, BinStrOrIoList, makePadChars(PadChar, Precision - StrLen, <<>>))
  471. end;
  472. true ->
  473. StrLen = charsLen(BinStrOrIoList),
  474. NewPrecision = erlang:min(StrLen, case Precision of none -> Width; _ -> min(Precision, Width) end),
  475. if
  476. StrLen > NewPrecision ->
  477. adjust(Adjust, makePadChars($*, NewPrecision, <<>>), makePadChars(PadChar, Width - NewPrecision, <<>>));
  478. true ->
  479. adjust(Adjust, BinStrOrIoList, makePadChars(PadChar, Width - StrLen, <<>>))
  480. end
  481. end.
  482. print(Term, Depth, Width, _Adjust, Precision, _PadChar, Encoding, Strings, CharsLimit, I) ->
  483. if
  484. Width == none -> NewWidth = 80;
  485. true -> NewWidth = Width
  486. end,
  487. if
  488. Precision == none -> NewPrecision = I + 1;
  489. true -> NewPrecision = Precision
  490. end,
  491. eFmtPretty:print(Term, NewPrecision, NewWidth, Depth, -1, CharsLimit, no_fun, Encoding, Strings).
  492. floatE(Float, Width, Adjust, Precision, PadChar) ->
  493. case Precision of
  494. none ->
  495. NewPrecision = 6;
  496. _ ->
  497. NewPrecision = Precision
  498. end,
  499. case Width of
  500. none ->
  501. float_to_binary(Float, [{scientific, NewPrecision}]);
  502. _ ->
  503. term(float_to_binary(Float, [{scientific, NewPrecision}]), Width, Adjust, Width, PadChar)
  504. end.
  505. floatF(Float, Width, Adjust, Precision, PadChar) ->
  506. case Precision of
  507. none ->
  508. NewPrecision = 6;
  509. _ ->
  510. NewPrecision = Precision
  511. end,
  512. case Width of
  513. none ->
  514. float_to_binary(Float, [{decimals, NewPrecision}]);
  515. _ ->
  516. term(float_to_binary(Float, [{decimals, NewPrecision}]), Width, Adjust, Width, PadChar)
  517. end.
  518. floatG(Float, Width, Adjust, Precision, PadChar) ->
  519. case Float > -10000.0 andalso Float < 10000.0 of
  520. true ->
  521. floatF(Float, Width, Adjust, Precision, PadChar);
  522. _ ->
  523. floatE(Float, Width, Adjust, Precision, PadChar)
  524. end.
  525. floatG(Float) ->
  526. float_to_binary(Float, [{decimals, 6}]).
  527. strToChars(BinStr, Width, CharsLimit) ->
  528. ByteSize = byte_size(BinStr),
  529. if
  530. Width == none ->
  531. case CharsLimit < 0 orelse CharsLimit >= ByteSize of
  532. true ->
  533. BinStr;
  534. _ ->
  535. <<(binary:part(BinStr, 0, CharsLimit))/binary, "...">>
  536. end;
  537. CharsLimit < 0 orelse CharsLimit >= Width ->
  538. BinStr;
  539. true ->
  540. <<(binary:part(BinStr, 0, CharsLimit))/binary, "...">>
  541. end.
  542. string(Str, Width, Adjust, Precision, PadChar, Encoding) ->
  543. if
  544. Width == none andalso Precision == none ->
  545. Str;
  546. Precision == none ->
  547. strField(Str, Width, Adjust, charsLen(Str), PadChar, Encoding);
  548. Width == none ->
  549. strField(Str, Precision, left, charsLen(Str), PadChar, Encoding);
  550. true ->
  551. StrLen = charsLen(Str),
  552. if
  553. Width > Precision ->
  554. if StrLen > Precision ->
  555. adjust(Adjust, flatTrunc(Str, Precision, Encoding), makePadChars(PadChar, Width - Precision, <<>>));
  556. StrLen < Precision ->
  557. adjust(Adjust, [Str | makePadChars(PadChar, Precision - StrLen, <<>>)], makePadChars(PadChar, Width - Precision, <<>>));
  558. true -> % N == P
  559. adjust(Adjust, Str, makePadChars(PadChar, Width - Precision, <<>>))
  560. end;
  561. true -> % F == P
  562. strField(Str, Width, Adjust, StrLen, PadChar, Encoding)
  563. end
  564. end.
  565. strField(Str, Width, Adjust, StrLen, PadChar, Encoding) when StrLen > Width ->
  566. if
  567. StrLen > Width ->
  568. flatTrunc(Str, Width, Encoding);
  569. StrLen < Width ->
  570. adjust(Adjust, Str, makePadChars(PadChar, Width - StrLen, <<>>));
  571. true ->
  572. Str
  573. end.
  574. flatTrunc(List, Width, _Encoding) ->
  575. binary:part(iolist_to_binary(List), 0, Width).
  576. makePadChars(PadChar, Cnt, BinStr) ->
  577. case Cnt > 0 of
  578. true ->
  579. makePadChars(PadChar, Cnt - 1, <<BinStr/binary, PadChar:8>>);
  580. _ ->
  581. BinStr
  582. end.
  583. adjust(left, Data, Pad) -> [Data, Pad];
  584. adjust(right, Data, Pad) -> [Pad, Data].
  585. unPrefixedInt(Int, Width, Adjust, Base, PadChar, Lowercase) ->
  586. case Lowercase of
  587. true ->
  588. term(toLowerStr(integer_to_binary(Int, Base)), Width, Adjust, none, PadChar);
  589. _ ->
  590. term(integer_to_binary(Int, Base), Width, Adjust, none, PadChar)
  591. end.
  592. prefixedInt(Int, Width, Adjust, Base, PadChar, Prefix, Lowercase) ->
  593. case Int < 0 of
  594. true ->
  595. case Lowercase of
  596. true ->
  597. term(<<"-", (toBinary(Prefix))/binary, (toLowerStr(integer_to_binary(-Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  598. _ ->
  599. term(<<"-", (toBinary(Prefix))/binary, (integer_to_binary(-Int, Base))/binary>>, Width, Adjust, none, PadChar)
  600. end;
  601. _ ->
  602. case Lowercase of
  603. true ->
  604. term(<<(toBinary(Prefix))/binary, (toLowerStr(integer_to_binary(Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  605. _ ->
  606. term(<<(toBinary(Prefix))/binary, (integer_to_binary(Int, Base))/binary>>, Width, Adjust, none, PadChar)
  607. end
  608. end.
  609. prefixedInt(Int, Width, Adjust, Base, PadChar, Prefix, Prefix2, Lowercase) ->
  610. case Int < 0 of
  611. true ->
  612. case Lowercase of
  613. true ->
  614. term(<<"-", (toBinary(Prefix))/binary, Prefix2:8, (toLowerStr(integer_to_binary(-Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  615. _ ->
  616. term(<<"-", (toBinary(Prefix))/binary, Prefix2:8, (integer_to_binary(-Int, Base))/binary>>, Width, Adjust, none, PadChar)
  617. end;
  618. _ ->
  619. case Lowercase of
  620. true ->
  621. term(<<(toBinary(Prefix))/binary, Prefix2:8, (toLowerStr(integer_to_binary(Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  622. _ ->
  623. term(<<(toBinary(Prefix))/binary, Prefix2:8, (integer_to_binary(Int, Base))/binary>>, Width, Adjust, none, PadChar)
  624. end
  625. end.
  626. char(Char, Width, Adjust, Precision, PadChar) ->
  627. if
  628. Width == none andalso Precision == none ->
  629. Char;
  630. Precision == none ->
  631. makePadChars(Char, Width, <<>>);
  632. Width == none ->
  633. makePadChars(Char, Precision, <<>>);
  634. true ->
  635. adjust(Adjust, makePadChars(Char, Precision, <<>>), makePadChars(PadChar, Width - Precision, <<>>))
  636. end.
  637. newline(none, _Adjust, _Precision, _PadChar) -> <<"\n">>;
  638. newline(Width, Adjust, _Precision, _PadChar) ->
  639. case Adjust of
  640. right ->
  641. makePadChars($\n, Width, <<>>);
  642. _ ->
  643. <<"\n">>
  644. end.
  645. remainChars(T, E) ->
  646. if
  647. T < 0 ->
  648. T;
  649. T >= E ->
  650. T - E;
  651. true ->
  652. 0
  653. end.
  654. %% ********************************************** eFmtFormat end *****************************************************
  655. %% ********************************************** eFmtPretty start *****************************************************
  656. %% ********************************************** eFmtPretty end *****************************************************
  657. %% ********************************************** utils start **********************************************************
  658. toLowerStr(BinStr) ->
  659. <<begin
  660. case C >= $A andalso C =< $Z of
  661. true ->
  662. <<(C + 32)>>;
  663. _ ->
  664. <<C>>
  665. end
  666. end || <<C:8>> <= BinStr
  667. >>.
  668. toUpperStr(BinStr) ->
  669. <<begin
  670. case C >= $a andalso C =< $z of
  671. true ->
  672. <<(C - 32)>>;
  673. _ ->
  674. <<C>>
  675. end
  676. end || <<C:8>> <= BinStr
  677. >>.
  678. -spec charsLen(chars()) -> non_neg_integer().
  679. charsLen(S) ->
  680. try
  681. iolist_size(S)
  682. catch
  683. _:_ ->
  684. string:length(S)
  685. end.
  686. getOpt(Key, TupleList, Default) ->
  687. case lists:keyfind(Key, 1, TupleList) of
  688. false ->
  689. Default;
  690. ValueTuple ->
  691. element(2, ValueTuple)
  692. end.
  693. toBinary(Value) when is_integer(Value) -> integer_to_binary(Value);
  694. toBinary(Value) when is_list(Value) -> list_to_binary(Value);
  695. toBinary(Value) when is_float(Value) -> float_to_binary(Value, [{decimals, 6}, compact]);
  696. toBinary(Value) when is_atom(Value) -> atom_to_binary(Value, utf8);
  697. toBinary(Value) when is_binary(Value) -> Value;
  698. toBinary([Tuple | PropList] = Value) when is_list(PropList) and is_tuple(Tuple) ->
  699. lists:map(fun({K, V}) -> {toBinary(K), toBinary(V)} end, Value);
  700. toBinary(Value) -> term_to_binary(Value).
  701. %% ********************************************** utils end **********************************************************