Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

601 řádky
24 KiB

před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
před 4 roky
  1. -module(eFmtFormat).
  2. -include("eFmt.hrl").
  3. -compile(export_all).
  4. %% Formatting functions of io library.
  5. -export([
  6. fwrite/2
  7. , fwrite/3
  8. , floatG/1
  9. , scan/2
  10. , build/1
  11. , build/2
  12. ]).
  13. %% 在字符串格式之后将参数格式化为Args。刚产生
  14. %% 如果参数中有错误,则为错误。
  15. %%
  16. %% 要正确执行打印命令,我们需要计算
  17. %% 当前缩进的所有内容。这可能非常
  18. %% 价格昂贵,尤其是在不需要时,因此我们首先确定
  19. %% 是否以及需要多长时间来计算缩进。我们的确是
  20. %% 首先收集所有控制序列,然后
  21. %% 相应的参数,然后计算打印顺序,然后
  22. %% 然后构建输出。这种方法有一些缺点,它确实
  23. %% 在格式字符串上两次传递并创建更多临时数据,
  24. %% 并且还将控制字符的处理分为两个
  25. %% 部分。
  26. -spec fwrite(Format :: io:format(), Data :: [term()]) -> eFmt:chars().
  27. fwrite(Format, Args) ->
  28. build(scan(Format, Args)).
  29. -spec fwrite(Format :: io:format(), Data :: [term()], Options :: [{'chars_limit', CharsLimit :: integer()}]) -> eFmt:chars().
  30. fwrite(Format, Args, Options) ->
  31. build(scan(Format, Args), Options).
  32. %% Parse all control sequences in the format string.
  33. -spec scan(Format :: io:format(), Data :: [term()]) -> FormatList :: [char() | eFmt:fmtSpec()].
  34. %% 格式 ~F.P.PadModC
  35. scan(Format, Args) ->
  36. if
  37. is_atom(Format) ->
  38. doCollect(atom_to_binary(Format, utf8), Args, []);
  39. is_list(Format) ->
  40. doCollect(list_to_binary(Format), Args, []);
  41. true ->
  42. doCollect(Format, Args, [])
  43. end.
  44. doCollect(FmtBinStr, Args, Acc) ->
  45. case binary:split(FmtBinStr, <<"~">>) of
  46. [NotMatch] ->
  47. [NotMatch | Acc];
  48. [FPart, LPart] ->
  49. doCollWidth(LPart, Args, 0, left, [FPart | Acc])
  50. end.
  51. doCollWidth(<<>>, _Args, _Width, _Adjust, Acc) ->
  52. Acc;
  53. doCollWidth(LPart, Args, Width, Adjust, Acc) ->
  54. %% 匹配宽度
  55. case LPart of
  56. <<"-*", LeftLPart/binary>> ->
  57. [WidthArgs | LeftArgs] = Args,
  58. doCollPrecision(LeftLPart, LeftArgs, WidthArgs, left, Acc);
  59. <<"-", LeftLPart/binary>> ->
  60. doCollWidth(LeftLPart, Args, Width, left, Acc);
  61. <<"*", LeftLPart/binary>> ->
  62. [WidthArgs | LeftArgs] = Args,
  63. doCollPrecision(LeftLPart, LeftArgs, WidthArgs, right, Acc);
  64. <<WidthInt:8/integer, LeftLPart/binary>> ->
  65. case WidthInt >= $0 andalso WidthInt =< $9 of
  66. true ->
  67. doCollWidth(LeftLPart, Args, 10 * Width + (WidthInt - $0), Adjust, Acc);
  68. _ ->
  69. case Width == 0 of
  70. true ->
  71. doCollPrecision(LPart, Args, none, Adjust, Acc);
  72. _ ->
  73. doCollPrecision(LPart, Args, Width, Adjust, Acc)
  74. end
  75. end
  76. end.
  77. doCollPrecision(LPart, Args, Width, Adjust, Acc) ->
  78. case LPart of
  79. <<".", LeftLPart/binary>> ->
  80. doCollPrecision(LeftLPart, Args, Width, Adjust, 0, Acc);
  81. _ ->
  82. doCollPadChar(LPart, Args, Width, Adjust, none, Acc)
  83. end.
  84. doCollPrecision(LPart, Args, Width, Adjust, Precision, Acc) ->
  85. case LPart of
  86. <<"*", LeftLPart/binary>> ->
  87. [PrecisionArgs | LeftArgs] = Args,
  88. doCollPadChar(LeftLPart, LeftArgs, Width, Adjust, PrecisionArgs, Acc);
  89. <<PrecisionInt:8/integer, LeftLPart/binary>> ->
  90. case PrecisionInt >= $0 andalso PrecisionInt =< $9 of
  91. true ->
  92. doCollPrecision(LeftLPart, Args, Width, Adjust, 10 * Precision + (PrecisionInt - $0));
  93. _ ->
  94. case Precision == 0 of
  95. true ->
  96. doCollPadChar(LPart, Args, Width, Adjust, none, Acc);
  97. _ ->
  98. doCollPadChar(LPart, Args, Width, Adjust, Precision, Acc)
  99. end
  100. end
  101. end.
  102. doCollPadChar(LPart, Args, Width, Adjust, Precision, Acc) ->
  103. case LPart of
  104. <<".*", LeftLPart/binary>> ->
  105. [PadChar | LeftArgs] = Args,
  106. doCollEncoding(LeftLPart, LeftArgs, Width, Adjust, Precision, PadChar, Acc);
  107. <<".", PadChar:8/integer, LeftLPart/binary>> ->
  108. doCollEncoding(LeftLPart, Args, Width, Adjust, Precision, PadChar, Acc);
  109. _ ->
  110. doCollEncoding(LPart, Args, Width, Adjust, Precision, 32, Acc)
  111. end.
  112. doCollEncoding(LPart, Args, Width, Adjust, Precision, PadChar, Acc) ->
  113. case LPart of
  114. <<"t", LeftLPart/binary>> ->
  115. %true = Char =/= $l,
  116. doCollStrings(LeftLPart, Args, Width, Adjust, Precision, PadChar, unicode, Acc);
  117. _ ->
  118. doCollStrings(LPart, Args, Width, Adjust, Precision, PadChar, latin1, Acc)
  119. end.
  120. doCollStrings(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, Acc) ->
  121. case LPart of
  122. <<"l", LeftLPart/binary>> ->
  123. %true = Char =/= $t,
  124. doCollCA(LeftLPart, Args, Width, Adjust, Precision, PadChar, Encoding, false, Acc);
  125. _ ->
  126. doCollCA(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, true, Acc)
  127. end.
  128. doCollCA(LPart, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, Acc) ->
  129. <<CtlChar:8/integer, LeftLPart/binary>> = LPart,
  130. case CtlChar of
  131. $w -> [OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  132. $p ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  133. $W ->[OneArgs | LeftArgs] = Args, [Depth | LastArgs] = LeftArgs, As = [OneArgs, Depth], NextArgs = LastArgs;
  134. $P -> [OneArgs | LeftArgs] = Args,[Depth | LastArgs] = LeftArgs, As = [OneArgs, Depth], NextArgs = LastArgs;
  135. $s ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  136. $e ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  137. $f ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  138. $g -> [OneArgs | LeftArgs] = Args,As = OneArgs, NextArgs = LeftArgs;
  139. $b ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  140. $B ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  141. $x ->[OneArgs | LeftArgs] = Args, [Prefix | LastArgs] = LeftArgs, As = [OneArgs, Prefix], NextArgs = LastArgs;
  142. $X -> [OneArgs | LeftArgs] = Args,[Prefix | LastArgs] = LeftArgs, As = [OneArgs, Prefix], NextArgs = LastArgs;
  143. $+ -> [OneArgs | LeftArgs] = Args,As = OneArgs, NextArgs = LeftArgs;
  144. $# ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  145. $c ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs;
  146. $~ -> As = undefined, NextArgs = Args;
  147. $n -> As = undefined, NextArgs = Args;
  148. $i ->[OneArgs | LeftArgs] = Args, As = OneArgs, NextArgs = LeftArgs
  149. end,
  150. FmtSpec = #fmtSpec{ctlChar = CtlChar, args = As, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings},
  151. doCollect(LeftLPart, NextArgs, [FmtSpec | Acc]).
  152. %% Build the output text for a pre-parsed format list.
  153. -spec build(FormatList :: [char() | eFmt:fmtSpec()]) -> eFmt:chars().
  154. build(Cs) ->
  155. build(Cs, []).
  156. -spec build(FormatList :: [char() | eFmt:fmtSpec()], Options :: [{'chars_limit', CharsLimit :: integer()}]) -> eFmt:chars().
  157. build(Cs, Options) ->
  158. CharsLimit = getOpt(chars_limit, Options, -1),
  159. ResList = buildSmall(Cs, []),
  160. {P, S, W, Other} = cntSmall(ResList, 0, 0, 0, 0),
  161. case P + S + W of
  162. 0 ->
  163. ResList;
  164. NumOfLimited ->
  165. RemainChars = remainChars(CharsLimit, Other),
  166. buildLimited(ResList, P, NumOfLimited, RemainChars, 0, [])
  167. end.
  168. %% build_small([Control]) -> eFmt:chars().
  169. %% Interpret the control structures, but only the small ones. The big ones are saved for later.
  170. %% build_limited([Control], NumberOfPps, NumberOfLimited, CharsLimit, Indentation)
  171. %% Interpret the control structures. Count the number of print
  172. %% remaining and only calculate indentation when necessary. Must also
  173. %% be smart when calculating indentation for characters in format.
  174. buildSmall([], Acc) -> Acc;
  175. buildSmall([OneCA | Cs], Acc) ->
  176. case OneCA of
  177. #fmtSpec{ctlChar = CtlChar, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding} ->
  178. case ctlSmall(CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding) of
  179. not_small -> buildSmall(Cs, [OneCA | Acc]);
  180. ignore -> buildSmall(Cs, Acc);
  181. Str -> buildSmall(Cs, [Str | Acc])
  182. end;
  183. _ ->
  184. buildSmall(Cs, [OneCA | Acc])
  185. end.
  186. %% control_small(FormatChar, [Argument], FieldWidth, Adjust, Precision,
  187. %% PadChar, Encoding) -> String
  188. %% control_limited(FormatChar, [Argument], FieldWidth, Adjust, Precision,
  189. %% PadChar, Encoding, StringP, ChrsLim, Indentation) -> String
  190. %% These are the dispatch functions for the various formatting controls.
  191. ctlSmall($s, Args, Width, Adjust, Precision, PadChar, Encoding) when is_atom(Args) ->
  192. case Encoding of
  193. latin1 ->
  194. AtomBinStr = eFmt:writeAtom(Args, latin1);
  195. _ ->
  196. AtomBinStr = eFmt:writeAtom(Args, uft8)
  197. end,
  198. string(AtomBinStr, Width, Adjust, Precision, PadChar, Encoding);
  199. ctlSmall($e, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_float(Args) ->
  200. floatE(Args, Width, Adjust, Precision, PadChar);
  201. ctlSmall($f, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_float(Args) ->
  202. floatF(Args, Width, Adjust, Precision, PadChar);
  203. ctlSmall($g, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_float(Args) ->
  204. floatG(Args, Width, Adjust, Precision, PadChar);
  205. ctlSmall($b, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  206. unPrefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, true);
  207. ctlSmall($B, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  208. unPrefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, false);
  209. ctlSmall($x, [Args, Prefix], Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args), is_atom(Prefix) ->
  210. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, atom_to_binary(Prefix, utf8), true);
  211. ctlSmall($x, [Args, Prefix], Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  212. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, Prefix, true);
  213. ctlSmall($X, [Args, Prefix], Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args), is_atom(Prefix) ->
  214. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, atom_to_binary(Prefix, utf8), false);
  215. ctlSmall($X, [Args, Prefix], Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  216. prefixedInt(Args, Width, Adjust, ?base(Precision), PadChar, Prefix, false);
  217. ctlSmall($+, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  218. Base = ?base(Precision),
  219. prefixedInt(Args, Width, Adjust, Base, PadChar, integer_to_binary(Base), $#, true);
  220. ctlSmall($#, Args, Width, Adjust, Precision, PadChar, _Encoding) when is_integer(Args) ->
  221. Base = ?base(Precision),
  222. prefixedInt(Args, Width, Adjust, Base, PadChar, integer_to_binary(Base), $#, false);
  223. ctlSmall($c,Args, Width, Adjust, Precision, PadChar, Encoding) when is_integer(Args) ->
  224. case Encoding of
  225. unicode ->
  226. char(Args, Width, Adjust, Precision, PadChar);
  227. _ ->
  228. char(Args band 255, Width, Adjust, Precision, PadChar)
  229. end;
  230. ctlSmall($~, _Args, Width, Adjust, Precision, PadChar, _Encoding) -> char($~, Width, Adjust, Precision, PadChar);
  231. ctlSmall($n, _Args, Width, Adjust, Precision, PadChar, _Encoding) -> newline(Width, Adjust, Precision, PadChar);
  232. ctlSmall($i, _Args, _Width, _Adjust, _Precision, _PadChar, _Encoding) -> ignore;
  233. ctlSmall(_C, _Args, _Width, _Adjust, _Precision, _PadChar, _Encoding) -> not_small.
  234. cntSmall([], P, S, W, Other) ->
  235. {P, S, W, Other};
  236. cntSmall([OneRes | Cs], P, S, W, Other) ->
  237. case OneRes of
  238. #fmtSpec{ctlChar = CtlChar} ->
  239. case CtlChar of
  240. $p ->
  241. cntSmall(Cs, P + 1, S, W, Other);
  242. $P ->
  243. cntSmall(Cs, P + 1, S, W, Other);
  244. $w ->
  245. cntSmall(Cs, P, S, W + 1, Other);
  246. $W ->
  247. cntSmall(Cs, P, S, W + 1, Other);
  248. $s ->
  249. cntSmall(Cs, P, S, W + 1, Other);
  250. _ ->
  251. cntSmall(Cs, P, S, W, Other)
  252. end;
  253. _ ->
  254. if
  255. is_binary(OneRes) orelse is_list(OneRes) ->
  256. cntSmall(Cs, P, S, W, Other + eFmt:charsLen(OneRes));
  257. is_integer(OneRes) ->
  258. cntSmall(Cs, P, S, W, Other + 1);
  259. true ->
  260. cntSmall(Cs, P, S, W, Other)
  261. end
  262. end.
  263. buildLimited([], _, _, _, _, Acc) -> Acc;
  264. buildLimited([OneCA | Cs], NumOfPs, Count, MaxLen, I, Acc) ->
  265. case OneCA of
  266. #fmtSpec{ctlChar = CtlChar, args = Args, width = Width, adjust = Adjust, precision = Precision, padChar = PadChar, encoding = Encoding, strings = Strings} ->
  267. MaxChars = if MaxLen < 0 -> MaxLen; true -> MaxLen div Count end,
  268. IoListStr = ctlLimited(CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I),
  269. NewNumOfPs = decrPc(CtlChar, NumOfPs),
  270. NewCount = Count - 1,
  271. MaxLen = ?IIF(MaxLen < 0, MaxLen, remainChars(MaxLen, eFmt:charsLen(IoListStr))),
  272. if
  273. NewNumOfPs > 0 ->
  274. buildLimited(Cs, NewNumOfPs, NewCount, MaxLen, I, [IoListStr | Acc]);
  275. true ->
  276. buildLimited(Cs, NewNumOfPs, NewCount, MaxLen, I, [IoListStr | Acc])
  277. end;
  278. _ ->
  279. buildLimited(Cs, NumOfPs, Count, MaxLen, I + 1, [OneCA | Acc])
  280. end.
  281. decrPc($p, Pc) -> Pc - 1;
  282. decrPc($P, Pc) -> Pc - 1;
  283. decrPc(_, Pc) -> Pc.
  284. %% (CtlChar, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, MaxChars, I)
  285. ctlLimited($s, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  286. case Encoding of
  287. latin1 ->
  288. BinStr = erlang:iolist_to_binary(Args);
  289. _ ->
  290. BinStr = case catch unicode:characters_to_binary(Args, unicode) of
  291. Str when is_binary(Str) -> Str;
  292. _ -> toBinary(Args)
  293. end
  294. end,
  295. TemBinStr = strToChars(BinStr, Width, CharsLimit),
  296. string(TemBinStr, ?IIF(CharsLimit < 0 orelse Width =:= none, Width, max(3, min(Width, CharsLimit))), Adjust, Precision, PadChar, Encoding);
  297. ctlLimited($w, Args, Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  298. Chars = eFmt:doWrite(Args, -1, Encoding, CharsLimit),
  299. term(Chars, Width, Adjust, Precision, PadChar);
  300. ctlLimited($p, Args, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I) ->
  301. print(Args, -1, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I);
  302. ctlLimited($W, [Args, Depth], Width, Adjust, Precision, PadChar, Encoding, _Strings, CharsLimit, _I) ->
  303. Chars = eFmt:doWrite(Args, Depth, Encoding, CharsLimit),
  304. term(Chars, Width, Adjust, Precision, PadChar);
  305. ctlLimited($P, [Args, Depth], Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I) ->
  306. print(Args, Depth, Width, Adjust, Precision, PadChar, Encoding, Strings, CharsLimit, I).
  307. %% term(TermList, Field, Adjust, Precision, PadChar)
  308. %% Output the characters in a term.
  309. %% Adjust the characters within the field if length less than Max padding
  310. %% with PadChar.
  311. term(BinStrOrIoList, Width, Adjust, Precision, PadChar) ->
  312. if
  313. Width == none andalso Precision == none ->
  314. BinStrOrIoList;
  315. Width == none ->
  316. StrLen = eFmt:charsLen(BinStrOrIoList),
  317. NewPrecision = erlang:min(StrLen, Precision),
  318. if
  319. StrLen > NewPrecision ->
  320. adjust(Adjust, makePadChars($*, NewPrecision, <<>>), <<>>);
  321. true ->
  322. adjust(Adjust, BinStrOrIoList, makePadChars(PadChar, Precision - StrLen, <<>>))
  323. end;
  324. true ->
  325. StrLen = eFmt:charsLen(BinStrOrIoList),
  326. NewPrecision = erlang:min(StrLen, case Precision of none -> Width; _ -> min(Precision, Width) end),
  327. if
  328. StrLen > NewPrecision ->
  329. adjust(Adjust, makePadChars($*, NewPrecision, <<>>), makePadChars(PadChar, Width - NewPrecision, <<>>));
  330. true ->
  331. adjust(Adjust, BinStrOrIoList, makePadChars(PadChar, Width - StrLen, <<>>))
  332. end
  333. end.
  334. %% print(Term, Depth, Field, Adjust, Precision, PadChar, Encoding,
  335. %% Indentation)
  336. %% Print a term. Field width sets maximum line length, Precision sets
  337. %% initial indentation.
  338. print(T, D, none, Adj, P, Pad, E, Str, ChLim, I) ->
  339. print(T, D, 80, Adj, P, Pad, E, Str, ChLim, I);
  340. print(T, D, F, Adj, none, Pad, E, Str, ChLim, I) ->
  341. print(T, D, F, Adj, I + 1, Pad, E, Str, ChLim, I);
  342. print(T, D, F, right, P, _Pad, Enc, Str, ChLim, _I) ->
  343. Options = [{chars_limit, ChLim},
  344. {column, P},
  345. {line_length, F},
  346. {depth, D},
  347. {encoding, Enc},
  348. {strings, Str}],
  349. eFmt_pretty:print(T, Options).
  350. floatE(Float, Width, Adjust, Precision, PadChar) ->
  351. case Precision of
  352. none ->
  353. NewPrecision = 6;
  354. _ ->
  355. NewPrecision = Precision
  356. end,
  357. case Width of
  358. none ->
  359. float_to_binary(Float, [{scientific, NewPrecision}]);
  360. _ ->
  361. term(float_to_binary(Float, [{scientific, NewPrecision}]), Width, Adjust, Width, PadChar)
  362. end.
  363. floatF(Float, Width, Adjust, Precision, PadChar) ->
  364. case Precision of
  365. none ->
  366. NewPrecision = 6;
  367. _ ->
  368. NewPrecision = Precision
  369. end,
  370. case Width of
  371. none ->
  372. float_to_binary(Float, [{decimals, NewPrecision}]);
  373. _ ->
  374. term(float_to_binary(Float, [{decimals, NewPrecision}]), Width, Adjust, Width, PadChar)
  375. end.
  376. %% fwrite_g(Float, Field, Adjust, Precision, PadChar)
  377. %% Use the f form if Float is >= 0.1 and < 1.0e4,
  378. %% and the prints correctly in the f form, else the e form.
  379. %% Precision always means the # of significant digits.
  380. floatG(Float, Width, Adjust, Precision, PadChar) ->
  381. case Float > -10000.0 andalso Float < 10000.0 of
  382. true ->
  383. floatF(Float, Width, Adjust, Precision, PadChar);
  384. _ ->
  385. floatE(Float, Width, Adjust, Precision, PadChar)
  386. end.
  387. floatG(Float) ->
  388. float_to_binary(Float, [{decimals, 6}]).
  389. strToChars(BinStr, Width, CharsLimit) ->
  390. ByteSize = byte_size(BinStr),
  391. if
  392. Width == none ->
  393. case CharsLimit < 0 orelse CharsLimit >= ByteSize of
  394. true ->
  395. BinStr;
  396. _ ->
  397. <<(binary:part(BinStr, 0, CharsLimit))/binary, "...">>
  398. end;
  399. CharsLimit < 0 orelse CharsLimit >= Width ->
  400. BinStr;
  401. true ->
  402. <<(binary:part(BinStr, 0, CharsLimit))/binary, "...">>
  403. end.
  404. string(Str, Width, Adjust, Precision, PadChar, Encoding) ->
  405. if
  406. Width == none andalso Precision == none ->
  407. Str;
  408. Precision == none ->
  409. strField(Str, Width, Adjust, eFmt:charsLen(Str), PadChar, Encoding);
  410. Width == none ->
  411. strField(Str, Precision, left, eFmt:charsLen(Str), PadChar, Encoding);
  412. true ->
  413. StrLen = eFmt:charsLen(Str),
  414. if
  415. Width > Precision ->
  416. if StrLen > Precision ->
  417. adjust(Adjust, flatTrunc(Str, Precision, Encoding), makePadChars(PadChar, Width - Precision, <<>>));
  418. StrLen < Precision ->
  419. adjust(Adjust, [Str | makePadChars(PadChar, Precision - StrLen, <<>>)], makePadChars(PadChar, Width - Precision, <<>>));
  420. true -> % N == P
  421. adjust(Adjust, Str, makePadChars(PadChar, Width - Precision, <<>>))
  422. end;
  423. true -> % F == P
  424. strField(Str, Width, Adjust, StrLen, PadChar, Encoding)
  425. end
  426. end.
  427. strField(Str, Width, Adjust, StrLen, PadChar, Encoding) when StrLen > Width ->
  428. if
  429. StrLen > Width ->
  430. flatTrunc(Str, Width, Encoding);
  431. StrLen < Width ->
  432. adjust(Adjust, Str, makePadChars(PadChar, Width - StrLen, <<>>));
  433. true ->
  434. Str
  435. end.
  436. flatTrunc(List, Width, _Encoding) ->
  437. binary:part(iolist_to_binary(List), 0, Width).
  438. makePadChars(Char, Cnt, BinStr) ->
  439. case Cnt > 0 of
  440. true ->
  441. makePadChars(Cnt - 1, Char, <<BinStr/binary, (integer_to_binary(Char))/binary>>);
  442. _ ->
  443. BinStr
  444. end.
  445. adjust(left, Data, Pad) -> [Data, Pad];
  446. adjust(right, Data, Pad) -> [Pad, Data].
  447. unPrefixedInt(Int, Width, Adjust, Base, PadChar, Lowercase) ->
  448. case Lowercase of
  449. true ->
  450. term(toLowerStr(integer_to_binary(Int, Base)), Width, Adjust, none, PadChar);
  451. _ ->
  452. term(integer_to_binary(Int, Base), Width, Adjust, none, PadChar)
  453. end.
  454. prefixedInt(Int, Width, Adjust, Base, PadChar, Prefix, Lowercase) ->
  455. case Int < 0 of
  456. true ->
  457. case Lowercase of
  458. true ->
  459. term(<<"-", (toBinary(Prefix))/binary, (toLowerStr(integer_to_binary(-Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  460. _ ->
  461. term(<<"-", (toBinary(Prefix))/binary, (integer_to_binary(-Int, Base))/binary>>, Width, Adjust, none, PadChar)
  462. end;
  463. _ ->
  464. case Lowercase of
  465. true ->
  466. term(<<(toBinary(Prefix))/binary, (toLowerStr(integer_to_binary(Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  467. _ ->
  468. term(<<(toBinary(Prefix))/binary, (integer_to_binary(Int, Base))/binary>>, Width, Adjust, none, PadChar)
  469. end
  470. end.
  471. prefixedInt(Int, Width, Adjust, Base, PadChar, Prefix, Prefix2, Lowercase) ->
  472. case Int < 0 of
  473. true ->
  474. case Lowercase of
  475. true ->
  476. term(<<"-", (toBinary(Prefix))/binary, Prefix2:8, (toLowerStr(integer_to_binary(-Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  477. _ ->
  478. term(<<"-", (toBinary(Prefix))/binary, Prefix2:8, (integer_to_binary(-Int, Base))/binary>>, Width, Adjust, none, PadChar)
  479. end;
  480. _ ->
  481. case Lowercase of
  482. true ->
  483. term(<<(toBinary(Prefix))/binary, Prefix2:8, (toLowerStr(integer_to_binary(Int, Base)))/binary>>, Width, Adjust, none, PadChar);
  484. _ ->
  485. term(<<(toBinary(Prefix))/binary, Prefix2:8, (integer_to_binary(Int, Base))/binary>>, Width, Adjust, none, PadChar)
  486. end
  487. end.
  488. char(Char, Width, Adjust, Precision, PadChar) ->
  489. if
  490. Width == none andalso Precision == none ->
  491. integer_to_binary(Char);
  492. Precision == none ->
  493. makePadChars(Char, Width, <<>>);
  494. Width == none ->
  495. makePadChars(Char, Precision, <<>>);
  496. true ->
  497. adjust(Adjust, makePadChars(Char, Precision, <<>>), makePadChars(PadChar, Width - Precision, <<>>))
  498. end.
  499. newline(none, _Adjust, _Precision, _PadChar) -> <<"\n">>;
  500. newline(Width, Adjust, _Precision, _PadChar) ->
  501. case Adjust of
  502. right ->
  503. makePadChars($\n, Width, <<>>);
  504. _ ->
  505. <<"\n">>
  506. end.
  507. remainChars(T, E) ->
  508. if
  509. T < 0 ->
  510. T;
  511. T >= E ->
  512. T - E;
  513. true ->
  514. 0
  515. end.
  516. getOpt(Key, TupleList, Default) ->
  517. case lists:keyfind(Key, 1, TupleList) of
  518. {_, Value} ->
  519. Value;
  520. _ ->
  521. Default
  522. end.
  523. toLowerStr(BinStr) ->
  524. << begin
  525. case C >= $A andalso C =< $Z of
  526. true ->
  527. <<(C + 32)>>;
  528. _ ->
  529. <<C>>
  530. end
  531. end || <<C:8>> <= BinStr
  532. >>.
  533. toUpperStr(BinStr) ->
  534. << begin
  535. case C >= $a andalso C =< $z of
  536. true ->
  537. <<(C - 32)>>;
  538. _ ->
  539. <<C>>
  540. end
  541. end || <<C:8>> <= BinStr
  542. >>.
  543. toBinary(Value) when is_integer(Value) -> integer_to_binary(Value);
  544. toBinary(Value) when is_list(Value) -> list_to_binary(Value);
  545. toBinary(Value) when is_float(Value) -> float_to_binary(Value, [{decimals, 6}, compact]);
  546. toBinary(Value) when is_atom(Value) -> atom_to_binary(Value, utf8);
  547. toBinary(Value) when is_binary(Value) -> Value;
  548. toBinary([Tuple | PropList] = Value) when is_list(PropList) and is_tuple(Tuple) ->
  549. lists:map(fun({K, V}) -> {toBinary(K), toBinary(V)} end, Value);
  550. toBinary(Value) -> term_to_binary(Value).