Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1142 строки
43 KiB

4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
1 год назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
2 лет назад
2 лет назад
2 лет назад
2 лет назад
2 лет назад
2 лет назад
2 лет назад
2 лет назад
2 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
1 год назад
4 лет назад
4 лет назад
3 лет назад
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 лет назад
2 лет назад
3 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
1 год назад
4 лет назад
1 год назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
1 год назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
1 год назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
2 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
3 лет назад
4 лет назад
3 лет назад
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 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
1 год назад
4 лет назад
1 год назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
1 год назад
4 лет назад
1 год назад
3 лет назад
4 лет назад
3 лет назад
1 год назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
1 год назад
4 лет назад
1 год назад
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 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
4 лет назад
1 год назад
1 год назад
1 год назад
1 год назад
1 год назад
1 год назад
4 лет назад
3 лет назад
4 лет назад
4 лет назад
  1. -module(eFmt).
  2. -import(binary, [split/2, part/3]).
  3. -import(lists, [keyfind/3, reverse/2]).
  4. -import(maps, [iterator/1, next/1]).
  5. -compile(inline).
  6. -compile({inline_size, 128}).
  7. %% pretty 模式下 每行打印的字符数
  8. -define(LineCCnt, 120).
  9. -define(eFmtPtMc, '$eFmtPtMc').
  10. -define(base(Precision), case Precision of none -> 10; _ -> Precision end).
  11. %% 三元表达式
  12. -define(CASE(Cond, Ret1, Ret2), (case Cond of true -> Ret1; _ -> Ret2 end)).
  13. -record(fmtSpec, {
  14. ctlChar :: char() %% 控制序列的类型 $p $w
  15. , args :: [any()] %% 是控制序列使用的参数的列表,如果控制序列不带任何参数,则为空列表。
  16. , width :: 'none' | integer() %% 字段宽度
  17. , adjust :: 'left' | 'right' %% 对齐方式
  18. , precision :: 'none' | integer() %% 打印参数的精度
  19. , padChar :: char() %% 填充字符
  20. , encoding :: 'unicode' | 'latin1' %% 如果存在翻译修饰符t,则编码设置为true
  21. , strings :: boolean() %% 如果存在修饰符l,则将 string设置为false。
  22. }).
  23. -on_load(on_load/0).
  24. -export([
  25. %% eFmt
  26. format/2
  27. , format/3
  28. , formatIol/2
  29. , formatIol/3
  30. , scan/2
  31. , build/1
  32. , build/2
  33. , write/1
  34. , write/2
  35. , write/3
  36. , write/4
  37. , write/6
  38. %% eFmtformat
  39. , fWrite/2
  40. , fWrite/3
  41. , fScan/2
  42. , fBuild/1
  43. , fBuild/2
  44. %% utils
  45. , toLowerStr/1
  46. , toUpperStr/1
  47. , toBinary/1
  48. , charsLen/1
  49. , getOpt/3
  50. , visualList/2
  51. , visualBin/2
  52. , writeTerm/3
  53. , writeTerm/5
  54. ]).
  55. %% ********************************************** eFmt start ***********************************************************
  56. -type chars() :: [char() | chars() | binary()].
  57. -type depth() :: -1 | non_neg_integer().
  58. -type encoding() :: epp:source_encoding() | 'unicode'.
  59. -type charsLimit() :: integer().
  60. -type fmtSpec() :: #fmtSpec{}.
  61. -type format() :: atom() | string() | binary().
  62. on_load() ->
  63. case persistent_term:get(?eFmtPtMc, undefined) of
  64. undefined ->
  65. persistent_term:put(?eFmtPtMc, binary:compile_pattern(<<"~">>));
  66. _ ->
  67. ignore
  68. end,
  69. ok.
  70. -spec format(Format :: format(), Data :: [term()]) -> chars().
  71. format(Format, Args) ->
  72. try iolist_to_binary(fWrite(Format, Args))
  73. catch
  74. C:R:S ->
  75. erlang:error(badarg, [Format, Args, {C, R, S}])
  76. end.
  77. -spec format(Format :: format(), Data :: [term()], Options :: [{charsLimit, CharsLimit :: charsLimit()}]) -> chars().
  78. format(Format, Args, Options) ->
  79. try iolist_to_binary(fWrite(Format, Args, Options))
  80. catch
  81. C:R:S ->
  82. erlang:error(badarg, [Format, Args, {C, R, S}])
  83. end.
  84. -spec formatIol(Format :: format(), Data :: [term()]) -> chars().
  85. formatIol(Format, Args) ->
  86. try fWrite(Format, Args)
  87. catch
  88. C:R:S ->
  89. erlang:error(badarg, [Format, Args, {C, R, S}])
  90. end.
  91. -spec formatIol(Format :: format(), Data :: [term()], Options :: [{charsLimit, CharsLimit :: charsLimit()}]) -> chars().
  92. formatIol(Format, Args, Options) ->
  93. try fWrite(Format, Args, Options)
  94. catch
  95. C:R:S ->
  96. erlang:error(badarg, [Format, Args, {C, R, S}])
  97. end.
  98. -spec scan(Format :: format(), Data :: [term()]) -> FormatList :: [char() | fmtSpec()].
  99. scan(Format, Args) ->
  100. try fScan(Format, Args)
  101. catch
  102. C:R:S ->
  103. erlang:error(badarg, [Format, Args, {C, R, S}])
  104. end.
  105. -spec build(FormatList :: [char() | fmtSpec()]) -> chars().
  106. build(FormatList) ->
  107. try fBuild(FormatList)
  108. catch
  109. C:R:S ->
  110. erlang:error(badarg, [FormatList, {C, R, S}])
  111. end.
  112. -spec build(FormatList :: [char() | fmtSpec()], Options :: [{charsLimit, CharsLimit :: charsLimit()}]) -> chars().
  113. build(FormatList, Options) ->
  114. try fBuild(FormatList, Options)
  115. catch
  116. C:R:S ->
  117. erlang:error(badarg, [FormatList, Options, {C, R, S}])
  118. end.
  119. -spec write(Term :: term()) -> chars().
  120. write(Term) ->
  121. writeTerm(Term, -1, latin1).
  122. -spec write(Term :: term(), Depth :: depth()) -> chars().
  123. write(Term, Depth) ->
  124. writeTerm(Term, Depth, latin1).
  125. -spec write(Term :: term(), Depth :: depth(), IsPretty :: boolean()) -> chars().
  126. write(Term, Depth, IsPretty) ->
  127. case IsPretty of
  128. true ->
  129. writeTerm(Term, Depth, ?LineCCnt, latin1, true);
  130. _ ->
  131. writeTerm(Term, Depth, latin1)
  132. end.
  133. splitPart(Term)when is_map(Term) ->
  134. <<"...}">>;
  135. splitPart(Term)when is_tuple(Term) ->
  136. <<"...}">>;
  137. splitPart(Term)when is_list(Term) ->
  138. <<"...]">>;
  139. splitPart(Term) when is_binary(Term) ->
  140. <<"...>>">>;
  141. splitPart(_Term) ->
  142. <<"...">>.
  143. -spec write(Term :: term(), Depth :: depth(), Encoding :: encoding(), CharsLimit :: charsLimit()) -> chars().
  144. write(Term, Depth, Encoding, CharsLimit) ->
  145. if
  146. Depth =:= 0 orelse CharsLimit =:= 0 ->
  147. <<"...">>;
  148. CharsLimit < 0 ->
  149. writeTerm(Term, Depth, Encoding);
  150. true ->
  151. BinTerm = writeTerm(Term, Depth, Encoding),
  152. BinTermSize = byte_size(BinTerm),
  153. if
  154. CharsLimit < 0 ->
  155. BinTerm;
  156. BinTermSize > CharsLimit ->
  157. <<(part(BinTerm, 0, CharsLimit))/binary, (splitPart(Term))/binary>>;
  158. true ->
  159. BinTerm
  160. end
  161. end.
  162. write(Term, Depth, Width, CharsLimit, Encoding, Strings) ->
  163. if
  164. Depth =:= 0 orelse CharsLimit =:= 0 ->
  165. <<"...">>;
  166. true ->
  167. BinTerm = writeTerm(Term, Depth, Width, Encoding, Strings),
  168. BinTermSize = byte_size(BinTerm),
  169. if
  170. CharsLimit < 0 ->
  171. BinTerm;
  172. BinTermSize > CharsLimit ->
  173. <<(part(BinTerm, 0, CharsLimit))/binary, (splitPart(Term))/binary>>;
  174. true ->
  175. BinTerm
  176. end
  177. end.
  178. -define(writeInt(Int), integer_to_binary(Term)).
  179. -define(writeFloat(Float), floatG(Term)).
  180. -define(writePort(Port), list_to_binary(port_to_list(Port))).
  181. -define(writeRef(Ref), list_to_binary(ref_to_list(Ref))).
  182. -define(writePid(Ref), list_to_binary(pid_to_list(Ref))).
  183. -define(writeFun(Fun), list_to_binary(erlang:fun_to_list(Fun))).
  184. writeAtom(Atom, Encoding) ->
  185. AtomBin = atom_to_binary(Atom, Encoding),
  186. case isQuoteAtom(Atom, AtomBin) of
  187. true ->
  188. <<"'", (atom_to_binary(Atom, Encoding))/binary, "'">>;
  189. _ ->
  190. AtomBin
  191. end.
  192. isQuoteAtom(Atom, AtomBin) ->
  193. case erl_scan:reserved_word(Atom) of
  194. true -> true;
  195. _ ->
  196. visualAtomBin(AtomBin)
  197. end.
  198. visualAtomBin(<<>>) -> false;
  199. visualAtomBin(<<C/utf8, Left/binary>>) -> ?CASE(visualAtomChar(C), visualAtomBin(Left), true);
  200. visualAtomBin(_) -> true.
  201. visualAtomChar(C) when C >= $a, C =< $z -> true;
  202. visualAtomChar(C) when C >= , C =< $ÿ, C =/= -> true;
  203. visualAtomChar(C) when C >= $A, C =< $Z -> true;
  204. visualAtomChar(C) when C >= , C =< , C =/= -> true;
  205. visualAtomChar(C) when C >= $0, C =< $9 -> true;
  206. visualAtomChar($_) -> true;
  207. visualAtomChar($@) -> true;
  208. visualAtomChar(_) -> false.
  209. %% **************************************************** ~w start *******************************************************
  210. writeList([], _D, _E, BinAcc) ->
  211. <<BinAcc/binary, "]">>;
  212. writeList([One], D, E, BinAcc) ->
  213. VBin = writeTerm(One, D, E),
  214. <<BinAcc/binary, VBin/binary, "]">>;
  215. writeList([One | List], D, E, BinAcc) ->
  216. if
  217. D =:= 1 -> <<BinAcc/binary, "|...]">>;
  218. true ->
  219. VBin = writeTerm(One, D, E),
  220. writeList(List, D - 1, E, <<BinAcc/binary, VBin/binary, ",">>)
  221. end;
  222. writeList(Other, D, E, BinAcc) ->
  223. NewBinAcc = part(BinAcc, 0, byte_size(BinAcc) - 1),
  224. VBin = writeTerm(Other, D, E),
  225. <<NewBinAcc/binary, "|", VBin/binary, "]">>.
  226. writeTuple(Tuple, D, E, Index, TupleSize, BinAcc) ->
  227. if
  228. D =:= 1 -> <<BinAcc/binary, "...}">>;
  229. true ->
  230. if
  231. Index < TupleSize ->
  232. VBin = writeTerm(element(Index, Tuple), D - 1, E),
  233. writeTuple(Tuple, D - 1, E, Index + 1, TupleSize, <<BinAcc/binary, VBin/binary, ",">>);
  234. Index == TupleSize ->
  235. VBin = writeTerm(element(Index, Tuple), D - 1, E),
  236. <<BinAcc/binary, VBin/binary, "}">>;
  237. true ->
  238. <<BinAcc/binary, "}">>
  239. end
  240. end.
  241. writeMap(Map, D, E, BinAcc) ->
  242. if
  243. D =:= 1 ->
  244. <<BinAcc/binary, "...}">>;
  245. true ->
  246. writeMapBody(iterator(Map), D, E, BinAcc)
  247. end.
  248. writeMapBody(I, D, E, BinAcc) ->
  249. if
  250. D =:= 1 ->
  251. <<BinAcc/binary, " ...}">>;
  252. true ->
  253. case next(I) of
  254. {K, V, none} ->
  255. KeyTermBin = writeTerm(K, -1, E),
  256. ValueTermBin = writeTerm(V, -1, E),
  257. <<BinAcc/binary, KeyTermBin/binary, " => ", ValueTermBin/binary, "}">>;
  258. {K, V, NextI} ->
  259. KeyTermBin = writeTerm(K, -1, E),
  260. ValueTermBin = writeTerm(V, -1, E),
  261. writeMapBody(NextI, D - 1, E, <<BinAcc/binary, KeyTermBin/binary, " => ", ValueTermBin/binary, ",">>);
  262. _ ->
  263. <<BinAcc/binary, "}">>
  264. end
  265. end.
  266. writeBinary(Bin, D, BinAcc) ->
  267. if
  268. D == 1 ->
  269. <<BinAcc/binary, "...>>">>;
  270. true ->
  271. case Bin of
  272. <<>> ->
  273. <<BinAcc/binary, ">>">>;
  274. <<Int:8>> ->
  275. VBin = integer_to_binary(Int),
  276. <<BinAcc/binary, VBin/binary, ">>">>;
  277. <<Int:8, LeftBin/bitstring>> ->
  278. VBin = integer_to_binary(Int),
  279. writeBinary(LeftBin, D - 1, <<BinAcc/binary, VBin/binary, ",">>);
  280. _ ->
  281. L = bit_size(Bin),
  282. <<X:L>> = Bin,
  283. XBin = integer_to_binary(X),
  284. LBin = integer_to_binary(L),
  285. <<BinAcc/binary, XBin/binary, ":", LBin/binary, ">>">>
  286. end
  287. end.
  288. %% **************************************************** ~w end *******************************************************
  289. %% **************************************************** ~p start *******************************************************
  290. writeList([], _Depth, _Width, _Encoding, _Strings) ->
  291. <<"[]">>;
  292. writeList(List, Depth, Width, Encoding, Strings) ->
  293. case Strings andalso visualList(List, Encoding) of
  294. true ->
  295. <<"\"", (unicode:characters_to_binary(List))/binary, "\"">>;
  296. _ ->
  297. writeList(List, Depth, Width, Encoding, Strings, 0, <<"[">>)
  298. end.
  299. writeList([], _Depth, _Width, _Encoding, _Strings, _SumLC, BinAcc) ->
  300. <<BinAcc/binary, "]">>;
  301. writeList([One], Depth, Width, Encoding, Strings, SumLC, BinAcc) ->
  302. TermBin = writeTerm(One, Depth, Width, Encoding, Strings),
  303. TermBinBinSize = byte_size(TermBin),
  304. NewSumLC = SumLC + TermBinBinSize,
  305. case Width /= 0 andalso NewSumLC >= Width of
  306. true ->
  307. <<BinAcc/binary, TermBin/binary, "]\n">>;
  308. _ ->
  309. <<BinAcc/binary, TermBin/binary, "]">>
  310. end;
  311. writeList([One | List], Depth, Width, Encoding, Strings, SumLC, BinAcc) ->
  312. if
  313. Depth =:= 1 -> <<BinAcc/binary, "|...]">>;
  314. true ->
  315. TermBin = writeTerm(One, Depth, Width, Encoding, Strings),
  316. TermBinBinSize = byte_size(TermBin),
  317. NewSumLC = SumLC + TermBinBinSize,
  318. case Width /= 0 andalso NewSumLC >= Width of
  319. true ->
  320. writeList(List, Depth - 1, Width, Encoding, Strings, 0, <<BinAcc/binary, TermBin/binary, ",\n">>);
  321. _ ->
  322. writeList(List, Depth - 1, Width, Encoding, Strings, NewSumLC, <<BinAcc/binary, TermBin/binary, ",">>)
  323. end
  324. end;
  325. writeList(Other, Depth, Width, Encoding, Strings, SumLC, BinAcc) ->
  326. TermBin = writeTerm(Other, Depth, Width, Encoding, Strings),
  327. TermBinBinSize = byte_size(TermBin),
  328. NewSumLC = SumLC + TermBinBinSize,
  329. NewBinAcc = part(BinAcc, 0, byte_size(BinAcc) - 1),
  330. case Width /= 0 andalso NewSumLC >= Width of
  331. true ->
  332. <<NewBinAcc/binary, "|", TermBin/binary, "]\n">>;
  333. _ ->
  334. <<NewBinAcc/binary, "|", TermBin/binary, "]">>
  335. end.
  336. writeTuple(Tuple, Depth, Width, Encoding, Strings, Index, TupleSize, SumLC, BinAcc) ->
  337. if
  338. Depth =:= 1 -> <<BinAcc/binary, "...}">>;
  339. true ->
  340. if
  341. Index < TupleSize ->
  342. TermBin = writeTerm(element(Index, Tuple), Depth, Width, Encoding, Strings),
  343. TermBinBinSize = byte_size(TermBin),
  344. NewSumLC = SumLC + TermBinBinSize,
  345. case Width /= 0 andalso NewSumLC >= Width of
  346. true ->
  347. writeTuple(Tuple, Depth - 1, Width, Encoding, Strings, Index + 1, TupleSize, 0, <<BinAcc/binary, TermBin/binary, ",\n">>);
  348. _ ->
  349. writeTuple(Tuple, Depth - 1, Width, Encoding, Strings, Index + 1, TupleSize, NewSumLC, <<BinAcc/binary, TermBin/binary, ",">>)
  350. end;
  351. Index == TupleSize ->
  352. TermBin = writeTerm(element(Index, Tuple), Depth, Width, Encoding, Strings),
  353. TermBinBinSize = byte_size(TermBin),
  354. NewSumLC = SumLC + TermBinBinSize,
  355. case Width /= 0 andalso NewSumLC >= Width of
  356. true ->
  357. <<BinAcc/binary, TermBin/binary, "}\n">>;
  358. _ ->
  359. <<BinAcc/binary, TermBin/binary, "}">>
  360. end;
  361. true ->
  362. <<BinAcc/binary, "}">>
  363. end
  364. end.
  365. writeMap(Map, Depth, Width, Encoding, Strings, SumLC, BinAcc) ->
  366. if
  367. Depth =:= 1 ->
  368. <<BinAcc/binary, "...}">>;
  369. true ->
  370. writeMapBody(iterator(Map), Depth, Width, Encoding, Strings, SumLC, BinAcc)
  371. end.
  372. writeMapBody(I, Depth, Width, Encoding, Strings, SumLC, BinAcc) ->
  373. if
  374. Depth =:= 1 ->
  375. <<BinAcc/binary, " ...}">>;
  376. true ->
  377. case next(I) of
  378. {K, V, none} ->
  379. KeyTermBin = writeTerm(K, -1, Width, Encoding, Strings),
  380. ValueTermBin = writeTerm(V, -1, Width, Encoding, Strings),
  381. TermBinBinSize = byte_size(KeyTermBin) + byte_size(ValueTermBin),
  382. NewSumLC = SumLC + TermBinBinSize,
  383. case Width /= 0 andalso NewSumLC >= Width of
  384. true ->
  385. <<BinAcc/binary, KeyTermBin/binary, " => ", ValueTermBin/binary, "}\n">>;
  386. _ ->
  387. <<BinAcc/binary, KeyTermBin/binary, " => ", ValueTermBin/binary, "}">>
  388. end;
  389. {K, V, NextI} ->
  390. KeyTermBin = writeTerm(K, -1, Width, Encoding, Strings),
  391. ValueTermBin = writeTerm(V, -1, Width, Encoding, Strings),
  392. TermBinBinSize = byte_size(KeyTermBin) + byte_size(ValueTermBin),
  393. NewSumLC = SumLC + TermBinBinSize,
  394. case Width /= 0 andalso NewSumLC >= Width of
  395. true ->
  396. writeMapBody(NextI, Depth - 1, Width, Encoding, Strings, 0, <<BinAcc/binary, KeyTermBin/binary, " => ", ValueTermBin/binary, ",\n">>);
  397. _ ->
  398. writeMapBody(NextI, Depth - 1, Width, Encoding, Strings, NewSumLC, <<BinAcc/binary, KeyTermBin/binary, " => ", ValueTermBin/binary, ",">>)
  399. end;
  400. _ ->
  401. <<BinAcc/binary, "}">>
  402. end
  403. end.
  404. writeBinary(<<>>, _Depth, _Width, _Encoding, _Strings) ->
  405. <<"<<>>">>;
  406. writeBinary(Bin, Depth, Width, Encoding, Strings) ->
  407. case Strings andalso visualBin(Bin, Encoding) of
  408. true ->
  409. <<"<<\"", Bin/binary, "\">>">>;
  410. _ ->
  411. writeBinary(Bin, Depth, Width, Encoding, Strings, 0, <<"<<">>)
  412. end.
  413. writeBinary(Bin, Depth, Width, Encoding, Strings, SumLC, BinAcc) ->
  414. if
  415. Depth == 1 ->
  416. <<BinAcc/binary, "...>>">>;
  417. true ->
  418. case Bin of
  419. <<>> ->
  420. <<BinAcc/binary, ">>">>;
  421. <<Int:8>> ->
  422. <<BinAcc/binary, (integer_to_binary(Int))/binary, ">>">>;
  423. <<Int:8, LeftBin/bitstring>> ->
  424. TermBin = integer_to_binary(Int),
  425. TermBinBinSize = byte_size(TermBin),
  426. NewSumLC = SumLC + TermBinBinSize,
  427. case Width /= 0 andalso NewSumLC >= Width of
  428. true ->
  429. writeBinary(LeftBin, Depth - 1, Width, Encoding, Strings, 0, <<BinAcc/binary, TermBin/binary, ",\n">>);
  430. _ ->
  431. writeBinary(LeftBin, Depth - 1, Width, Encoding, Strings, NewSumLC, <<BinAcc/binary, TermBin/binary, ",">>)
  432. end;
  433. _ ->
  434. L = bit_size(Bin),
  435. <<X:L>> = Bin,
  436. <<BinAcc/binary, (integer_to_binary(X))/binary, ":", (integer_to_binary(L))/binary, ">>">>
  437. end
  438. end.
  439. %% **************************************************** ~p end *******************************************************
  440. %% ~w
  441. writeTerm(_Term, Depth, _E) when Depth == 0 -> <<"...">>;
  442. writeTerm(Term, _Depth, _E) when is_integer(Term) -> ?writeInt(Term);
  443. writeTerm(Term, _Depth, E) when is_atom(Term) -> writeAtom(Term, E);
  444. writeTerm(Term, Depth, E) when is_list(Term) -> writeList(Term, Depth, E, <<"[">>);
  445. writeTerm(Term, Depth, E) when is_map(Term) -> writeMap(Term, Depth, E, <<"#{">>);
  446. writeTerm(Term, Depth, E) when is_tuple(Term) -> writeTuple(Term, Depth, E, 1, tuple_size(Term), <<"{">>);
  447. writeTerm(Term, Depth, _E) when is_bitstring(Term) -> writeBinary(Term, Depth, <<"<<">>);
  448. writeTerm(Term, _Depth, _E) when is_pid(Term) -> ?writePid(Term);
  449. writeTerm(Term, _Depth, _E) when is_float(Term) -> ?writeFloat(Term);
  450. writeTerm(Term, _Depth, _E) when is_port(Term) -> ?writePort(Term);
  451. writeTerm(Term, _Depth, _E) when is_reference(Term) -> ?writeRef(Term);
  452. writeTerm(Term, _Depth, _E) when is_function(Term) -> ?writeFun(Term).
  453. %% ~p
  454. writeTerm(_Term, Depth, _Width, _Encoding, _Strings) when Depth == 0 -> <<"...">>;
  455. writeTerm(Term, _Depth, _Width, _Encoding, _Strings) when is_integer(Term) -> ?writeInt(Term);
  456. writeTerm(Term, _Depth, _Width, Encoding, _Strings) when is_atom(Term) -> writeAtom(Term, Encoding);
  457. writeTerm(Term, Depth, Width, Encoding, Strings) when is_list(Term) -> writeList(Term, Depth, Width, Encoding, Strings);
  458. writeTerm(Term, Depth, Width, Encoding, Strings) when is_map(Term) ->
  459. writeMap(Term, Depth, Width, Encoding, Strings, 0, <<"#{">>);
  460. writeTerm(Term, Depth, Width, Encoding, Strings) when is_tuple(Term) ->
  461. writeTuple(Term, Depth, Width, Encoding, Strings, 1, tuple_size(Term), 0, <<"{">>);
  462. writeTerm(Term, Depth, Width, Encoding, Strings) when is_bitstring(Term) ->
  463. writeBinary(Term, Depth, Width, Encoding, Strings);
  464. writeTerm(Term, _Depth, _Width, _Encoding, _Strings) when is_pid(Term) -> ?writePid(Term);
  465. writeTerm(Term, _Depth, _Width, _Encoding, _Strings) when is_float(Term) -> ?writeFloat(Term);
  466. writeTerm(Term, _Depth, _Width, _Encoding, _Strings) when is_port(Term) -> ?writePort(Term);
  467. writeTerm(Term, _Depth, _Width, _Encoding, _Strings) when is_reference(Term) -> ?writeRef(Term);
  468. writeTerm(Term, _Depth, _Width, _Encoding, _Strings) when is_function(Term) -> ?writeFun(Term).
  469. %% ********************************************** eFmt end *************************************************************
  470. %% ********************************************** eFmtFormat start *****************************************************
  471. -spec fWrite(Format :: format(), Data :: [term()]) -> chars().
  472. fWrite(Format, Args) ->
  473. fBuild(fScan(Format, Args), []).
  474. -spec fWrite(Format :: format(), Data :: [term()], Options :: [{charsLimit, CharsLimit :: integer()}]) -> chars().
  475. fWrite(Format, Args, Options) ->
  476. fBuild(fScan(Format, Args), Options).
  477. %% 格式 ~F.P.PadModC
  478. %% Parse all control sequences in the format string.
  479. -spec fScan(Format :: format(), Data :: [term()]) -> FormatList :: [char() | fmtSpec()].
  480. fScan(Format, Args) ->
  481. if
  482. is_binary(Format) ->
  483. doCollect(Format, Args, []);
  484. is_list(Format) ->
  485. doCollect(list_to_binary(Format), Args, []);
  486. is_atom(Format) ->
  487. doCollect(atom_to_binary(Format, utf8), Args, []);
  488. true ->
  489. throw(bad_format)
  490. end.
  491. doCollect(FmtBinStr, Args, Acc) ->
  492. case split(FmtBinStr, persistent_term:get(?eFmtPtMc)) of
  493. [NotMatch] ->
  494. true = [] == Args,
  495. ?CASE(NotMatch == <<>>, Acc, [NotMatch | Acc]);
  496. [FPart, LPart] ->
  497. doCollWidth(LPart, Args, none, right, ?CASE(FPart == <<>>, Acc, [FPart | Acc]))
  498. end.
  499. doCollWidth(<<>>, _Args, _Width, _Adjust, Acc) ->
  500. Acc;
  501. doCollWidth(LPart, Args, Width, Adjust, Acc) ->
  502. case LPart of
  503. <<"-*", LeftLPart/binary>> ->
  504. [WidthArgs | LeftArgs] = Args,
  505. if
  506. WidthArgs == 0 ->
  507. NewWidth = WidthArgs,
  508. NewAdjust = left;
  509. WidthArgs < 0 ->
  510. NewWidth = -WidthArgs,
  511. NewAdjust = right;
  512. true ->
  513. NewWidth = WidthArgs,
  514. NewAdjust = left
  515. end,
  516. doCollPrecision(LeftLPart, LeftArgs, NewWidth, NewAdjust, Acc);
  517. <<"-", LeftLPart/binary>> ->
  518. doCollWidth(LeftLPart, Args, Width, left, Acc);
  519. <<"*", LeftLPart/binary>> ->
  520. [WidthArgs | LeftArgs] = Args,
  521. if
  522. WidthArgs == 0 ->
  523. NewWidth = WidthArgs,
  524. NewAdjust = left;
  525. WidthArgs < 0 ->
  526. NewWidth = -WidthArgs,
  527. NewAdjust = left;
  528. true ->
  529. NewWidth = WidthArgs,
  530. NewAdjust = right
  531. end,
  532. doCollPrecision(LeftLPart, LeftArgs, NewWidth, NewAdjust, Acc);
  533. <<WidthInt:8/integer, LeftLPart/binary>> ->
  534. case WidthInt >= $0 andalso WidthInt =< $9 of
  535. true ->
  536. NewWidth = ?CASE(Width == none, WidthInt - $0, 10 * Width + (WidthInt - $0)),
  537. doCollWidth(LeftLPart, Args, NewWidth, Adjust, Acc);
  538. _ ->
  539. doCollPrecision(LPart, Args, Width, Adjust, Acc)
  540. end
  541. end.
  542. doCollPrecision(LPart, Args, Width, Adjust, Acc) ->
  543. case LPart of
  544. <<".", LeftLPart/binary>> ->
  545. doCollPrecision(LeftLPart, Args, Width, Adjust, 0, Acc);
  546. _ ->
  547. doCollPadChar(LPart, Args, Width, Adjust, none, Acc)
  548. end.
  549. doCollPrecision(LPart, Args, Width, Adjust, Precision, Acc) ->
  550. case LPart of
  551. <<"*", LeftLPart/binary>> ->
  552. [PrecisionArgs | LeftArgs] = Args,
  553. NewPrecision = ?CASE(PrecisionArgs == 0, none, PrecisionArgs),
  554. doCollPadChar(LeftLPart, LeftArgs, Width, Adjust, NewPrecision, Acc);
  555. <<PrecisionInt:8/integer, LeftLPart/binary>> ->
  556. case PrecisionInt >= $0 andalso PrecisionInt =< $9 of
  557. true ->
  558. doCollPrecision(LeftLPart, Args, Width, Adjust, 10 * Precision + (PrecisionInt - $0), Acc);
  559. _ ->
  560. case Precision == 0 of
  561. true ->
  562. doCollPadChar(LPart, Args, Width, Adjust, none, Acc);
  563. _ ->
  564. doCollPadChar(LPart, Args, Width, Adjust, Precision, Acc)
  565. end
  566. end
  567. end.
  568. doCollPadChar(LPart, Args, Width, Adjust, Precision, Acc) ->
  569. case LPart of
  570. <<".*", LeftLPart/binary>> ->
  571. [PadChar | LeftArgs] = Args,
  572. doCollEncodingStrings(LeftLPart, LeftArgs, Width, Adjust, Precision, PadChar, Acc);
  573. <<".", PadChar:8/integer, LeftLPart/binary>> ->
  574. doCollEncodingStrings(LeftLPart, Args, Width, Adjust, Precision, PadChar, Acc);
  575. _ ->
  576. doCollEncodingStrings(LPart, Args, Width, Adjust, Precision, 32, Acc)
  577. end.
  578. doCollEncodingStrings(LPart, Args, Width, Adjust, Precision, PadChar, Acc) ->
  579. case LPart of
  580. <<"lt", LeftLPart/binary>> ->
  581. LLeftLPart = LeftLPart,
  582. Encoding = unicode,
  583. Strings = false;
  584. <<"tl", LeftLPart/binary>> ->
  585. LLeftLPart = LeftLPart,
  586. Encoding = unicode,
  587. Strings = false;
  588. <<"t", LeftLPart/binary>> ->
  589. LLeftLPart = LeftLPart,
  590. Encoding = unicode,
  591. Strings = true;
  592. <<"l", LeftLPart/binary>> ->
  593. LLeftLPart = LeftLPart,
  594. Encoding = latin1,
  595. Strings = false;
  596. _ ->
  597. LLeftLPart = LPart,
  598. Encoding = latin1,
  599. Strings = true
  600. end,
  601. doCollCA(LLeftLPart, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, Acc).
  602. doCollCA(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, Acc) ->
  603. <<CtlChar:8/integer, LeftLPart/binary>> = LPart,
  604. case CtlChar of
  605. $w -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  606. $p -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  607. $W -> [OneArgs | LeftArgs] = Args, [Depth | LastArgs] = LeftArgs, As = {OneArgs, Depth}, NextArgs = LastArgs;
  608. $P -> [OneArgs | LeftArgs] = Args, [Depth | LastArgs] = LeftArgs, As = {OneArgs, Depth}, NextArgs = LastArgs;
  609. $s -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  610. $e -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  611. $f -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  612. $g -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  613. $b -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  614. $B -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  615. $x -> [OneArgs | LeftArgs] = Args, [Prefix | LastArgs] = LeftArgs, As = {OneArgs, Prefix}, NextArgs = LastArgs;
  616. $X -> [OneArgs | LeftArgs] = Args, [Prefix | LastArgs] = LeftArgs, As = {OneArgs, Prefix}, NextArgs = LastArgs;
  617. $+ -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  618. $# -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  619. $c -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  620. $~ -> As = undefined, NextArgs = Args;
  621. $n -> As = undefined, NextArgs = Args;
  622. $i -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs
  623. end,
  624. FmtSpec = #fmtSpec{ctlChar = CtlChar, args = As, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings},
  625. doCollect(LeftLPart, NextArgs, [FmtSpec | Acc]).
  626. %% Build the output text for a pre-parsed format list.
  627. -spec fBuild(FormatList :: [char() | fmtSpec()]) -> chars().
  628. fBuild(Cs) ->
  629. fBuild(Cs, []).
  630. -spec fBuild(FormatList :: [char() | fmtSpec()], Options :: [{charsLimit, CharsLimit :: integer()}]) -> chars().
  631. fBuild(Cs, Options) ->
  632. CharsLimit = getOpt(charsLimit, Options, -1),
  633. buildSmall(Cs, CharsLimit, 0, 0, 0, 0, []).
  634. buildSmall([], CharsLimit, P, S, W, Other, Acc) ->
  635. NumOfLimited = P + S + W,
  636. case NumOfLimited of
  637. 0 ->
  638. Acc;
  639. _ ->
  640. RemainChars = remainChars(CharsLimit, Other),
  641. case buildLimited(Acc, P, NumOfLimited, RemainChars, 0, []) of
  642. [] ->
  643. [];
  644. [_One] = Ret ->
  645. Ret;
  646. [One, Two] ->
  647. [Two, One];
  648. [One, Two, Three] ->
  649. [Three, Two, One];
  650. Ret ->
  651. reverse(Ret, [])
  652. end
  653. end;
  654. buildSmall([OneCA | Cs], CharsLimit, P, S, W, Other, Acc) ->
  655. case OneCA of
  656. #fmtSpec{ctlChar = CtlChar, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding} ->
  657. case ctlSmall(CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding) of
  658. not_small ->
  659. case CtlChar of
  660. $p ->
  661. buildSmall(Cs, CharsLimit, P + 1, S, W, Other, [OneCA | Acc]);
  662. $P ->
  663. buildSmall(Cs, CharsLimit, P + 1, S, W, Other, [OneCA | Acc]);
  664. $w ->
  665. buildSmall(Cs, CharsLimit, P, S, W + 1, Other, [OneCA | Acc]);
  666. $W ->
  667. buildSmall(Cs, CharsLimit, P, S, W + 1, Other, [OneCA | Acc]);
  668. $s ->
  669. buildSmall(Cs, CharsLimit, P, S, W + 1, Other, [OneCA | Acc]);
  670. _ ->
  671. buildSmall(Cs, CharsLimit, P, S, W, Other, [OneCA | Acc])
  672. end;
  673. ignore ->
  674. buildSmall(Cs, CharsLimit, P, S, W, Other, Acc);
  675. Str ->
  676. if
  677. is_binary(Str) orelse is_list(Str) ->
  678. buildSmall(Cs, CharsLimit, P, S, W, Other + charsLen(Str), [Str | Acc]);
  679. is_integer(Str) ->
  680. buildSmall(Cs, CharsLimit, P, S, W, Other + 1, [Str | Acc]);
  681. true ->
  682. buildSmall(Cs, CharsLimit, P, S, W, Other, [Str | Acc])
  683. end
  684. end;
  685. _ ->
  686. if
  687. is_binary(OneCA) orelse is_list(OneCA) ->
  688. buildSmall(Cs, CharsLimit, P, S, W, Other + charsLen(OneCA), [OneCA | Acc]);
  689. is_integer(OneCA) ->
  690. buildSmall(Cs, CharsLimit, P, S, W, Other + 1, [OneCA | Acc]);
  691. true ->
  692. buildSmall(Cs, CharsLimit, P, S, W, Other, [OneCA | Acc])
  693. end
  694. end.
  695. ctlSmall($e, Args, Width, Adjust, Precision, PadChar, _Encoding) ->
  696. floatE(Args, Width, Adjust, Precision, PadChar);
  697. ctlSmall($f, Args, Width, Adjust, Precision, PadChar, _Encoding) ->
  698. floatF(Args, Width, Adjust, Precision, PadChar);
  699. ctlSmall($g, Args, Width, Adjust, Precision, PadChar, _Encoding) ->
  700. floatG(Args, Width, Adjust, Precision, PadChar);
  701. ctlSmall($b, Args, Width, Adjust, Precision, PadChar, _Encoding) ->
  702. unPrefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, true);
  703. ctlSmall($B, Args, Width, Adjust, Precision, PadChar, _Encoding) ->
  704. unPrefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, false);
  705. ctlSmall($x, {Args, Prefix}, Width, Adjust, Precision, PadChar, _Encoding) ->
  706. case is_atom(Prefix) of
  707. true ->
  708. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, atom_to_binary(Prefix, utf8), true);
  709. _ ->
  710. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, Prefix, true)
  711. end;
  712. ctlSmall($X, {Args, Prefix}, Width, Adjust, Precision, PadChar, _Encoding) ->
  713. case is_atom(Prefix) of
  714. true ->
  715. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, atom_to_binary(Prefix, utf8), false);
  716. _ ->
  717. Base = ?base(Precision),
  718. prefixedInt(Args, Width, Adjust, Base, PadChar, integer_to_binary(Base), $#, true)
  719. end;
  720. ctlSmall($+, Args, Width, Adjust, Precision, PadChar, _Encoding) ->
  721. Base = ?base(Precision),
  722. prefixedInt(Args, Width, Adjust, Base, PadChar, integer_to_binary(Base), $#, true);
  723. ctlSmall($#, Args, Width, Adjust, Precision, PadChar, _Encoding) ->
  724. Base = ?base(Precision),
  725. prefixedInt(Args, Width, Adjust, Base, PadChar, integer_to_binary(Base), $#, false);
  726. ctlSmall($c, Args, Width, Adjust, Precision, PadChar, Encoding) ->
  727. case Encoding of
  728. unicode ->
  729. char(Args, Width, Adjust, Precision, PadChar);
  730. _ ->
  731. char(Args band 255, Width, Adjust, Precision, PadChar)
  732. end;
  733. ctlSmall($~, _Args, Width, Adjust, Precision, PadChar, _Encoding) -> char($~, Width, Adjust, Precision, PadChar);
  734. ctlSmall($n, _Args, Width, Adjust, Precision, PadChar, _Encoding) -> newline(Width, Adjust, Precision, PadChar);
  735. ctlSmall($i, _Args, _Width, _Adjust, _Precision, _PadChar, _Encoding) -> ignore;
  736. ctlSmall($s, Args, Width, Adjust, Precision, PadChar, Encoding) when is_atom(Args) ->
  737. case Encoding of
  738. latin1 ->
  739. AtomBinStr = writeAtom(Args, latin1);
  740. _ ->
  741. AtomBinStr = writeAtom(Args, uft8)
  742. end,
  743. string(AtomBinStr, Width, Adjust, Precision, PadChar, Encoding);
  744. ctlSmall(_C, _Args, _Width, _Adjust, _Precision, _PadChar, _Encoding) -> not_small.
  745. buildLimited([], _, _, _, _, Acc) -> Acc;
  746. buildLimited([OneCA | Cs], NumOfPs, Count, MaxLen, I, Acc) ->
  747. case OneCA of
  748. #fmtSpec{ctlChar = CtlChar, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings} ->
  749. MaxChars = if MaxLen < 0 -> MaxLen; true -> MaxLen div Count end,
  750. IoListStr = ctlLimited(CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I),
  751. NewNumOfPs = ?CASE(CtlChar == $p orelse CtlChar == $P, NumOfPs - 1, NumOfPs),
  752. NewCount = Count - 1,
  753. NewMaxLen = ?CASE(MaxLen < 0, MaxLen, remainChars(MaxLen, charsLen(IoListStr))),
  754. if
  755. NewNumOfPs > 0 ->
  756. buildLimited(Cs, NewNumOfPs, NewCount, NewMaxLen, I, [IoListStr | Acc]);
  757. true ->
  758. buildLimited(Cs, NewNumOfPs, NewCount, NewMaxLen, I, [IoListStr | Acc])
  759. end;
  760. _ ->
  761. buildLimited(Cs, NumOfPs, Count, MaxLen, I + 1, [OneCA | Acc])
  762. end.
  763. %% (CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I)
  764. ctlLimited($s, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  765. case Encoding of
  766. latin1 ->
  767. BinStr = iolist_to_binary(Args);
  768. _ ->
  769. BinStr =
  770. case catch unicode:characters_to_binary(Args, unicode) of
  771. Str when is_binary(Str) -> Str;
  772. _ -> toBinary(Args)
  773. end
  774. end,
  775. TemBinStr = strToChars(BinStr, Width, CharsLimit),
  776. string(TemBinStr, ?CASE(CharsLimit < 0 orelse Width =:= none, Width, max(3, min(Width, CharsLimit))), Adjust, Precision, PadChar, Encoding);
  777. ctlLimited($w, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  778. Chars = write(Args, -1, Encoding, CharsLimit),
  779. term(Chars, Width, Adjust, Precision, PadChar);
  780. ctlLimited($p, Args, Width, _Adjust, _Precision, _PadChar, Encoding, Strings, CharsLimit, _I) ->
  781. write(Args, -1, ?CASE(Width == none, ?LineCCnt, Width), CharsLimit, Encoding, Strings);
  782. ctlLimited($W, {Args, Depth}, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  783. Chars = write(Args, Depth, Encoding, CharsLimit),
  784. term(Chars, Width, Adjust, Precision, PadChar);
  785. ctlLimited($P, {Args, Depth}, Width, _Adjust, _Precision, _PadChar, Encoding, Strings, CharsLimit, _I) ->
  786. write(Args, Depth, ?CASE(Width == none, ?LineCCnt, Width), CharsLimit, Encoding, Strings).
  787. term(BinStrOrIoList, Width, Adjust, Precision, PadChar) ->
  788. if
  789. Width == none andalso Precision == none ->
  790. BinStrOrIoList;
  791. Width == none ->
  792. StrLen = charsLen(BinStrOrIoList),
  793. NewPrecision = min(StrLen, Precision),
  794. if
  795. StrLen > NewPrecision ->
  796. adjust(Adjust, makePadChars($*, NewPrecision, <<>>), <<>>);
  797. true ->
  798. adjust(Adjust, BinStrOrIoList, makePadChars(PadChar, Precision - StrLen, <<>>))
  799. end;
  800. true ->
  801. StrLen = charsLen(BinStrOrIoList),
  802. NewPrecision = min(StrLen, case Precision of none -> Width; _ -> min(Precision, Width) end),
  803. if
  804. StrLen > NewPrecision ->
  805. adjust(Adjust, makePadChars($*, NewPrecision, <<>>), makePadChars(PadChar, Width - NewPrecision, <<>>));
  806. true ->
  807. adjust(Adjust, BinStrOrIoList, makePadChars(PadChar, Width - StrLen, <<>>))
  808. end
  809. end.
  810. floatE(Float, Width, Adjust, Precision, PadChar) ->
  811. NewPrecision = ?CASE(Precision == none, 6, Precision),
  812. case Width of
  813. none ->
  814. float_to_binary(Float, [{scientific, NewPrecision}]);
  815. _ ->
  816. term(float_to_binary(Float, [{scientific, NewPrecision}]), Width, Adjust, Width, PadChar)
  817. end.
  818. floatF(Float, Width, Adjust, Precision, PadChar) ->
  819. NewPrecision = ?CASE(Precision == none, 6, Precision),
  820. case Width of
  821. none ->
  822. float_to_binary(Float, [{decimals, NewPrecision}]);
  823. _ ->
  824. term(float_to_binary(Float, [{decimals, NewPrecision}]), Width, Adjust, Width, PadChar)
  825. end.
  826. floatG(Float, Width, Adjust, Precision, PadChar) ->
  827. case Float > -10000.0 andalso Float < 10000.0 of
  828. true ->
  829. floatF(Float, Width, Adjust, Precision, PadChar);
  830. _ ->
  831. floatE(Float, Width, Adjust, Precision, PadChar)
  832. end.
  833. floatG(Float) ->
  834. float_to_binary(Float, [{decimals, 6}]).
  835. strToChars(BinStr, Width, CharsLimit) ->
  836. ByteSize = byte_size(BinStr),
  837. if
  838. Width == none ->
  839. case CharsLimit < 0 orelse CharsLimit >= ByteSize of
  840. true ->
  841. BinStr;
  842. _ ->
  843. <<(part(BinStr, 0, CharsLimit))/binary, "...">>
  844. end;
  845. CharsLimit < 0 orelse CharsLimit >= Width ->
  846. BinStr;
  847. true ->
  848. <<(part(BinStr, 0, CharsLimit))/binary, "...">>
  849. end.
  850. string(Str, Width, Adjust, Precision, PadChar, Encoding) ->
  851. if
  852. Width == none andalso Precision == none ->
  853. Str;
  854. Precision == none ->
  855. strField(Str, Width, Adjust, charsLen(Str), PadChar, Encoding);
  856. Width == none ->
  857. strField(Str, Precision, left, charsLen(Str), PadChar, Encoding);
  858. true ->
  859. StrLen = charsLen(Str),
  860. if
  861. Width > Precision ->
  862. if
  863. StrLen > Precision ->
  864. adjust(Adjust, flatTrunc(Str, Precision, Encoding), makePadChars(PadChar, Width - Precision, <<>>));
  865. StrLen < Precision ->
  866. adjust(Adjust, [Str | makePadChars(PadChar, Precision - StrLen, <<>>)], makePadChars(PadChar, Width - Precision, <<>>));
  867. true -> % N == P
  868. adjust(Adjust, Str, makePadChars(PadChar, Width - Precision, <<>>))
  869. end;
  870. true -> % F == P
  871. strField(Str, Width, Adjust, StrLen, PadChar, Encoding)
  872. end
  873. end.
  874. strField(Str, Width, Adjust, StrLen, PadChar, Encoding) when StrLen > Width ->
  875. if
  876. StrLen > Width ->
  877. flatTrunc(Str, Width, Encoding);
  878. StrLen < Width ->
  879. adjust(Adjust, Str, makePadChars(PadChar, Width - StrLen, <<>>));
  880. true ->
  881. Str
  882. end.
  883. flatTrunc(List, Width, _Encoding) ->
  884. part(iolist_to_binary(List), 0, Width).
  885. makePadChars(PadChar, Cnt, BinStr) ->
  886. case Cnt > 0 of
  887. true ->
  888. makePadChars(PadChar, Cnt - 1, <<BinStr/binary, PadChar:8>>);
  889. _ ->
  890. BinStr
  891. end.
  892. adjust(left, Data, Pad) -> [Data, Pad];
  893. adjust(right, Data, Pad) -> [Pad, Data].
  894. unPrefixedInt(Int, Width, Adjust, Base, PadChar, Lowercase) ->
  895. case Lowercase of
  896. true ->
  897. term(toLowerStr(integer_to_binary(Int, Base)), Width, Adjust, none, PadChar);
  898. _ ->
  899. term(integer_to_binary(Int, Base), Width, Adjust, none, PadChar)
  900. end.
  901. prefixedInt(Int, Width, Adjust, Base, PadChar, Prefix, Lowercase) ->
  902. case Int < 0 of
  903. true ->
  904. case Lowercase of
  905. true ->
  906. term(<<"-", (toBinary(Prefix))/binary, (toLowerStr(integer_to_binary(-Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  907. _ ->
  908. term(<<"-", (toBinary(Prefix))/binary, (integer_to_binary(-Int, Base))/binary>>, Width, Adjust, none, PadChar)
  909. end;
  910. _ ->
  911. case Lowercase of
  912. true ->
  913. term(<<(toBinary(Prefix))/binary, (toLowerStr(integer_to_binary(Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  914. _ ->
  915. term(<<(toBinary(Prefix))/binary, (integer_to_binary(Int, Base))/binary>>, Width, Adjust, none, PadChar)
  916. end
  917. end.
  918. prefixedInt(Int, Width, Adjust, Base, PadChar, Prefix, Prefix2, Lowercase) ->
  919. case Int < 0 of
  920. true ->
  921. case Lowercase of
  922. true ->
  923. term(<<"-", (toBinary(Prefix))/binary, Prefix2:8, (toLowerStr(integer_to_binary(-Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  924. _ ->
  925. term(<<"-", (toBinary(Prefix))/binary, Prefix2:8, (integer_to_binary(-Int, Base))/binary>>, Width, Adjust, none, PadChar)
  926. end;
  927. _ ->
  928. case Lowercase of
  929. true ->
  930. term(<<(toBinary(Prefix))/binary, Prefix2:8, (toLowerStr(integer_to_binary(Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  931. _ ->
  932. term(<<(toBinary(Prefix))/binary, Prefix2:8, (integer_to_binary(Int, Base))/binary>>, Width, Adjust, none, PadChar)
  933. end
  934. end.
  935. char(Char, Width, Adjust, Precision, PadChar) ->
  936. if
  937. Width == none andalso Precision == none ->
  938. Char;
  939. Precision == none ->
  940. makePadChars(Char, Width, <<>>);
  941. Width == none ->
  942. makePadChars(Char, Precision, <<>>);
  943. true ->
  944. adjust(Adjust, makePadChars(Char, Precision, <<>>), makePadChars(PadChar, Width - Precision, <<>>))
  945. end.
  946. newline(none, _Adjust, _Precision, _PadChar) -> <<"\n">>;
  947. newline(Width, Adjust, _Precision, _PadChar) ->
  948. case Adjust of
  949. right ->
  950. makePadChars($\n, Width, <<>>);
  951. _ ->
  952. <<"\n">>
  953. end.
  954. remainChars(T, E) ->
  955. if
  956. T < 0 ->
  957. T;
  958. T >= E ->
  959. T - E;
  960. true ->
  961. 0
  962. end.
  963. %% ********************************************** eFmtFormat end *****************************************************
  964. %% ********************************************** utils start **********************************************************
  965. toLowerStr(BinStr) ->
  966. <<begin
  967. case C >= $A andalso C =< $Z of
  968. true ->
  969. <<(C + 32)>>;
  970. _ ->
  971. <<C>>
  972. end
  973. end || <<C:8>> <= BinStr
  974. >>.
  975. toUpperStr(BinStr) ->
  976. <<begin
  977. case C >= $a andalso C =< $z of
  978. true ->
  979. <<(C - 32)>>;
  980. _ ->
  981. <<C>>
  982. end
  983. end || <<C:8>> <= BinStr
  984. >>.
  985. -spec charsLen(chars()) -> non_neg_integer().
  986. charsLen(S) ->
  987. try
  988. iolist_size(S)
  989. catch
  990. _:_ ->
  991. string:length(S)
  992. end.
  993. getOpt(Key, TupleList, Default) ->
  994. case keyfind(Key, 1, TupleList) of
  995. false ->
  996. Default;
  997. ValueTuple ->
  998. element(2, ValueTuple)
  999. end.
  1000. toBinary(Value) when is_integer(Value) -> integer_to_binary(Value);
  1001. toBinary(Value) when is_list(Value) -> list_to_binary(Value);
  1002. toBinary(Value) when is_float(Value) -> float_to_binary(Value, [{decimals, 6}, compact]);
  1003. toBinary(Value) when is_atom(Value) -> atom_to_binary(Value, utf8);
  1004. toBinary(Value) when is_binary(Value) -> Value;
  1005. toBinary(Value) -> term_to_binary(Value).
  1006. visualList(L, Encoding) ->
  1007. ?CASE(Encoding == latin1, visualLatin1List(L), visualUnicodeList(L, Encoding)).
  1008. visualBin(Bin, Encoding) ->
  1009. ?CASE(Encoding == latin1, visualLatin1Bin(Bin), visualUtf8Bin(Bin, io:printable_range())).
  1010. visualLatin1List([]) -> true;
  1011. visualLatin1List([C | Cs]) -> ?CASE(visualLatin1Char(C), visualLatin1List(Cs), false);
  1012. visualLatin1List(_) -> false.
  1013. visualUnicodeList([], _) -> true;
  1014. visualUnicodeList([C | Cs], Encoding) -> ?CASE(visualUtf8Char(C, Encoding), visualUnicodeList(Cs, Encoding), false);
  1015. visualUnicodeList(_, _) -> false.
  1016. visualLatin1Bin(<<>>) -> true;
  1017. visualLatin1Bin(<<C:8, Left/binary>>) -> ?CASE(visualLatin1Char(C), visualLatin1Bin(Left), false);
  1018. visualLatin1Bin(_) -> false.
  1019. visualUtf8Bin(<<>>, _) -> true;
  1020. visualUtf8Bin(<<C/utf8, Left/binary>>, Range) -> ?CASE(visualUtf8Char(C, Range), visualUtf8Bin(Left, Range), false);
  1021. visualUtf8Bin(_, _) -> false.
  1022. visualLatin1Char($\n) -> true;
  1023. visualLatin1Char($\r) -> true;
  1024. visualLatin1Char($\t) -> true;
  1025. visualLatin1Char($\v) -> true;
  1026. visualLatin1Char($\b) -> true;
  1027. visualLatin1Char($\f) -> true;
  1028. visualLatin1Char($\e) -> true;
  1029. visualLatin1Char(C) -> C >= $\040 andalso C =< $\176 orelse C >= $\240 andalso C =< $\377.
  1030. visualUtf8Char($\n, _) -> true;
  1031. visualUtf8Char($\r, _) -> true;
  1032. visualUtf8Char($\t, _) -> true;
  1033. visualUtf8Char($\v, _) -> true;
  1034. visualUtf8Char($\b, _) -> true;
  1035. visualUtf8Char($\f, _) -> true;
  1036. visualUtf8Char($\e, _) -> true;
  1037. visualUtf8Char(C, _Encoding) -> C >= $\s andalso C =< $~ orelse C >= 16#A0 andalso C < 16#D800 orelse C > 16#DFFF andalso C < 16#FFFE orelse C > 16#FFFF andalso C =< 16#10FFFF.
  1038. %% case Encoding of
  1039. %% latin1 ->
  1040. %% C >= $\s andalso C =< $~ orelse C >= 16#A0 andalso C =< 16#FF;
  1041. %% _ ->
  1042. %% C >= $\s andalso C =< $~ orelse C >= 16#A0 andalso C < 16#D800 orelse C > 16#DFFF andalso C < 16#FFFE orelse C > 16#FFFF andalso C =< 16#10FFFF
  1043. %% end.
  1044. %% ********************************************** utils end **********************************************************