1: %% -*- coding: utf-8 -*- 2: %% 3: %% %CopyrightBegin% 4: %% 5: %% Copyright Ericsson AB 1999-2013. All Rights Reserved. 6: %% 7: %% The contents of this file are subject to the Erlang Public License, 8: %% Version 1.1, (the "License"); you may not use this file except in 9: %% compliance with the License. You should have received a copy of the 10: %% Erlang Public License along with this software. If not, it can be 11: %% retrieved online at http://www.erlang.org/. 12: %% 13: %% Software distributed under the License is distributed on an "AS IS" 14: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 15: %% the License for the specific language governing rights and limitations 16: %% under the License. 17: %% 18: %% %CopyrightEnd% 19: %% 20: -module(io_SUITE). 21: 22: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 23: init_per_group/2,end_per_group/2]). 24: 25: -export([init_per_testcase/2, end_per_testcase/2]). 26: 27: -export([error_1/1, float_g/1, otp_5403/1, otp_5813/1, otp_6230/1, 28: otp_6282/1, otp_6354/1, otp_6495/1, otp_6517/1, otp_6502/1, 29: manpage/1, otp_6708/1, otp_7084/1, otp_7421/1, 30: io_lib_collect_line_3_wb/1, cr_whitespace_in_string/1, 31: io_fread_newlines/1, otp_8989/1, io_lib_fread_literal/1, 32: printable_range/1, 33: io_lib_print_binary_depth_one/1, otp_10302/1, otp_10755/1, 34: otp_10836/1]). 35: 36: -export([pretty/2]). 37: 38: %-define(debug, true). 39: 40: -ifdef(debug). 41: -define(format(S, A), io:format(S, A)). 42: -define(line, put(line, ?LINE), ). 43: -define(config(X,Y), foo). 44: -define(t, test_server). 45: -define(privdir(_), "./io_SUITE_priv"). 46: -else. 47: -include_lib("test_server/include/test_server.hrl"). 48: -define(format(S, A), ok). 49: -define(privdir(Conf), ?config(priv_dir, Conf)). 50: -endif. 51: 52: 53: % Default timetrap timeout (set in init_per_testcase). 54: -define(default_timeout, ?t:minutes(1)). 55: 56: init_per_testcase(_Case, Config) -> 57: ?line Dog = ?t:timetrap(?default_timeout), 58: [{watchdog, Dog} | Config]. 59: end_per_testcase(_Case, _Config) -> 60: Dog = ?config(watchdog, _Config), 61: test_server:timetrap_cancel(Dog), 62: ok. 63: 64: suite() -> [{ct_hooks,[ts_install_cth]}]. 65: 66: all() -> 67: [error_1, float_g, otp_5403, otp_5813, otp_6230, 68: otp_6282, otp_6354, otp_6495, otp_6517, otp_6502, 69: manpage, otp_6708, otp_7084, otp_7421, 70: io_lib_collect_line_3_wb, cr_whitespace_in_string, 71: io_fread_newlines, otp_8989, io_lib_fread_literal, 72: printable_range, 73: io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836]. 74: 75: groups() -> 76: []. 77: 78: init_per_suite(Config) -> 79: Config. 80: 81: end_per_suite(_Config) -> 82: ok. 83: 84: init_per_group(_GroupName, Config) -> 85: Config. 86: 87: end_per_group(_GroupName, Config) -> 88: Config. 89: 90: 91: error_1(doc) -> 92: ["Error cases for output"]; 93: error_1(suite) -> 94: []; 95: error_1(Config) when is_list(Config) -> 96: %% We don't do erroneous output on stdout - the test server 97: %% seems to catch that somehow. 98: ?line PrivDir = ?privdir(Config), 99: ?line File = filename:join(PrivDir, "slask"), 100: ?line {ok, F1} = file:open(File, [write]), 101: ?line {'EXIT', _} = (catch io:format(muttru, "hej", [])), 102: ?line {'EXIT', _} = (catch io:format(F1, pelle, "hej")), 103: ?line {'EXIT', _} = (catch io:format(F1, 1, "hej")), 104: ?line {'EXIT', _} = (catch io:format(F1, "~p~", [kaka])), 105: ?line {'EXIT', _} = (catch io:format(F1, "~m~n", [kaka])), 106: 107: %% This causes the file process to die, and it is linked to us, 108: %% so we can't catch the error this easily. 109: % ?line {'EXIT', _} = (catch io:put_chars(F1, 666)), 110: 111: ?line file:close(F1), 112: ?line {'EXIT', _} = (catch io:format(F1, "~p", ["hej"])), 113: ok. 114: 115: float_g(Config) when is_list(Config) -> 116: ?line ["5.00000e-2", 117: "0.500000", 118: "5.00000", 119: "50.0000", 120: "500.000", 121: "5000.00", 122: "5.00000e+4", 123: "5.00000e+5"] = float_g_1("~g", 5.0, -2, 5), 124: 125: ?line ["-5.0000e-2", 126: "-0.50000", 127: "-5.0000", 128: "-50.000", 129: "-500.00", 130: "-5000.0", 131: "-5.0000e+4", 132: "-5.0000e+5"] = float_g_1("~.5g", -5.0, -2, 5), 133: 134: ?line ["5.000e-2", 135: "0.5000", 136: "5.000", 137: "50.00", 138: "500.0", 139: "5.000e+3", 140: "5.000e+4", 141: "5.000e+5"] = float_g_1("~.4g", 5.0, -2, 5), 142: 143: ?line ["-5.00e-2", 144: "-0.500", 145: "-5.00", 146: "-50.0", 147: "-5.00e+2", 148: "-5.00e+3", 149: "-5.00e+4", 150: "-5.00e+5"] = float_g_1("~.3g", -5.0, -2, 5), 151: 152: ?line ["5.0e-2", 153: "0.50", 154: "5.0", 155: "5.0e+1", 156: "5.0e+2", 157: "5.0e+3", 158: "5.0e+4", 159: "5.0e+5"] = float_g_1("~.2g", 5.0, -2, 5), 160: 161: ?line 162: case catch fmt("~.1g", [0.5]) of 163: "0.5" -> 164: ?line 165: ["5.0e-2", 166: "0.5", 167: "5.0e+0", 168: "5.0e+1", 169: "5.0e+2", 170: "5.0e+3", 171: "5.0e+4", 172: "5.0e+5"] = float_g_1("~.1g", 5.0, -2, 5); 173: {'EXIT',_} -> ok 174: end, 175: 176: ?line ["4.99999e-2", 177: "0.499999", 178: "4.99999", 179: "49.9999", 180: "499.999", 181: "4999.99", 182: "4.99999e+4", 183: "4.99999e+5"] = float_g_1("~g", 4.9999949999, -2, 5), 184: 185: ?line ["-5.00000e-2", 186: "-0.500000", 187: "-5.00000", 188: "-50.0000", 189: "-500.000", 190: "-5000.00", 191: "-5.00000e+4", 192: "-5.00000e+5"] = float_g_1("~g", -4.9999950001, -2, 5), 193: ok. 194: 195: float_g_1(Fmt, V, Min, Max) -> 196: [fmt(Fmt, [V*math:pow(10, E)]) || E <- lists:seq(Min, Max)]. 197: 198: otp_5403(doc) -> 199: ["OTP-5403. ~s formats I/O lists and a single binary."]; 200: otp_5403(suite) -> 201: []; 202: otp_5403(Config) when is_list(Config) -> 203: ?line "atom" = fmt("~s", [atom]), 204: ?line "binary" = fmt("~s", [<<"binary">>]), 205: ?line "atail" = fmt("~s", [["a" | <<"tail">>]]), 206: ?line "deepcharlist" = fmt("~s", [["deep",["char",["list"]]]]), 207: ?line "somebinaries" = fmt("~s", [[<<"some">>,[<<"binaries">>]]]), 208: ok. 209: 210: otp_5813(doc) -> 211: ["OTP-5813. read/3 is new."]; 212: otp_5813(suite) -> 213: []; 214: otp_5813(Config) when is_list(Config) -> 215: ?line PrivDir = ?privdir(Config), 216: ?line File = filename:join(PrivDir, "test"), 217: 218: ?line ok = file:write_file(File, <<"a. ">>), 219: ?line {ok, Fd} = file:open(File, [read]), 220: ?line {ok, a, 1} = io:read(Fd, '', 1), 221: ?line {eof,1} = io:read(Fd, '', 1), 222: ok = file:close(Fd), 223: 224: ?line ok = file:write_file(File, <<"[}.">>), 225: ?line {ok, Fd2} = file:open(File, [read]), 226: ?line {error,{1,_,_},1} = io:read(Fd2, '', 1), 227: ?line ok = file:close(Fd), 228: 229: file:delete(File), 230: ok. 231: 232: otp_6230(doc) -> 233: ["OTP-6230. ~p and ~P with (huge) binaries."]; 234: otp_6230(suite) -> 235: []; 236: otp_6230(Config) when is_list(Config) -> 237: %% The problem is actually huge binaries, but the small tests here 238: %% just run through most of the modified code. 239: ?line "<<>>" = fmt("~P", [<<"">>,-1]), 240: ?line "<<\"hej\">>" = fmt("~P", [<<"hej">>,-1]), 241: ?line "{hej,...}" = fmt("~P", [{hej,<<"hej">>},2]), 242: ?line "{hej,<<...>>}" = fmt("~P", [{hej,<<"hej">>},3]), 243: ?line "{hej,<<\"hejs\"...>>}" = fmt("~P", [{hej,<<"hejsan">>},4]), 244: ?line "{hej,<<\"hej\">>}" = fmt("~P", [{hej,<<"hej">>},6]), 245: ?line "<<...>>" = fmt("~P", [<<"hej">>,1]), 246: ?line "<<\"hejs\"...>>" = fmt("~P", [<<"hejsan">>,2]), 247: ?line "<<\"hej\">>" = fmt("~P", [<<"hej">>,4]), 248: ?line "{hej,<<127,...>>}" = 249: fmt("~P", [{hej,<<127:8,<<"hej">>/binary>>},4]), 250: ?line "{hej,<<127,104,101,...>>}" = 251: fmt("~P", [{hej,<<127:8,<<"hej">>/binary>>},6]), 252: 253: B = list_to_binary(lists:duplicate(30000, $a)), 254: ?line "<<\"aaaa"++_ = fmt("~P", [B, 20000]), 255: ok. 256: 257: otp_6282(doc) -> 258: ["OTP-6282. ~p truncates strings (like binaries) depending on depth."]; 259: otp_6282(suite) -> 260: []; 261: otp_6282(Config) when is_list(Config) -> 262: ?line "[]" = p("", 1, 20, 1), 263: ?line "[]" = p("", 1, 20, -1), 264: ?line "[...]" = p("a", 1, 20, 1), 265: ?line "\"a\"" = p("a", 1, 20, 2), 266: ?line "\"aa\"" = p("aa", 1, 20, 2), 267: ?line "\"aaa\"" = p("aaa", 1, 20, 2), 268: ?line "\"aaaa\"" = p("aaaa", 1, 20, 2), 269: % ?line "\"aaaa\"..." = p("aaaaaa", 1, 20, 2), 270: ?line "\"a\"" = p("a", 1, 20, -1), 271: % ?line "\"aa\"..." = p([$a,$a,1000], 1, 20, 2), 272: % ?line "\"aa\"..." = p([$a,$a,1000], 1, 20, 3), 273: ?line "[97,97,1000]" = p([$a,$a,1000], 1, 20, 4), 274: S1 = lists:duplicate(200,$a), 275: ?line "[...]" = p(S1, 1, 20, 1), 276: % ?line "\"aaaaaaaaaaaaaaaa\"\n \"aaaaaaaaaaaaaaaa\"\n \"aaaa\"..." = 277: % ?line "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"..." = 278: % p(S1, 1, 20, 10), 279: ?line true = "\"" ++ S1 ++ "\"" =:= p(S1, 1, 205, -1), 280: ?line "[97,97,1000|...]" = p([$a,$a,1000,1000], 1, 20, 4), 281: 282: ?line "[[]]" = p([""], 1, 20, 2), 283: ?line "[[]]" = p([""], 1, 20, -1), 284: ?line "[[...]]" = p(["a"], 1, 20, 2), 285: ?line "[\"a\"]" = p(["a"], 1, 20, 3), 286: ?line "[\"aa\"]" = p(["aa"], 1, 20, 3), 287: ?line "[\"aaa\"]" = p(["aaa"], 1, 20, 3), 288: ?line "[\"a\"]" = p(["a"], 1, 20, -1), 289: % ?line "[\"aa\"...]" = p([[$a,$a,1000]], 1, 20, 3), 290: % ?line "[\"aa\"...]" = p([[$a,$a,1000]], 1, 20, 4), 291: ?line "[[97,97,1000]]" = p([[$a,$a,1000]], 1, 20, 5), 292: ?line "[[...]]" = p([S1], 1, 20, 2), 293: % ?line "[\"aaaaaaaaaaaaaa\"\n \"aaaaaaaaaaaaaa\"\n \"aaaaaaaa\"...]" = 294: % ?line "[\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"...]" = 295: % p([S1], 1, 20, 11), 296: ?line true = "[\"" ++ S1 ++ "\"]" =:= p([S1], 1, 210, -1), 297: ?line "[[97,97,1000|...]]" = p([[$a,$a,1000,1000]], 1, 20, 5), 298: 299: % ?line "[\"aaaa\"...]" = p(["aaaaa"], 1, 10, 3), 300: ?line "[\"aaaaa\"]" = p(["aaaaa"], 1, 10, 6), 301: 302: ok. 303: 304: otp_6354(doc) -> 305: ["OTP-6354. io_lib_pretty rewritten."]; 306: otp_6354(suite) -> 307: []; 308: otp_6354(Config) when is_list(Config) -> 309: %% A few tuples: 310: ?line "{}" = p({}, 1, 20, -1), 311: ?line "..." = p({}, 1, 20, 0), 312: ?line "{}" = p({}, 1, 20, 1), 313: ?line "{}" = p({}, 1, 20, 2), 314: ?line "{a}" = p({a}, 1, 20, -1), 315: ?line "..." = p({a}, 1, 20, 0), 316: ?line "{...}" = p({a}, 1, 20, 1), 317: ?line "{a}" = p({a}, 1, 20, 2), 318: ?line "{a,b}" = p({a,b}, 1, 20, -1), 319: ?line "..." = p({a,b}, 1, 20, 0), 320: ?line "{...}" = p({a,b}, 1, 20, 1), 321: ?line "{a,...}" = p({a,b}, 1, 20, 2), 322: ?line "{a,b}" = p({a,b}, 1, 20, 3), 323: ?line "{}" = p({}, 1, 1, -1), 324: ?line "..." = p({}, 1, 1, 0), 325: ?line "{}" = p({}, 1, 1, 1), 326: ?line "{}" = p({}, 1, 1, 2), 327: ?line "{a}" = p({a}, 1, 1, -1), 328: ?line "..." = p({a}, 1, 1, 0), 329: ?line "{...}" = p({a}, 1, 1, 1), 330: ?line "{a}" = p({a}, 1, 1, 2), 331: ?line "{a,\n b}" = p({a,b}, 1, 1, -1), 332: ?line "{1,\n b}" = p({1,b}, 1, 1, -1), 333: ?line "..." = p({a,b}, 1, 1, 0), 334: ?line "{...}" = p({a,b}, 1, 1, 1), 335: ?line "{a,...}" = p({a,b}, 1, 1, 2), 336: ?line "{a,\n b}" = p({a,b}, 1, 1, 3), 337: ?line "{{}}" = p({{}}, 1, 1, 2), 338: ?line "{[]}" = p({[]}, 1, 1, 2), 339: ?line bt(<<"{1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}">>, 340: p({1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}, -1)), 341: ?line bt(<<"{abcd,ddddd,\n ddddd}">>, 342: p({abcd,ddddd,ddddd}, 1,16, -1)), 343: ?line bt(<<"{1,2,a,b,\n {sfdsf,sdfdsfs},\n [sfsdf,sdfsdf]}">>, 344: p({1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}, 1, 35, 100)), 345: % With other terms than atomic ones on the same line: 346: % ?line bt(<<"{1,2,a,b,{sfdsf,sdfdsfs},\n [sfsdf,sdfsdf]}">>, 347: % p({1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}, 1, 35, 100)), 348: % With line breaks: 349: % ?line bt(<<"{1,\n" 350: % " 2,\n" 351: % " a,\n" 352: % " b,\n" 353: % " {sfdsf,sdfdsfs},\n" 354: % " [sfsdf,sdfsdf]}">>, 355: % p({1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]}, 1, 35, 100)), 356: ?line "{1,{1,{2,3}}}" = p({1,{1,{2,3}}}, 1, 80, 100), 357: 358: ?line bt(<<"{wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds,\n" 359: " sdkfjdsl,sdakfjdsklj,sdkljfsdj}}}}}">>, 360: p({wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds, 361: sdkfjdsl,sdakfjdsklj,sdkljfsdj}}}}}, -1)), 362: 363: % With no restriction on number of characters per line: 364: % ?line bt(<<"{wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds," 365: % "sdkfjdsl,sdakfjdsklj,\n" 366: % " sdkljfsdj}}}}}">>, 367: % p({wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds, 368: % sdkfjdsl,sdakfjdsklj,sdkljfsdj}}}}}, -1)), 369: 370: % With line breaks: 371: % ?line bt(<<"{wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,\n" 372: % " klsdjfjklds,\n" 373: % " sdkfjdsl,\n" 374: % " sdakfjdsklj,\n" 375: % " sdkljfsdj}}}}}">>, 376: % p({wwwww,{wwwww,{wwwww,{wwwww,{wwwww,lkjsldfj,klsdjfjklds, 377: % sdkfjdsl,sdakfjdsklj,sdkljfsdj}}}}}, -1)), 378: ?line bt(<<"{wwwww,\n" 379: " {wwwww,\n" 380: " {wwwww,\n" 381: " {wwwww,\n" 382: " {wwwww,\n" 383: " {lkjsldfj,\n" 384: " {klsdjfjklds,\n" 385: " {klajsljls,\n" 386: " #aaaaaaaaaaaaaaaaaaaaa" 387: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa{}}}}}}}}}">>, 388: p({wwwww,{wwwww,{wwwww,{wwwww,{wwwww,{lkjsldfj, 389: {klsdjfjklds,{klajsljls, 390: {aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}}}}}}}}}, 391: -1)), 392: ?line "{{...},...}" = p({{a,b},{a,b,c},{d,e,f}},1,8,2), 393: %% Closing brackets and parentheses count: 394: ?line "{{a,b,c},\n {{1,2,\n 3}}}" = p({{a,b,c},{{1,2,3}}},1,11,-1), 395: % With line breaks: 396: % ?line "{{a,b,c},\n {{1,\n 2,\n 3}}}" = p({{a,b,c},{{1,2,3}}},1,11,-1), 397: ?line "{{a,b,c},\n [1,2,\n 3]}" = p({{a,b,c},[1,2,3]},1,10,-1), 398: % With line breaks: 399: % ?line "{{a,b,c},\n [1,\n 2,\n 3]}" = p({{a,b,c},[1,2,3]},1,10,-1), 400: ?line "[{{a,b,c},\n {1,2,\n 3}}]" = p([{{a,b,c},{1,2,3}}],1,12,-1), 401: % With line breaks: 402: % ?line "[{{a,b,c},\n {1,\n 2,\n 3}}]" = p([{{a,b,c},{1,2,3}}],1,12,-1), 403: 404: %% A few lists: 405: ?line "[]" = p([], 1, 20, -1), 406: ?line "..." = p([], 1, 20, 0), 407: ?line "[]" = p([], 1, 20, 1), 408: ?line "[]" = p([], 1, 20, 2), 409: ?line "[a]" = p([a], 1, 20, -1), 410: ?line "..." = p([a], 1, 20, 0), 411: ?line "[...]" = p([a], 1, 20, 1), 412: ?line "[a]" = p([a], 1, 20, 2), 413: ?line "[a,b]" = p([a,b], 1, 20, -1), 414: ?line "..." = p([a,b], 1, 20, 0), 415: ?line "[...]" = p([a,b], 1, 20, 1), 416: ?line "[a|...]" = p([a,b], 1, 20, 2), 417: ?line "[a,b]" = p([a,b], 1, 20, 3), 418: ?line "[a|b]" = p([a|b], 1, 20, -1), 419: ?line "..." = p([a|b], 1, 20, 0), 420: ?line "[...]" = p([a|b], 1, 20, 1), 421: ?line "[a|...]" = p([a|b], 1, 20, 2), 422: ?line "[a|b]" = p([a|b], 1, 20, 3), 423: ?line "[]" = p([], 1, 1, -1), 424: ?line "..." = p([], 1, 1, 0), 425: ?line "[]" = p([], 1, 1, 1), 426: ?line "[]" = p([], 1, 1, 2), 427: ?line "[a]" = p([a], 1, 1, -1), 428: ?line "..." = p([a], 1, 1, 0), 429: ?line "[...]" = p([a], 1, 1, 1), 430: ?line "[a]" = p([a], 1, 1, 2), 431: ?line "[a,\n b]" = p([a,b], 1, 1, -1), 432: ?line "..." = p([a,b], 1, 1, 0), 433: ?line "[...]" = p([a,b], 1, 1, 1), 434: ?line "[a|...]" = p([a,b], 1, 1, 2), 435: ?line "[a,\n b]" = p([a,b], 1, 1, 3), 436: ?line "[a|\n b]" = p([a|b], 1, 1, -1), 437: ?line "..." = p([a|b], 1, 1, 0), 438: ?line "[...]" = p([a|b], 1, 1, 1), 439: ?line "[a|...]" = p([a|b], 1, 1, 2), 440: ?line "[a|\n b]" = p([a|b], 1, 1, 3), 441: ?line "[{}]" = p([{}], 1, 1, 2), 442: ?line "[[]]" = p([[]], 1, 1, 2), 443: ?line bt(<<"[1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]]">>, 444: p([1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]], -1)), 445: ?line bt(<<"[1,2,a,b,\n {sfdsf,sdfdsfs},\n [sfsdf,sdfsdf]]">>, 446: p([1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]], 1, 35, 100)), 447: % With other terms than atomic ones on the same line: 448: % ?line bt(<<"[1,2,a,b,{sfdsf,sdfdsfs},\n [sfsdf,sdfsdf]]">>, 449: % p([1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]], 1, 35, 100)), 450: % With line breaks: 451: % ?line bt(<<"[1,\n" 452: % " 2,\n" 453: % " a,\n" 454: % " b,\n" 455: % " {sfdsf,sdfdsfs},\n" 456: % " [sfsdf,sdfsdf]]">>, 457: % p([1,2,a,b,{sfdsf,sdfdsfs},[sfsdf,sdfsdf]], 1, 35, 100)), 458: %% Element #8 is not printable: 459: ?line "[49," ++ _ = p("1234567"++[3,4,5,6,7], 1, 100, 9), 460: % ?line "\"1234567\"..." = p("1234567"++[3,4,5,6,7], 1, 100, 8), 461: 462: %% A few records: 463: %% -record(a, {}). 464: %% -record(a, {}). 465: ?line "..." = p({a}, 0), 466: ?line "{...}" = p({a}, 1), 467: ?line "#a{}" = p({a}, 2), 468: ?line "#a{}" = p({a}, -1), 469: %% -record(b, {f}). 470: ?line "{...}" = p({b}, 1), 471: ?line "..." = p({b,c}, 0), 472: ?line "{...}" = p({b,c}, 1), 473: ?line "#b{...}" = p({b,c}, 2), 474: ?line "#b{f = c}" = p({b,c}, 3), 475: ?line "#b{f = c}" = p({b,c}, -1), 476: ?line "..." = p({b,{c,d}}, 0), 477: ?line "{...}" = p({b,{c,d}}, 1), 478: ?line "#b{...}" = p({b,{c,d}}, 2), 479: ?line "#b{f = {...}}" = p({b,{c,d}}, 3), 480: ?line "#b{f = {c,...}}" = p({b,{c,d}}, 4), 481: ?line "#b{f = {c,d}}" = p({b,{c,d}}, 5), 482: ?line "#b{f = {...}}" = p({b,{b,c}}, 3), 483: ?line "#b{f = #b{...}}" = p({b,{b,c}}, 4), 484: ?line "#b{f = #b{f = c}}" = p({b,{b,c}}, 5), 485: %% -record(c, {f1, f2}). 486: ?line "#c{f1 = d,f2 = e}" = p({c,d,e}, -1), 487: ?line "..." = p({c,d,e}, 0), 488: ?line "{...}" = p({c,d,e}, 1), 489: ?line "#c{...}" = p({c,d,e}, 2), 490: ?line "#c{f1 = d,...}" = p({c,d,e}, 3), 491: ?line "#c{f1 = d,f2 = e}" = p({c,d,e}, 4), 492: %% -record(d, {a..., b..., c.., d...}). 493: ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,\n" 494: " cccccccccccccccccccc = 3,dddddddddddddddddddd = 4,\n" 495: " eeeeeeeeeeeeeeeeeeee = 5}">>, 496: p({d,1,2,3,4,5}, -1)), 497: % With no restriction on number of characters per line: 498: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2," 499: % "cccccccccccccccccccc = 3,\n dddddddddddddddddddd = 4," 500: % "eeeeeeeeeeeeeeeeeeee = 5}">>, 501: % p({d,1,2,3,4,5}, -1)), 502: % With line breaks: 503: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n" 504: % " bbbbbbbbbbbbbbbbbbbb = 2,\n" 505: % " cccccccccccccccccccc = 3,\n" 506: % " dddddddddddddddddddd = 4,\n" 507: % " eeeeeeeeeeeeeeeeeeee = 5}">>, 508: % p({d,1,2,3,4,5}, -1)), 509: ?line "..." = p({d,1,2,3,4,5}, 0), 510: ?line "{...}" = p({d,1,2,3,4,5}, 1), 511: ?line "#d{...}" = p({d,1,2,3,4,5}, 2), 512: ?line "#d{aaaaaaaaaaaaaaaaaaaa = 1,...}" = p({d,1,2,3,4,5}, 3), 513: ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,...}">>, 514: p({d,1,2,3,4,5}, 4)), 515: ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,\n" 516: " cccccccccccccccccccc = 3,...}">>, 517: p({d,1,2,3,4,5}, 5)), % longer than 80 characters... 518: % With no restriction on number of characters per line: 519: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2," 520: % "cccccccccccccccccccc = 3,...}">>, 521: % p({d,1,2,3,4,5}, 5)), % longer than 80 characters... 522: % With line breaks: 523: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n" 524: % " bbbbbbbbbbbbbbbbbbbb = 2,\n" 525: % " cccccccccccccccccccc = 3,...}">>, 526: % p({d,1,2,3,4,5}, 5)), 527: ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,\n" 528: " cccccccccccccccccccc = 3,dddddddddddddddddddd = 4,...}">>, 529: p({d,1,2,3,4,5}, 6)), 530: % With no restriction on number of characters per line: 531: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2," 532: % "cccccccccccccccccccc = 3,\n dddddddddddddddddddd = 4,...}">>, 533: % p({d,1,2,3,4,5}, 6)), 534: % With line breaks: 535: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n" 536: % " bbbbbbbbbbbbbbbbbbbb = 2,\n" 537: % " cccccccccccccccccccc = 3,\n" 538: % " dddddddddddddddddddd = 4,...}">>, 539: % p({d,1,2,3,4,5}, 6)), 540: ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2,\n" 541: " cccccccccccccccccccc = 3,dddddddddddddddddddd = 4,\n" 542: " eeeeeeeeeeeeeeeeeeee = 5}">>, 543: p({d,1,2,3,4,5}, 7)), 544: % With no restriction on number of characters per line: 545: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,bbbbbbbbbbbbbbbbbbbb = 2," 546: % "cccccccccccccccccccc = 3,\n dddddddddddddddddddd = 4," 547: % "eeeeeeeeeeeeeeeeeeee = 5}">>, 548: % p({d,1,2,3,4,5}, 7)), 549: % With line breaks: 550: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n" 551: % " bbbbbbbbbbbbbbbbbbbb = 2,\n" 552: % " cccccccccccccccccccc = 3,\n" 553: % " dddddddddddddddddddd = 4,\n" 554: % " eeeeeeeeeeeeeeeeeeee = 5}">>, 555: % p({d,1,2,3,4,5}, 7)), 556: ?line bt(<<"#rrrrr{\n" 557: " f1 = 1,\n" 558: " f2 = #rrrrr{f1 = a,f2 = b,f3 = c},\n" 559: " f3 = \n" 560: " #rrrrr{\n" 561: " f1 = h,f2 = i,\n" 562: " f3 = \n" 563: " #rrrrr{\n" 564: " f1 = aa,\n" 565: " f2 = \n" 566: " #rrrrr{\n" 567: " f1 = #rrrrr{f1 = a,f2 = b,f3 = c},\n" 568: " f2 = 2,f3 = 3},\n" 569: " f3 = bb}}}">>, 570: p({rrrrr,1,{rrrrr,a,b,c},{rrrrr,h,i, 571: {rrrrr,aa,{rrrrr,{rrrrr,a,b,c}, 572: 2,3},bb}}}, 573: -1)), 574: % With other terms than atomic ones on the same line: 575: % ?line bt(<<"#rrrrr{\n" 576: % " f1 = 1,f2 = #rrrrr{f1 = a,f2 = b,f3 = c},\n" 577: % " f3 = \n" 578: % " #rrrrr{\n" 579: % " f1 = h,f2 = i,\n" 580: % " f3 = \n" 581: % " #rrrrr{\n" 582: % " f1 = aa,\n" 583: % " f2 = \n" 584: % " #rrrrr{\n" 585: % " f1 = #rrrrr{f1 = a,f2 = b," 586: % "f3 = c},f2 = 2,f3 = 3},\n" 587: % " f3 = bb}}}">>, 588: % p({rrrrr,1,{rrrrr,a,b,c},{rrrrr,h,i, 589: % {rrrrr,aa,{rrrrr,{rrrrr,a,b,c}, 590: % 2,3},bb}}}, 591: % -1)), 592: % With line breaks: 593: % ?line bt(<<"#rrrrr{\n" 594: % " f1 = 1,\n" 595: % " f2 = #rrrrr{f1 = a,f2 = b,f3 = c},\n" 596: % " f3 = \n" 597: % " #rrrrr{\n" 598: % " f1 = h,\n" 599: % " f2 = i,\n" 600: % " f3 = \n" 601: % " #rrrrr{\n" 602: % " f1 = aa,\n" 603: % " f2 = \n" 604: % " #rrrrr{\n" 605: % " f1 = #rrrrr{f1 = a,f2 = b," 606: % "f3 = c},\n" 607: % " f2 = 2,\n" 608: % " f3 = 3},\n" 609: % " f3 = bb}}}">>, 610: % p({rrrrr,1,{rrrrr,a,b,c},{rrrrr,h,i, 611: % {rrrrr,aa,{rrrrr,{rrrrr,a,b,c}, 612: % 2,3},bb}}}, 613: % -1)), 614: ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n" 615: " bbbbbbbbbbbbbbbbbbbb = \n" 616: " #d{aaaaaaaaaaaaaaaaaaaa = a,bbbbbbbbbbbbbbbbbbbb = b,\n" 617: " cccccccccccccccccccc = c,dddddddddddddddddddd = d,\n" 618: " eeeeeeeeeeeeeeeeeeee = e},\n" 619: " cccccccccccccccccccc = 3,\n" 620: " dddddddddddddddddddd = \n" 621: " #d{aaaaaaaaaaaaaaaaaaaa = h,bbbbbbbbbbbbbbbbbbbb = i,\n" 622: " cccccccccccccccccccc = \n" 623: " #d{aaaaaaaaaaaaaaaaaaaa = aa," 624: "bbbbbbbbbbbbbbbbbbbb = bb,\n" 625: " cccccccccccccccccccc = \n" 626: " #d{aaaaaaaaaaaaaaaaaaaa = 1," 627: "bbbbbbbbbbbbbbbbbbbb = 2,\n" 628: " cccccccccccccccccccc = 3," 629: "dddddddddddddddddddd = 4,\n" 630: " eeeeeeeeeeeeeeeeeeee = 5},\n" 631: " dddddddddddddddddddd = dd," 632: "eeeeeeeeeeeeeeeeeeee = ee},\n" 633: " dddddddddddddddddddd = k," 634: "eeeeeeeeeeeeeeeeeeee = l},\n" 635: " eeeeeeeeeeeeeeeeeeee = 5}">>, 636: p({d,1,{d,a,b,c,d,e},3,{d,h,i,{d,aa,bb,{d,1,2,3,4,5},dd,ee}, 637: k,l},5}, -1)), 638: % With line breaks: 639: % ?line bt(<<"#d{aaaaaaaaaaaaaaaaaaaa = 1,\n" 640: % " bbbbbbbbbbbbbbbbbbbb = \n" 641: % " #d{aaaaaaaaaaaaaaaaaaaa = a,\n" 642: % " bbbbbbbbbbbbbbbbbbbb = b,\n" 643: % " cccccccccccccccccccc = c,\n" 644: % " dddddddddddddddddddd = d,\n" 645: % " eeeeeeeeeeeeeeeeeeee = e},\n" 646: % " cccccccccccccccccccc = 3,\n" 647: % " dddddddddddddddddddd = \n" 648: % " #d{aaaaaaaaaaaaaaaaaaaa = h,\n" 649: % " bbbbbbbbbbbbbbbbbbbb = i,\n" 650: % " cccccccccccccccccccc = \n" 651: % " #d{aaaaaaaaaaaaaaaaaaaa = aa,\n" 652: % " bbbbbbbbbbbbbbbbbbbb = bb,\n" 653: % " cccccccccccccccccccc = \n" 654: % " #d{aaaaaaaaaaaaaaaaaaaa = 1,\n" 655: % " bbbbbbbbbbbbbbbbbbbb = 2,\n" 656: % " cccccccccccccccccccc = 3,\n" 657: % " dddddddddddddddddddd = 4,\n" 658: % " eeeeeeeeeeeeeeeeeeee = 5},\n" 659: % " dddddddddddddddddddd = dd,\n" 660: % " eeeeeeeeeeeeeeeeeeee = ee},\n" 661: % " dddddddddddddddddddd = k,\n" 662: % " eeeeeeeeeeeeeeeeeeee = l},\n" 663: % " eeeeeeeeeeeeeeeeeeee = 5}">>, 664: % p({d,1,{d,a,b,c,d,e},3,{d,h,i,{d,aa,bb,{d,1,2,3,4,5},dd,ee}, 665: % k,l},5}, -1)), 666: 667: A = aaaaaaaaaaaaa, 668: %% Print the record with dots at the end of the line (Ll = 80). 669: ?line "{aaaaaaa" ++ _ = 670: p({A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A, 671: {A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A, 672: {A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A, 673: {A,{A,{ggg,{hhh,{ii,{jj,{kk,{ll,{mm,{nn,{oo,{d,1,2,3,4,5} 674: }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} 675: }}}}}}}}}}}}}}}}, 146), 676: ?line "{aaaaaaa" ++ _ = 677: p({A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A, 678: {A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A, 679: {A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{A, 680: {A,{A,{A,{A,{A,{ggg,{hhh,{ii,{jj,{kk,{ll,{mm,{nn,{oo,{a} 681: }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} 682: }}}}}}}}}}}}}}}}}}}, 152), 683: 684: ?line bt(<<"{aaaaaaaaaaaaa,\n" 685: " {aaaaaaaaaaaaa,\n" 686: " {aaaaaaaaaaaaa,\n" 687: " {aaaaaaaaaaaaa,\n" 688: " {aaaaaaaaaaaaa,\n" 689: " {aaaaaaaaaaaaa,\n" 690: " {g,{h,{i,{j,{k,{l,{m,{n,{o,#" 691: "d{...}}}}}}}}}}}}}}}}">>, 692: p({A,{A,{A,{A,{A,{A, 693: {g,{h,{i,{j,{k,{l,{m,{n,{o,{d,1,2,3,4,5}}}}}}}}}}}}}}}}, 32)), 694: ?line bt(<<"{a,#b{f = {c,{d,{e,{f,...}}}}}}">>, 695: p({a,{b,{c,{d,{e,{f,g}}}}}}, 12)), 696: ?line bt(<<"{aaaaaaaaaaaaa,\n" 697: " {aaaaaaaaaaaaa,\n" 698: " {aaaaaaaaaaaaa,\n" 699: " {aaaaaaaaaaaaa,\n" 700: " {aaaaaaaaaaaaa,\n" 701: " {aaaaaaaaaaaaa,\n" 702: " {aaaaaaaaaaaaa,\n" 703: " {aaaaaaaaaaaaa,\n" 704: " {aaaaaaaaaaaaa,#c{f1 = ddd," 705: "f2 = eee}}}}}}}}}}">>, 706: p({A,{A,{A,{A,{A,{A,{A,{A,{A,{c,ddd,eee}}}}}}}}}}, 100)), 707: ?line bt(<<"{aaaaaaaaaaaaa,\n" 708: " {aaaaaaaaaaaaa,{aaaaaaaaaaaaa,{aaaaaaaaaaaaa,...}}}}">>, 709: p({A,{A,{A,{A,{b}}}}}, 8)), 710: % With no restriction on number of characters per line: 711: % ?line bt(<<"{aaaaaaaaaaaaa,{aaaaaaaaaaaaa,{aaaaaaaaaaaaa," 712: % "{aaaaaaaaaaaaa,...}}}}">>, 713: % p({A,{A,{A,{A,{b}}}}}, 8)), 714: ?line bt(<<"{aaaaaaaaaaaaa,\n" 715: " {aaaaaaaaaaaaa,\n" 716: " {aaaaaaaaaaaaa,{aaaaaaaaaaaaa,{aaaaaaaaaaaaa,...}}}}}">>, 717: p({A,{A,{A,{A,{A,{b}}}}}}, 10)), 718: % With no restriction on number of characters per line: 719: % ?line bt(<<"{aaaaaaaaaaaaa,\n" 720: % " {aaaaaaaaaaaaa,{aaaaaaaaaaaaa,{aaaaaaaaaaaaa," 721: % "{aaaaaaaaaaaaa,...}}}}}">>, 722: % p({A,{A,{A,{A,{A,{b}}}}}}, 10)), 723: ?line bt(<<"{aaaaaaaaaaaaa,\n" 724: " {aaaaaaaaaaaaa,\n" 725: " {aaaaaaaaaaaaa,\n" 726: " {aaaaaaaaaaaaa,\n" 727: " {aaaaaaaaaaaaa,\n" 728: " {aaaaaaaaaaaaa,\n" 729: " {aaaaaaaaaaaaa,\n" 730: " {aaaaaaaaaaaaa,\n" 731: " {aaaaaaaaaaaaa," 732: "{aaaaaaaaaaaaa,#a{}}}}}}}}}}}">>, 733: p({A,{A,{A,{A,{A,{A,{A,{A,{A,{A,{a}}}}}}}}}}}, 23)), 734: ?line bt(<<"{aaaaaaaaaaaaa,\n" 735: " {aaaaaaaaaaaaa,\n" 736: " {aaaaaaaaaaaaa,\n", 737: " #rrrrr{\n" 738: " f1 = kljlkjlksfdgkljlsdkjf," 739: "f2 = kljkljsdaflkjlkjsdf,...}}}}">>, 740: p({A,{A,{A,{rrrrr, kljlkjlksfdgkljlsdkjf, 741: kljkljsdaflkjlkjsdf, 742: asdfkldsjfklkljsdklfds}}}}, 10)), 743: % With no restriction on number of characters per line: 744: % ?line bt(<<"{aaaaaaaaaaaaa,\n" 745: % " {aaaaaaaaaaaaa,\n" 746: % " {aaaaaaaaaaaaa,\n", 747: % " #rrrrr{f1 = kljlkjlksfdgkljlsdkjf,f2 = " 748: % "kljkljsdaflkjlkjsdf,...}}}}">>, 749: % p({A,{A,{A,{rrrrr, kljlkjlksfdgkljlsdkjf, 750: % kljkljsdaflkjlkjsdf, 751: % asdfkldsjfklkljsdklfds}}}}, 10)), 752: ?line bt(<<"{aaaaaaaaaaaaa,\n" 753: " {aaaaaaaaaaaaa,\n" 754: " {aaaaaaaaaaaaa,\n" 755: " {aaaaaaaaaaaaa,\n" 756: " {aaaaaaaaaaaaa,\n" 757: " {aaaaaaaaaaaaa,\n" 758: " {aaaaaaaaaaaaa,\n" 759: " {g,{h,{i,{j,{k,{l,{m,{n," 760: "{o,#a{}}}}}}}}}}}}}}}}}">>, 761: p({A,{A,{A,{A,{A,{A,{A, 762: {g,{h,{i,{j,{k,{l,{m,{n,{o,{a}}}}}}}}}}}}}}}}}, 100)), 763: ?line bt(<<"#c{\n" 764: " f1 = \n" 765: " #c{\n" 766: " f1 = \n" 767: " #c{\n" 768: " f1 = \n" 769: " #c{\n" 770: " f1 = \n" 771: " #c{\n" 772: " f1 = \n" 773: " #c{\n" 774: " f1 = \n" 775: " #c{\n" 776: " f1 = \n" 777: " #c{\n" 778: " f1 = \n" 779: " #c{\n" 780: " f1 = #c{f1 = #c{f1 = #c{f1 = a," 781: "f2 = b},f2 = b},f2 = b},\n" 782: " f2 = b},\n" 783: " f2 = b},\n" 784: " f2 = b},\n" 785: " f2 = b},\n" 786: " f2 = b},\n" 787: " f2 = b},\n" 788: " f2 = b},\n" 789: " f2 = b},\n" 790: " f2 = b}">>, 791: p({c,{c,{c,{c,{c,{c,{c,{c,{c,{c,{c,{c,a,b},b},b},b},b},b}, 792: b},b},b},b},b},b}, -1)), 793: ?line bt(<<"#rrrrr{\n" 794: " f1 = \n" 795: " #rrrrr{\n" 796: " f1 = \n" 797: " #rrrrr{\n" 798: " f1 = \n" 799: " #rrrrr{\n" 800: " f1 = \n" 801: " {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a," 802: "f3 = b}},b},\n" 803: " f2 = {rrrrr,c,d},\n" 804: " f3 = {rrrrr,1,2}},\n" 805: " f2 = 1,f3 = 2},\n" 806: " f2 = 3,f3 = 4},\n" 807: " f2 = 5,f3 = 6}">>, 808: p({rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,a,{rrrrr, 809: {rrrrr,1,2},a,b}},b},{rrrrr,c,d},{rrrrr,1,2}}, 810: 1,2},3,4},5,6}, -1)), 811: % With other terms than atomic ones on the same line: 812: % ?line bt(<<"#rrrrr{\n" 813: % " f1 = \n" 814: % " #rrrrr{\n" 815: % " f1 = \n" 816: % " #rrrrr{\n" 817: % " f1 = \n" 818: % " #rrrrr{\n" 819: % " f1 = \n" 820: % " {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a," 821: % "f3 = b}},b},\n" 822: % " f2 = {rrrrr,c,d},f3 = {rrrrr,1,2}},\n" 823: % " f2 = 1,f3 = 2},\n" 824: % " f2 = 3,f3 = 4},\n" 825: % " f2 = 5,f3 = 6}">>, 826: % p({rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,a,{rrrrr, 827: % {rrrrr,1,2},a,b}},b},{rrrrr,c,d},{rrrrr,1,2}}, 828: % 1,2},3,4},5,6}, -1)), 829: % With no restriction on number of characters per line: 830: % ?line bt(<<"#rrrrr{\n" 831: % " f1 = \n" 832: % " #rrrrr{\n" 833: % " f1 = \n" 834: % " #rrrrr{\n" 835: % " f1 = \n" 836: % " #rrrrr{\n" 837: % " f1 = {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a," 838: % "f3 = b}},b},\n" 839: % " f2 = {rrrrr,c,d},f3 = {rrrrr,1,2}},\n" 840: % " f2 = 1,f3 = 2},\n" 841: % " f2 = 3,f3 = 4},\n" 842: % " f2 = 5,f3 = 6}">>, 843: % p({rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,a,{rrrrr, 844: % {rrrrr,1,2},a,b}},b},{rrrrr,c,d},{rrrrr,1,2}}, 845: % 1,2},3,4},5,6}, -1)), 846: % With line breaks: 847: % ?line bt(<<"#rrrrr{\n" 848: % " f1 = \n" 849: % " #rrrrr{\n" 850: % " f1 = \n" 851: % " #rrrrr{\n" 852: % " f1 = \n" 853: % " #rrrrr{\n" 854: % " f1 = {rrrrr,{rrrrr,a,#rrrrr{f1 = {rrrrr,1,2},f2 = a," 855: % "f3 = b}},b},\n" 856: % " f2 = {rrrrr,c,d},\n" 857: % " f3 = {rrrrr,1,2}},\n" 858: % " f2 = 1,\n" 859: % " f3 = 2},\n" 860: % " f2 = 3,\n" 861: % " f3 = 4},\n" 862: % " f2 = 5,\n" 863: % " f3 = 6}">>, 864: % p({rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,{rrrrr,a,{rrrrr, 865: % {rrrrr,1,2},a,b}},b},{rrrrr,c,d},{rrrrr,1,2}}, 866: % 1,2},3,4},5,6}, -1)), 867: ?line "{aaa,\n {aaa," ++ _ = 868: p({aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa, 869: {aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa, 870: {aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa, 871: {aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa,{aaa, 872: {aaa,a}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}, 873: 1, 80, -1), 874: 875: %% A few other cases... 876: ?line "{a,#Fun<" ++ _ = lists:flatten(io_lib_pretty:print({a,fun fmt/2})), 877: ?line "#Fun<" ++ _ = io_lib_pretty:print(fun() -> foo end), 878: % ?line "[<<\"foobar\">>|<<\"barf\"...>>]" = 879: % p([<<"foobar">>|<<"barfoo">>], 1, 30, 4), 880: %% No support for negative columns any more: 881: ?line "[a,\n [b,\n c,\n d,\n [e,\n f]],\n c]" = 882: p([a,[b,c,d,[e,f]],c], -1, 2, 10), 883: ?line "[a,\n [b,\n c,\n d,\n [e,\n f]],\n c]" = 884: p([a,[b,c,d,[e,f]],c], 0, 2, 10), 885: %% 20 bytes are tried first, then the rest. Try 21 bytes: 886: L = lists:duplicate(20, $a), 887: % ?line bt(<<"<<\"aaaaaa\"\n \"aaaaaa\"\n \"aaaaaa\"\n \"aaa\">>">>, 888: ?line bt(<<"<<\"aaaaaaaaaaaaaaaaaaaaa\">>">>, 889: p(list_to_binary([$a | L]), 1, 10, -1)), 890: ?line "<<97," ++ _ = p(list_to_binary(L ++ [3]), 1, 10, -1), 891: % ?line "<<\"aaaa\"...>>" = p(list_to_binary(L ++ [3]), 1, 10, 2), 892: % ?line "<<\"aaaaaa\"\n \"aa\"...>>" = 893: % ?line "<<\"aaaaaaaa\"...>>" = 894: % p(list_to_binary(L ++ [3]), 1, 10, 3), 895: % ?line "<<\"aaaaaa\"\n \"aaaaaa\"\n \"aaaaaa\"\n \"aa\"...>>" = 896: % ?line "<<\"aaaaaaaaaaaaaaaaaaaa\"...>>" = 897: % p(list_to_binary(L ++ [3]), 1, 10, 21), 898: ?line "<<97," ++ _ = p(list_to_binary(L ++ [3]), 1, 10, 22), 899: 900: ?line "\"\\b\\t\\n\\v\\f\\r\\e\250\"" = 901: p([8,9,10,11,12,13,27,168], 1, 40, -1), 902: % ?line "\"\\b\\t\\n\"\n \"\\v\\f\\r\"\n \"\\e\250\"" = 903: ?line "\"\\b\\t\\n\\v\\f\\r\\e¨\"" = 904: p([8,9,10,11,12,13,27,168], 1, 10, -1), 905: ?line "\"\\b\\t\\n\\v\\f\\r\\e\250\"" = 906: p([8,9,10,11,12,13,27,168], 1, 40, 100), 907: % ?line "\"\\e\\t\\nab\"\n \"cd\"" = 908: ?line "\"\\e\\t\\nabcd\"" = 909: p("\e\t\nabcd", 1, 12, -1), 910: 911: %% DEL (127) is special... 912: ?line "[127]" = p("\d", 1, 10, -1), 913: ?line "[127]" = p([127], 1, 10, 100), 914: 915: ?line "<<\"\\b\\t\\n\\v\\f\\r\\e\250\">>" = 916: p(<<8,9,10,11,12,13,27,168>>, 1, 40, -1), 917: ?line "<<\"\\b\\t\\n\\v\\f\\r\\e\250\">>" = 918: p(<<8,9,10,11,12,13,27,168>>, 1, 10, -1), 919: ?line "<<127>>" = p(<<127>>, 1, 10, 100), 920: 921: %% "Partial" string binaries: 922: ?line "<<\"he\"...>>" = p(list_to_binary("he"++[3]), 1, 80, 2), 923: ?line "<<\"he\"...>>" = p(list_to_binary("he"++[3]), 1, 80, 3), 924: ?line "<<104,101,3>>" = p(list_to_binary("he"++[3]), 1, 80, 4), 925: ?line "<<...>>" = p(list_to_binary([3] ++ "he"), 1, 80, 1), 926: ?line "<<3,...>>" = p(list_to_binary([3] ++ "he"), 1, 80, 2), 927: ?line "<<3,104,...>>" = p(list_to_binary([3] ++ "he"), 1, 80, 3), 928: 929: ?line "<<\"12345678901234567890\"...>>" = 930: p(list_to_binary("12345678901234567890"++[3]), 1, 80, 8), 931: ?line "<<\"12345678901234567890\"...>>" = 932: p(list_to_binary("12345678901234567890"++[3]), 1, 80, 21), 933: ?line "<<49," ++ _ = 934: p(list_to_binary("12345678901234567890"++[3]), 1, 80, 22), 935: 936: ?line "{sdfsdfj,\n 23" ++ _ = 937: p({sdfsdfj,23423423342.23432423}, 1, 17, -1), 938: 939: ?line bt(<<"kljkljlksdjjlf kljalkjlsdajafasjdfj [kjljklasdf,kjlljsfd,sdfsdkjfsd,kjjsdf,jl, 940: lkjjlajsfd|jsdf]">>, 941: fmt("~w ~w ~p", 942: [kljkljlksdjjlf, 943: kljalkjlsdajafasjdfj, 944: [kjljklasdf,kjlljsfd,sdfsdkjfsd,kjjsdf,jl,lkjjlajsfd | 945: jsdf]])), 946: 947: %% Binaries are split as well: 948: ?line bt(<<"<<80,100,0,55,55,55,55,55,55,55,55,55,\n " 949: "55,55,55,55,55,55,55,...>>">>, 950: p(<<80,100,0,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, 951: 55,55,55,55,55,55,55,55,55,55,55,55>>,1,40,20)), 952: ?line bt(<<"<<80,100,0,55,55,55,55,55,55,55,55,55,\n " 953: "55,55,55,55,55,55,55,55,55,55,55,55,\n 55,55,55,55,55,55>>">>, 954: p(<<80,100,0,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, 955: 55,55,55,55,55,55,55,55,55,55,55,55>>,1,40,-1)), 956: ?line "<<0,0,0,\n ...>>" = p(<<0,0,0,0,0>>, 1, 10, 4), 957: 958: %% ~W now uses ",..." when printing tuples 959: ?line "[a,b|...]" = fmt("~W", [[a,b,c,d,e], 3]), 960: ?line "{a,b,...}" = fmt("~W", [{a,b,c,d,e}, 3]), 961: ok. 962: 963: otp_6495(doc) -> 964: ["OTP-6495. io_lib_pretty bugfix."]; 965: otp_6495(suite) -> 966: []; 967: otp_6495(Config) when is_list(Config) -> 968: ?line bt(<<"[120,120,120,120,120,120,120,120,120,120,120,120,120,120," 969: "120,120,120,120,120]<<1>>">>, 970: fmt("~w~p", ["xxxxxxxxxxxxxxxxxxx", <<1>>])), 971: ok. 972: 973: otp_6517(doc) -> 974: ["OTP-6517. The Format argument of fwrite can be a binary."]; 975: otp_6517(suite) -> 976: []; 977: otp_6517(Config) when is_list(Config) -> 978: ?line "string" = fmt(<<"~s">>, [<<"string">>]), 979: ok. 980: 981: otp_6502(doc) -> 982: ["OTP-6502. Bits."]; 983: otp_6502(suite) -> 984: []; 985: otp_6502(Config) when is_list(Config) -> 986: ?line bt(<< 987: "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]" 988: "<<0,0,8,\n" 989: " " 990: " 1:1>>">>, 991: fmt("~w~p", [lists:seq(0, 25), <<17:25>>])), 992: ok. 993: 994: otp_7421(doc) -> 995: ["OTP-7421. Soft limit of 60 chars removed when pretty printing."]; 996: otp_7421(suite) -> 997: []; 998: otp_7421(Config) when is_list(Config) -> 999: bt(<<"{aa,bb,\n" 1000: " c,dd,\n" 1001: " eee,\n" 1002: " fff}">>, 1003: rp({aa,bb,c,dd,eee,fff}, 1, 80, -1, 5, none)), 1004: bt(<<"{aa,bb,\n" 1005: " c,\n" 1006: " dd,\n" 1007: " eee,\n" 1008: " fff}">>, 1009: rp({aa,bb,c,dd,eee,fff}, 1, 80, -1, 4, none)), 1010: ok. 1011: 1012: bt(Bin, R) -> 1013: R = binary_to_list(Bin). 1014: 1015: p(Term, D) -> 1016: rp(Term, 1, 80, D). 1017: 1018: p(Term, Col, Ll, D) -> 1019: rp(Term, Col, Ll, D, no_fun). 1020: 1021: rp(Term, Col, Ll, D) -> 1022: rp(Term, Col, Ll, D, fun rfd/2). 1023: 1024: -define(MAXCS, 60). 1025: 1026: rp(Term, Col, Ll, D, RF) -> 1027: rp(Term, Col, Ll, D, ?MAXCS, RF). 1028: 1029: rp(Term, Col, Ll, D, M, RF) -> 1030: %% io:format("~n~n*** Col = ~p Ll = ~p D = ~p~n~p~n-->~n", 1031: %% [Col, Ll, D, Term]), 1032: R = io_lib_pretty:print(Term, Col, Ll, D, M, RF), 1033: %% io:format("~s~n<--~n", [R]), 1034: lists:flatten(io_lib:format("~s", [R])). 1035: 1036: fmt(Fmt, Args) -> 1037: lists:flatten(io_lib:format(Fmt, Args)). 1038: 1039: rfd(a, 0) -> 1040: []; 1041: rfd(b, 1) -> 1042: [f]; 1043: rfd(c, 2) -> 1044: [f1, f2]; 1045: rfd(e, 3) -> 1046: [f, g, h]; 1047: rfd(d, 5) -> 1048: [aaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbb, 1049: cccccccccccccccccccc, dddddddddddddddddddd, 1050: eeeeeeeeeeeeeeeeeeee]; 1051: rfd(rrrrr, 3) -> 1052: [f1, f2, f3]; 1053: rfd(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 0) -> 1054: []; 1055: rfd(_, _) -> 1056: no. 1057: 1058: manpage(doc) -> 1059: ["The examples in io(3) and io_lib(3)."]; 1060: manpage(suite) -> 1061: []; 1062: manpage(Config) when is_list(Config) -> 1063: %% The examples that write or print only, not the ones that read... 1064: 1065: ?line bt(<<"Hello world!\n">>, 1066: fmt("Hello world!~n", [])), 1067: ?line bt(<<"| aaaaa|bbbbb |ccccc|\n">>, % bugfix 1068: fmt("|~10.5c|~-10.5c|~5c|~n", [$a, $b, $c])), 1069: ?line bt(<<"|**********|\n">>, 1070: fmt("|~10w|~n", [{hey, hey, hey}])), 1071: ?line bt(<<"|{hey,hey,h|\n">>, 1072: fmt("|~10s|~n", [io_lib:write({hey, hey, hey})])), 1073: 1074: T = [{attributes,[[{id,age,1.50000},{mode,explicit}, 1075: {typename,"INTEGER"}], [{id,cho},{mode,explicit},{typename,'Cho'}]]}, 1076: {typename,'Person'},{tag,{'PRIVATE',3}},{mode,implicit}], 1077: ?line bt(<<"[{attributes,[[{id,age,1.5},{mode,explicit},{typename," 1078: "[73,78,84,69,71,69,82]}],[{id,cho},{mode,explicit}," 1079: "{typename,'Cho'}]]},{typename,'Person'},{tag,{'PRIVATE',3}}," 1080: "{mode,implicit}]\n">>, 1081: fmt("~w~n", [T])), 1082: ?line bt(<<"[{attributes,[[{id,age,1.5},\n" 1083: " {mode,explicit},\n" 1084: " {typename,\"INTEGER\"}],\n" 1085: " [{id,cho},{mode,explicit},{typename,'Cho'}]]},\n" 1086: " {typename,'Person'},\n" 1087: " {tag,{'PRIVATE',3}},\n" 1088: " {mode,implicit}]\n">>, 1089: fmt("~62p~n", [T])), 1090: ?line bt(<<"Here T = [{attributes,[[{id,age,1.5},\n" 1091: " {mode,explicit},\n" 1092: " {typename,\"INTEGER\"}],\n" 1093: " [{id,cho},\n" 1094: " {mode,explicit},\n" 1095: " {typename,'Cho'}]]},\n" 1096: " {typename,'Person'},\n" 1097: " {tag,{'PRIVATE',3}},\n" 1098: " {mode,implicit}]\n">>, 1099: fmt("Here T = ~62p~n", [T])), 1100: ?line bt(<<"[{attributes,[[{id,age,1.5},{mode,explicit}," 1101: "{typename,...}],[{id,cho},{mode,...},{...}]]}," 1102: "{typename,'Person'},{tag,{'PRIVATE',3}},{mode,implicit}]\n">>, 1103: fmt("~W~n", [T,9])), 1104: ?line bt(<<"[{attributes,[[{id,age,1.5},{mode,explicit},{typename,...}]," 1105: "\n " 1106: "[{id,cho},{mode,...},{...}]]},\n {typename,'Person'},\n " 1107: "{tag,{'PRIVATE',3}},\n {mode,implicit}]\n">>, 1108: fmt("~62P~n", [T,9])), 1109: 1110: ?line "1F\n" = fmt("~.16B~n", [31]), 1111: ?line "-10011\n" = fmt("~.2B~n", [-19]), 1112: ?line "5Z\n" = fmt("~.36B~n", [5*36+35]), 1113: ?line "10#31\n" = fmt("~X~n", [31,"10#"]), 1114: ?line "-0x1F\n" = fmt("~.16X~n", [-31,"0x"]), 1115: ?line "10#31\n" = fmt("~.10#~n", [31]), 1116: ?line "-16#1F\n" = fmt("~.16#~n", [-31]), 1117: ?line "abc def 'abc def' {foo,1} A \n" = 1118: fmt("~s ~w ~i ~w ~c ~n", 1119: ['abc def', 'abc def', {foo, 1},{foo, 1}, 65]), 1120: % fmt("~s", [65]), 1121: 1122: %% io_lib(3) 1123: ?line bt(<<"{1,[2],[3],[...],...}">>, 1124: lists:flatten(io_lib:write({1,[2],[3],[4,5],6,7,8,9}, 5))), 1125: ok. 1126: 1127: otp_6708(doc) -> 1128: ["OTP-6708. Fewer newlines when pretty-printing."]; 1129: otp_6708(suite) -> 1130: []; 1131: otp_6708(Config) when is_list(Config) -> 1132: ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,\n" 1133: " 23,24,25,26,27,28,29|...]">>, 1134: p(lists:seq(1,1000), 30)), 1135: ?line bt(<<"{lkjasklfjsdak,mlkasjdflksj,klasdjfklasd,jklasdfjkl,\n" 1136: " jklsdjfklsd,masdfjkkl}">>, 1137: p({lkjasklfjsdak,mlkasjdflksj,klasdjfklasd,jklasdfjkl, 1138: jklsdjfklsd, masdfjkkl}, -1)), 1139: ?line bt(<<"#b{f = {lkjljalksdf,jklaskfjd,kljasdlf,kljasdf,kljsdlkf,\n" 1140: " kjdd}}">>, 1141: p({b, {lkjljalksdf,jklaskfjd,kljasdlf,kljasdf,kljsdlkf,kjdd}}, 1142: -1)), 1143: ?line bt(<<"#b{f = {lkjljalksdf,jklaskfjd,kljasdlf,kljasdf,kljsdlkf,\n" 1144: " kdd}}">>, 1145: p({b, {lkjljalksdf,jklaskfjd,kljasdlf,kljasdf,kljsdlkf,kdd}}, 1146: -1)), 1147: ?line bt(<<"#e{f = undefined,g = undefined,\n" 1148: " h = #e{f = 11,g = 22,h = 333}}">>, 1149: p({e,undefined,undefined,{e,11,22,333}}, -1)), 1150: ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21|\n" 1151: " apa11]">>, 1152: p(lists:seq(1,21) ++ apa11, -1)), 1153: ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,\n" 1154: " 23,\n" 1155: " {{abadalkjlasdjflksdajfksdklfsdjlkfdlskjflsdj" 1156: "flsdjfldsdsdddd}}]">>, 1157: p(lists:seq(1,23) ++ 1158: [{{abadalkjlasdjflksdajfksdklfsdjlkfdlskjflsdjflsdjfldsdsdddd}}], 1159: -1)), 1160: ?line bt(<<"{lkjasdf,\n" 1161: " {kjkjsd,\n" 1162: " {kjsd,\n" 1163: " {kljsdf,\n" 1164: " {kjlsd,{dkjsdf,{kjlds,{kljsd,{kljs," 1165: "{kljlkjsd}}}}}}}}}}">>, 1166: p({lkjasdf,{kjkjsd,{kjsd, 1167: {kljsdf, 1168: {kjlsd, 1169: {dkjsdf,{kjlds, 1170: {kljsd,{kljs,{kljlkjsd}}}}}}}}}}, 1171: -1)), 1172: ?line bt(<<"{lkjasdf,\n" 1173: " {kjkjsd,\n" 1174: " {kjsd,{kljsdf,{kjlsd,{dkjsdf,{kjlds," 1175: "{kljsd,{kljs}}}}}}}}}">>, 1176: p({lkjasdf,{kjkjsd,{kjsd, 1177: {kljsdf,{kjlsd,{dkjsdf, 1178: {kjlds,{kljsd,{kljs}}}}}}}}}, 1179: -1)), 1180: ?line bt(<<"<<1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,\n" 1181: " 22,23>>">>, 1182: p(list_to_binary(lists:seq(1,23)), -1)), 1183: ?line bt(<<"<<100,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,\n" 1184: " 27>>">>, 1185: p(list_to_binary([100|lists:seq(10,27)]), -1)), 1186: ?line bt(<<"<<100,101,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,\n" 1187: " 26>>">>, 1188: p(list_to_binary([100,101|lists:seq(10,26)]), -1)), 1189: ?line bt(<<"{{<<100,101,102,10,11,12,13,14,15,16,17,18,19,20,21,22,\n" 1190: " 23>>}}">>, 1191: p({{list_to_binary([100,101,102|lists:seq(10,23)])}}, -1)), 1192: ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22|\n" 1193: " ap]">>, 1194: p(lists:seq(1,22) ++ ap, -1)), 1195: ?line bt(<<"[1,2,3,4,5,6,7,8,9,10,{},[],\n <<>>,11,12,13,14,15]">>, 1196: p(lists:seq(1,10) ++ [{},[],<<>>] ++ lists:seq(11,15),1,30,-1)), 1197: ?line bt(<<"[ddd,ddd,\n" 1198: " {1},\n" 1199: " [1,2],\n" 1200: " ddd,kdfd,\n" 1201: " [[1,2],a,b,c],\n" 1202: " <<\"foo\">>,<<\"bar\">>,1,\n" 1203: " {2}]">>, 1204: p([ddd,ddd,{1},[1,2],ddd,kdfd,[[1,2],a,b,c],<<"foo">>,<<"bar">>, 1205: 1,{2}],1,50,-1)), 1206: 1207: ?line bt(<<"{dskljsadfkjsdlkjflksdjflksdjfklsdjklfjsdklfjlsdjfkl,jksd,\n" 1208: " " 1209: "lkjsdf,kljsdf,kljsf,kljsdf,kljsdf,jkldf,jklsdf,kljsdf,\n" 1210: " " 1211: "kljsdf,jklsdf,lkjfd,lkjsdf,kljsdf,kljsdf,lkjsdf,kljsdf,\n" 1212: " " 1213: "lkjsdfsd,kljsdf,kjsfj}">>, 1214: p({dskljsadfkjsdlkjflksdjflksdjfklsdjklfjsdklfjlsdjfkl,jksd, 1215: lkjsdf,kljsdf,kljsf,kljsdf,kljsdf,jkldf,jklsdf,kljsdf, 1216: kljsdf,jklsdf,lkjfd,lkjsdf,kljsdf,kljsdf,lkjsdf,kljsdf, 1217: lkjsdfsd,kljsdf,kjsfj}, 1, 110, -1)), 1218: ?line bt(<<"{dskljsadfkjsdlkjflksdjflksdjfklsdjklfjsdklfjlsdjfkl," 1219: "#d{aaaaaaaaaaaaaaaaaaaa = 1,\n" 1220: " " 1221: "bbbbbbbbbbbbbbbbbbbb = 2,cccccccccccccccccccc = 3,\n" 1222: " " 1223: "dddddddddddddddddddd = 4,eeeeeeeeeeeeeeeeeeee = 5}}">>, 1224: rp({dskljsadfkjsdlkjflksdjflksdjfklsdjklfjsdklfjlsdjfkl, 1225: {d,1,2,3,4,5}},1,200,-1)), 1226: ok. 1227: 1228: -define(ONE(N), ((1 bsl N) - 1)). 1229: -define(ALL_ONES, ((1 bsl 52) - 1)). 1230: 1231: otp_7084(doc) -> 1232: ["OTP-7084. Printing floating point numbers nicely."]; 1233: otp_7084(suite) -> 1234: []; 1235: otp_7084(Config) when is_list(Config) -> 1236: OldDog=?config(watchdog, Config), 1237: test_server:timetrap_cancel(OldDog), 1238: Timeout = 180, 1239: ?line Dog = test_server:timetrap({seconds,Timeout}), 1240: L = [{g_warm_up, fun g_warm_up/0}, 1241: {g_big_pos_float, fun g_big_pos_float/0}, 1242: {g_small_neg_float, fun g_small_neg_float/0}, 1243: {g_close_to_zero, fun g_close_to_zero/0}, 1244: {g_denormalized, fun g_denormalized/0}, 1245: {g_normalized, fun g_normalized/0}, 1246: {g_choice, fun g_choice/0}, 1247: {g_misc, fun g_misc/0}], 1248: F = fun({M,T}) -> io:format("~p~n", [M]), T() end, 1249: R = try 1250: lists:foreach(fun(T) -> F(T) end, L), 1251: ok 1252: catch throw:Reason -> 1253: Reason 1254: end, 1255: ?line test_server:timetrap_cancel(Dog), 1256: R. 1257: 1258: g_warm_up() -> 1259: g_t(0.5), 1260: g_t(-0.5), 1261: g_t((1 bsl 55) * 0.5), 1262: g_t(-(1 bsl 55) * 0.5), 1263: g_t(1.6799127650033296e+308), 1264: g_t(pack(1, 0, 2#1010101010001100101000010111100101000000101100110001)), 1265: g_t(pack(1, 0, 2#0001010000001001110100000101010101001110010001010110)), 1266: g_t(234324324.23432432432432), 1267: ok. 1268: 1269: g_big_pos_float() -> 1270: %% The greatest positive float: 1271: ft({{0,2046,?ONE(52)}, 100, 0}), 1272: ok. 1273: 1274: g_small_neg_float() -> 1275: %% The least negative float: 1276: ft({{1,2046,?ONE(52)}, 0, 100}), 1277: ok. 1278: 1279: g_close_to_zero() -> 1280: %% A few denormalized floats close to zero: 1281: ft({{0,0,0}, 100, 100}), 1282: g_t(pack(1, 0, 0)), % -0.0 1283: ok. 1284: 1285: g_denormalized() -> 1286: %% Denormalized floats (mantissa carry): 1287: % D = 5, 1288: %% Faster: 1289: D = 1, 1290: [ft({{S,0,?ONE(N)},D,D}) || S <- [0,1], N <- lists:seq(0, 52)], 1291: ok. 1292: 1293: g_normalized() -> 1294: %% Normalized floats (exponent carry): 1295: % D = 5, 1296: %% Faster: 1297: D = 1, 1298: [ft({{S,E,?ONE(52)},D,D}) || S <- [0,1], E <- lists:seq(0, 2045)], 1299: ok. 1300: 1301: g_choice() -> 1302: %% Exponent should be used when and only when the string is shorter. 1303: %% (g_misc/0 checks this too, and probably more throughly). 1304: L = [0.0003, 3.0e-5, 3.3e-5, 3.3e-4, 1305: 314.0, 314.1, 310.0, 3.1e6, -100.0, 1306: 3.34e4, 3.0e3, 3.34333e9, 3.3433323e10, 33433323700.0, 1307: 0.00197963, 1.97963e-4], 1308: lists:foreach(fun(V) -> g_t(V) end, L), 1309: ok. 1310: 1311: g_misc() -> 1312: L_0_308 = lists:seq(0, 308), 1313: L_0_307 = lists:seq(0, 307), 1314: % L_1_9 = lists:seq(1, 9), 1315: % L_0_9 = lists:seq(0, 9), 1316: %% Faster: 1317: L_1_9 = [1,5,9], 1318: L_0_9 = [0,1,5,9], 1319: 1320: %% 1.0,10.0, ... 2.0,20.0, ... 9.0,90.0, ... -1,-10, ... -2.0,-20.0... 1321: [g_t(S*T*pow10(N)) || S <- [1.0, -1.0], T <- L_1_9, N <- L_0_307], 1322: 1323: %% 1.0,1.0/10,1.0/100,... 2.0,2.0/10,2.0/100, ... 9.0,9.0/10,9.0/100, 1324: %% -1.0,-1.0/10,... -9.0,-9.0/10... 1325: [g_t(S*T/pow10(N)) || S <- [1.0, -1.0], T <- L_1_9, N <- L_0_308], 1326: 1327: %% 0.0,1.0,2.0,...,9.0, 0.0,10.0,20.0,...,90.0,... 1328: %% 0.0,-1.0,-2.0,...,-9.0, 0.0,-10.0,-20.0,...,-90.0,... 1329: [g_t(S*list_to_float([D+$0]++lists:duplicate(N, $0)++".0")) || 1330: S <- [1.0,-1.0], N <- lists:seq(0, 300), D <- L_0_9], 1331: 1332: %% 0.0,0.1,0.2,...0,9, 0.0,0.01,0.02,...,0.09, 1333: %% 0.0,-0.1,-0.2,...-0,9, 0.0,-0.01,-0.02,...,-0.09, 1334: [g_t(S*list_to_float("0."++lists:duplicate(N, $0)++[D+$0])) || 1335: S <- [1.0,-1.0], N <- lists:seq(0, 300), D <- L_0_9], 1336: ok. 1337: 1338: ft({{S,E,M}, L, G}) -> 1339: ft({pack(S, E, M), L, G}); 1340: ft({V, Less, Greater}) when is_float(V) -> 1341: _ = g_t(V), 1342: ft(V, fun inc/1, Greater), 1343: ft(V, fun dec/1, Less). 1344: 1345: ft(V0, F, I) when I > 0, is_float(V0) -> 1346: V = F(V0), 1347: _ = g_t(V), 1348: ft(V, F, I - 1); 1349: ft(V, _F, 0) when is_float(V) -> 1350: ok. 1351: 1352: g_t(V) when is_float(V) -> 1353: %% io:format("Testing ~.17g~n", [V]), 1354: Io = io_lib:format("~p", [V]), 1355: Sv = binary_to_list(iolist_to_binary(Io)), 1356: ok = g_t(V, Sv), 1357: Sv. 1358: 1359: %% -> ok | THROW 1360: 1361: %% Checks that Sv is the shortest, correctly rounded string that 1362: %% converts to V when read back with list_to_float/1. 1363: %% Note: in a few cases the least significant digit has been 1364: %% incremented by one, namely when the correctly rounded string 1365: %% converts to another floating point number. 1366: g_t(0.0, "0.0") -> 1367: ok; 1368: g_t(V, Sv) -> 1369: try 1370: g_t_1(V, Sv) 1371: catch throw:Reason -> 1372: throw({Reason, V, Sv}) 1373: end. 1374: 1375: g_t_1(V, Sv) -> 1376: %% Check that the least significant digit is correct. 1377: %% If Sv is "3.14" then Sv- is "3.13" and Sv+ is "3.15". 1378: %% Check that |V - Sv| =< (V - Sv-) and 1379: %% that |V - Sv| =< (Sv+ - V) 1380: Times = least_significant_digit(Sv), 1381: case Times of 1382: 0 -> throw(least_significant_digit_is_zero); 1383: _ -> ok 1384: end, 1385: S = if V < 0 -> -1; true -> 1 end, 1386: SvMinus = incr_lsd(Sv, -S), 1387: SvPlus = incr_lsd(Sv, S), 1388: Svr = s2r(Sv), 1389: Svminusr = s2r(SvMinus), 1390: Svplusr = s2r(SvPlus), 1391: Vr = f2r(V), 1392: 1393: Abs_Sv_Vr = rat_abs(rat_minus(Svr, Vr)), 1394: Svminus_Vr = rat_minus(Vr, Svminusr), 1395: Svplus_Vr = rat_minus(Svplusr, Vr), 1396: %% The are 45 (negative) floats where SvMinus (SvPlus) is closer 1397: %% to V than Sv, but such that when reading SvMinus (SvPlus) wrong 1398: %% float would be returned. 1399: case rat_lte(Abs_Sv_Vr, Svminus_Vr) of 1400: true -> 1401: ok; 1402: false -> 1403: case list_to_float(SvMinus) of 1404: V -> throw(vsminus_too_close_to_v); 1405: _Vminus -> ok 1406: end 1407: end, 1408: case rat_lte(Abs_Sv_Vr, Svplus_Vr) of 1409: true -> 1410: ok; 1411: false -> 1412: case list_to_float(SvPlus) of 1413: V -> throw(vsplus_too_close_to_v); 1414: _Vplus -> ok 1415: end 1416: end, 1417: 1418: %% Check that Sv is closer to V than to V- and V+. 1419: %% Check that |V - Sv| =< (V - V-) and 1420: %% that |V - Sv| =< (V+ - V) 1421: %% (An alternative is V- + V =< 2*Sv =< V + V+.) 1422: case inc(V) of 1423: inf -> 1424: ok; 1425: Vplus -> 1426: Vplusr = f2r(Vplus), 1427: V_Vplusr = rat_minus(Vplusr, Vr), 1428: case rat_lte(Abs_Sv_Vr, V_Vplusr) of 1429: true -> ok; 1430: false -> throw(vplus_too_close_to_sv) 1431: end 1432: end, 1433: case dec(V) of 1434: '-inf' -> 1435: ok; 1436: Vminus -> 1437: Vminusr = f2r(Vminus), 1438: V_Vminusr = rat_minus(Vr, Vminusr), 1439: case rat_lte(Abs_Sv_Vr, V_Vminusr) of 1440: true -> ok; 1441: false -> throw(vminus_too_close_to_sv) 1442: end 1443: end, 1444: 1445: %% Check that no prefix of Sv yields V. 1446: %% If Sv is "3.14" then Svlow is "3.1" and Svhigh is "3.2". 1447: %% 1448: %% This is just one way of getting Svlow and Svhigh: 1449: if 1450: V < 0 -> 1451: SvHigh = step_lsd(Sv, -Times), 1452: SvLow = step_lsd(Sv, 10 - Times); 1453: true -> 1454: SvHigh = step_lsd(Sv, 10 - Times), 1455: SvLow = step_lsd(Sv, -Times) 1456: end, 1457: 1458: case catch list_to_float(SvLow) of 1459: V -> throw(low_is_v); 1460: _ -> ok 1461: end, 1462: 1463: case catch list_to_float(SvHigh) of 1464: V -> throw(high_is_v); 1465: _ -> ok 1466: end, 1467: 1468: %% Check that Sv has enough digits. 1469: case list_to_float(Sv) of 1470: V -> ok; 1471: _ -> throw(wrong_float) % cannot happen 1472: end, 1473: 1474: g_choice(Sv), 1475: 1476: ok. 1477: 1478: %%% In "123450000.0", '5' is the lsd; 1479: %%% in "1234.0000", (the last) '0' is the lsd; 1480: %%% in "1234.0", '4' is the lsd (the Erlang syntax requires the final zero). 1481: 1482: %% Trailing zeroes are not significant ("3.0", "5.0e-324", "232000.0"). 1483: least_significant_digit("-"++Ds) -> 1484: least_significant_digit(Ds); 1485: least_significant_digit("+"++Ds) -> 1486: least_significant_digit(Ds); 1487: least_significant_digit(Ds) -> 1488: [MS|_E] = string:tokens(Ds, "eE"), 1489: lsd0(lists:reverse(MS))-$0. 1490: 1491: lsd0("0."++Ds) -> 1492: lsd1(Ds); 1493: lsd0([D | _Ds]) -> 1494: D. 1495: 1496: lsd1("0"++Ds) -> 1497: lsd1(Ds); 1498: lsd1([D | _Ds]) -> 1499: D. 1500: 1501: step_lsd(Ds, 0) -> 1502: Ds; 1503: step_lsd(Ds, N) when N > 0 -> 1504: NDs = incr_lsd(Ds, 1), 1505: step_lsd(NDs, N - 1); 1506: step_lsd(Ds, N) when N < 0 -> 1507: NDs = incr_lsd(Ds, -1), 1508: step_lsd(NDs, N + 1). 1509: 1510: %% Assumes Ds represents some other number than zero. 1511: %% Increments or decrements the least significant digit. 1512: incr_lsd("-"++Ds, I) -> 1513: "-"++incr_lsd(Ds, I); 1514: incr_lsd(Ds, I) when I =:= 1; I =:= -1 -> 1515: [MS|E] = string:tokens(Ds, "eE"), 1516: X = ["e" || true <- [E =/= []]], 1517: lists:flatten([incr_lsd0(lists:reverse(MS), I, []), X, E]). 1518: 1519: incr_lsd0("0."++Ds, C, L) -> 1520: incr_lsd1(Ds, C, [$., $0 | L]); 1521: incr_lsd0(Ds, C, L) -> 1522: incr_lsd2(Ds, C, L). 1523: 1524: incr_lsd1("0"++Ds, C, L) -> 1525: incr_lsd1(Ds, C, [$0 | L]); 1526: incr_lsd1(Ds, C, L) -> 1527: incr_lsd2(Ds, C, L). 1528: 1529: incr_lsd2([], C, L) -> 1530: [C + $0 | L]; 1531: incr_lsd2("."++Ds, C, L) -> 1532: incr_lsd2(Ds, C, [$. | L]); 1533: incr_lsd2("9"++Ds, 1=C, L) -> 1534: incr_lsd2(Ds, C, [$0 | L]); 1535: incr_lsd2("0"++Ds, -1=C, L) -> 1536: incr_lsd2(Ds, C, [$9 | L]); 1537: incr_lsd2([D | Ds], C, L) -> 1538: lists:reverse(Ds, [D + C | L]). 1539: 1540: s2r(S) when is_list(S) -> 1541: case string:tokens(S, "eE") of 1542: [MS] -> 1543: s10(MS); 1544: [MS, ES] -> 1545: Mr = s10(MS), 1546: E = list_to_integer(ES), 1547: if 1548: E < 0 -> 1549: rat_multiply(Mr, {1,pow10(-E)}); 1550: true -> 1551: rat_multiply(Mr, {pow10(E), 1}) 1552: end 1553: end. 1554: 1555: s10("-"++S) -> 1556: rat_multiply({-1,1},s10(S)); 1557: s10(S) -> 1558: [AS, BS] = string:tokens(S, "."), 1559: Sc = length(BS), 1560: A = list_to_integer(AS), 1561: B = list_to_integer(BS), 1562: F = pow10(Sc), 1563: rat_multiply({1,1}, {A*F + B, F}). 1564: 1565: pow10(X) -> 1566: int_pow(10, X). 1567: 1568: int_pow(X, 0) when is_integer(X) -> 1569: 1; 1570: int_pow(X, N) when is_integer(X), is_integer(N), N > 0 -> 1571: int_pow(X, N, 1). 1572: 1573: int_pow(X, N, R) when N < 2 -> 1574: R * X; 1575: int_pow(X, N, R) -> 1576: int_pow(X * X, N bsr 1, case N band 1 of 1 -> R * X; 0 -> R end). 1577: 1578: dec(F) when is_float(F) -> 1579: <<S:1, BE:11, M:52>> = <<F:64/float>>, 1580: dec({S,BE,M}); 1581: dec({1,2046,?ALL_ONES}) -> 1582: '-inf'; 1583: dec({S,BE,M}) when 0 =< S, S =< 1, 1584: 0 =< BE, BE =< 2046, 1585: 0 =< M, M =< ?ALL_ONES -> 1586: {S1,BE1,M1} = dec1(S, BE, M), 1587: <<F:64/float>> = <<S:1, BE:11, M:52>>, 1588: <<F1:64/float>> = <<S1:1, BE1:11, M1:52>>, 1589: true = F1 < F, 1590: F1. 1591: 1592: 1593: dec1(0, 0, 0) -> 1594: dec1(1, 0, 0); 1595: dec1(0, BE, 0) -> 1596: {0,BE-1,?ALL_ONES}; 1597: dec1(0, BE, M) -> 1598: {0,BE,M-1}; 1599: dec1(1, BE, ?ALL_ONES) -> 1600: {1,BE+1,0}; 1601: dec1(1, BE, M) -> 1602: {1,BE,M+1}. 1603: 1604: inc(F) when is_float(F) -> 1605: <<S:1, BE:11, M:52>> = <<F:64/float>>, 1606: inc({S,BE,M}); 1607: inc({0,2046,?ALL_ONES}) -> 1608: inf; 1609: inc({S,BE,M}) when 0 =< S, S =< 1, 1610: 0 =< BE, BE =< 2046, 1611: 0 =< M, M =< ?ALL_ONES -> 1612: {S1,BE1,M1} = inc1(S, BE, M), 1613: <<F:64/float>> = <<S:1, BE:11, M:52>>, 1614: <<F1:64/float>> = <<S1:1, BE1:11, M1:52>>, 1615: true = F1 > F, 1616: F1. 1617: 1618: inc1(0, BE, ?ALL_ONES) -> 1619: {0,BE+1,0}; 1620: inc1(0, BE, M) -> 1621: {0,BE,M+1}; 1622: inc1(1, 0, 0) -> 1623: inc1(0, 0, 0); 1624: inc1(1, BE, 0) -> 1625: {1,BE-1,?ALL_ONES}; 1626: inc1(1, BE, M) -> 1627: {1,BE,M-1}. 1628: 1629: f2r(F) when is_float(F) -> 1630: <<S:1, BE:11, M:52>> = <<F:64/float>>, 1631: f2r({S,BE,M}); 1632: f2r({S,BE,M}) when 0 =< S, S =< 1, 1633: 0 =< BE, BE =< 2046, 1634: 0 =< M, M =< ?ALL_ONES -> 1635: Vr = {T,N} = f2r1(S, BE, M), 1636: <<F:64/float>> = <<S:1, BE:11, M:52>>, 1637: case catch T/N of 1638: {'EXIT', _} -> ok; 1639: TN -> true = F =:= TN 1640: end, 1641: Vr. 1642: 1643: f2r1(S, 0, M) -> 1644: rat_multiply({sign(S),1}, {M, 1 bsl 1074}); 1645: f2r1(S, BE, M) when BE - 1075 >= 0 -> 1646: rat_multiply({sign(S),1}, {((1 bsl 52)+M) * (1 bsl (BE-1075)),1}); 1647: f2r1(S, BE, M) -> 1648: rat_multiply({sign(S),1}, {(1 bsl 52)+M, 1 bsl (1075-BE)}). 1649: 1650: sign(0) -> 1651: 1; 1652: sign(1) -> 1653: -1. 1654: 1655: %%% Rational numbers (very scetchy). 1656: 1657: rat_abs({A,B}) when A < 0 -> 1658: {-A,B}; 1659: rat_abs({A,B}) -> 1660: {A,B}. 1661: 1662: -ifdef(not_used). 1663: rat_equal(R1, R2) -> 1664: R1 =:= R2. 1665: 1666: rat_negate({A,B}) -> 1667: {-A,B}. 1668: 1669: rat_divide({A,B},{C,D}) -> 1670: rat_multiply({A,B},{D,C}). 1671: -endif. 1672: 1673: rat_lte({A,B}, {C,D}) when B =/= 0, D =/= 0 -> 1674: A*D =< C*B. 1675: 1676: rat_minus({A,B}, {C,D}) -> 1677: rat_plus({A,B}, {-C,D}). 1678: 1679: rat_plus({A,B}, {C,D}) when B =/= 0, D =/= 0 -> 1680: rat_normalize({A*D+B*C, B*D}). 1681: 1682: rat_multiply({A,B}, {C,D}) when B =/= 0, D =/= 0 -> 1683: rat_normalize({A * C, B * D}). 1684: 1685: rat_normalize({T,N}) when N =/= 0 -> 1686: G = gcd(T, N), 1687: T2 = T div G, 1688: N2 = N div G, 1689: if 1690: T2 < 0 -> 1691: if 1692: N2 < 0 -> {-T2,-N2}; 1693: true -> {T2,N2} 1694: end; 1695: true -> 1696: if 1697: N2 < 0 -> {-T2,-N2}; 1698: true -> {T2,N2} 1699: end 1700: end. 1701: 1702: gcd(A, 0) -> A; 1703: gcd(A, B) -> gcd(B, A rem B). 1704: 1705: %%% End of rational numbers. 1706: 1707: %% Check that there is an exponent if and only if characters are 1708: %% saved. Note: this assumes floating point numbers "Erlang style" 1709: %% (with a single zero before and after the dot, and no extra leading 1710: %% zero in the exponent). 1711: g_choice(S) when is_list(S) -> 1712: [MS | ES0] = string:tokens(S, "eE"), 1713: [IS, FS] = string:tokens(MS, "."), 1714: Il = length(IS), 1715: Fl = length(FS), 1716: Pre = z(MS), 1717: Post = z(lists:reverse(MS)), 1718: ES = lists:append(ES0), 1719: El = length(ES), 1720: I = list_to_integer(IS), 1721: if 1722: El =/= 0, ((I > 9) or (I < -9)) -> 1723: throw(too_many_digits_before_the_dot); 1724: El =/= 0, I =:= 0 -> 1725: throw(zero_before_the_dot); 1726: Pre =:= 0, Post > 0, El =:= 0 -> % DDDD0000.0 1727: Saving = if 1728: I < 0, Il =:= Post + 2 -> 1729: Post; 1730: I > 0, Il =:= Post + 1 -> 1731: Post; 1732: I =/= 0, true -> 1733: Post + 1 1734: end, 1735: Cost = 1 + length(integer_to_list(Il - 1)), 1736: if 1737: Cost < Saving -> 1738: throw(with_exponent_is_shorter); 1739: true -> 1740: ok 1741: end; 1742: Pre > 0, Post =:= 0, El =:= 0 -> % 0.000DDDD 1743: Saving = if 1744: Fl =:= Pre + 1 -> 1745: Pre; 1746: true -> 1747: Pre + 1 1748: end, 1749: Cost = 2 + length(integer_to_list(Pre + 1)), 1750: if 1751: Cost < Saving -> 1752: throw(with_exponent_is_shorter); 1753: true -> 1754: ok 1755: end; 1756: Pre =:= 0, Post =:= 0, El > 0 -> % D.DDDeDD 1757: E = list_to_integer(ES), 1758: if 1759: E >= 0 -> 1760: Cost = E - (Fl - 1); 1761: E < 0 -> 1762: Cost = -E 1763: end, 1764: Saving = length(ES) + 1, 1765: if 1766: Cost =:= Saving -> 1767: throw(draw_but_choose_form_without_exponent); 1768: Cost < Saving -> 1769: throw(without_exponent_is_shorter); 1770: true -> 1771: ok 1772: end; 1773: Pre =:= 0, Post =:= 0, El =:= 0 -> % DDD.DDD 1774: ok; 1775: true -> 1776: throw(badly_formed_floating_point_string) 1777: end. 1778: 1779: z("0."++Ds) -> 1780: length(lists:takewhile(fun(D) -> D =:= $0 end, Ds)); 1781: z(_Ds) -> 1782: 0. 1783: 1784: pack(Sign, Exp, Frac) -> 1785: <<Float:64/float>> = <<Sign:1, Exp:11, Frac:52>>, 1786: Float. 1787: 1788: %% Whitebox test of io_lib:collect_line/3. 1789: io_lib_collect_line_3_wb(Config) when is_list(Config) -> 1790: ?line do_collect_line(binary, "\n"), 1791: ?line do_collect_line(binary, "\r\n"), 1792: ?line do_collect_line(list, "\n"), 1793: ?line do_collect_line(list, "\r\n"), 1794: ok. 1795: 1796: do_collect_line(Mode, Eol) -> 1797: First = "abcde", 1798: FirstNL = First++"\n", 1799: Second = "unterminated line", 1800: Data0 = First ++ Eol ++ Second, 1801: {Data1,Result0} = do_collect_line_combine(Mode, Data0, FirstNL, Second), 1802: do_collect_line_1(Mode, Data1, Result0, []), 1803: 1804: {Data,Result} = do_collect_line_combine(Mode, "unterm", "unterm", eof), 1805: do_collect_line_1(Mode, Data, Result, []). 1806: 1807: do_collect_line_combine(binary, Data0, FirstNL, eof) -> 1808: {list_to_binary(Data0), 1809: {stop,list_to_binary(FirstNL),eof}}; 1810: do_collect_line_combine(binary, Data0, FirstNL, Second) -> 1811: {list_to_binary(Data0), 1812: {stop,list_to_binary(FirstNL),list_to_binary(Second)}}; 1813: do_collect_line_combine(list, Data0, FirstNL, Second) -> 1814: {Data0,{stop,FirstNL,Second}}. 1815: 1816: do_collect_line_1(Mode, [H|T], Result, Acc0) -> 1817: Acc = [H|Acc0], 1818: Result = do_collect_line_2(lists:reverse(Acc), T), 1819: do_collect_line_1(Mode, T, Result, Acc); 1820: do_collect_line_1(Mode, <<H,T/binary>>, Result, Acc0) -> 1821: Acc = [H|Acc0], 1822: Result = do_collect_line_2(list_to_binary(lists:reverse(Acc)), T), 1823: do_collect_line_1(Mode, T, Result, Acc); 1824: do_collect_line_1(_Mode, [], _Result, _Acc) -> 1825: ok; 1826: do_collect_line_1(_Mode, <<>>, _Result, _Acc) -> 1827: ok. 1828: 1829: do_collect_line_2(Part1, Part2) -> 1830: Dummy = make_ref(), 1831: do_collect_line_3(start, [Part1,Part2,eof], Dummy). 1832: 1833: do_collect_line_3(State0, [H|T], Dummy) -> 1834: case io_lib:collect_line(State0, H, Dummy) of 1835: {stop,Line,Rest} -> 1836: {stop,Line,do_collect_line_adjust_rest(Rest, T)}; 1837: State -> 1838: do_collect_line_3(State, T, Dummy) 1839: end. 1840: 1841: do_collect_line_adjust_rest(eof, []) -> eof; 1842: do_collect_line_adjust_rest(eof, <<>>) -> eof; 1843: do_collect_line_adjust_rest(Rest, [eof]) -> Rest; 1844: do_collect_line_adjust_rest(Rest, [Bin|T]) when is_binary(Bin) -> 1845: do_collect_line_adjust_rest(<<Rest/binary,Bin/binary>>, T); 1846: do_collect_line_adjust_rest(Rest, [List|T]) when is_list(List) -> 1847: do_collect_line_adjust_rest(Rest++List, T). 1848: 1849: 1850: 1851: cr_whitespace_in_string(Config) when is_list(Config) -> 1852: ?line {ok,["abc"],[]} = io_lib:fread("~s", "\rabc"). 1853: 1854: 1855: 1856: io_fread_newlines(Config) when is_list(Config) -> 1857: ?line PrivDir = ?privdir(Config), 1858: ?line Fname = filename:join(PrivDir, "io_fread_newlines.txt"), 1859: ?line F0 = [[0,1,2,3,4,5,6,7,8,9]], 1860: ?line F1 = [[0,1,2,3,4,5,6,7,8],[9]], 1861: ?line F2 = [[0,1,2,3,4,5,6,7],[8,9]], 1862: ?line F3 = [[0,1,2,3,4,5,6],[7,8,9]], 1863: ?line F4 = [[0,1,2,3,4,5],[6,7,8,9]], 1864: ?line F5 = [[0,1,2,3,4],[5,6,7,8,9]], 1865: ?line F6 = [[0,1,2,3],[4,5,6,7],[8,9]], 1866: ?line F7 = [[0,1,2],[3,4,5],[6,7,8],[9]], 1867: ?line F8 = [[0,1],[2,3],[4,5],[6,7],[8,9]], 1868: ?line F9 = [[0],[1],[2],[3],[4],[5],[6],[7],[8],[9]], 1869: ?line Newlines = ["\n", "\r\n", "\r"], 1870: try 1871: ?line io_fread_newlines_1([F0,F1,F2,F3,F4,F5,F6,F7,F8,F9], 1872: Fname, Newlines) 1873: after 1874: file:delete(Fname) 1875: end. 1876: 1877: io_fread_newlines_1(Fs, Fname, [Newline|Newlines]) -> 1878: ?line ok = io_fread_newlines_2(Fs, Fname, Newline), 1879: ?line io_fread_newlines_1(Fs, Fname, Newlines); 1880: io_fread_newlines_1(_, _, []) -> ok. 1881: 1882: io_fread_newlines_2([F|Fs], Fname, Newline) -> 1883: ?line N1 = write_newlines_file(Fname, F, Newline), 1884: ?line {F2,N2} = read_newlines_file(Fname), 1885: ?line io:format("~w ~p ~w~n~n", [N1,F,N2]), 1886: ?line F2 = lists:flatten(F), 1887: %% Intermediate newlines are not counted 1888: ?line N2 = N1 - (length(F) - 1)*length(Newline), 1889: ?line io_fread_newlines_2(Fs, Fname, Newline); 1890: io_fread_newlines_2([], _, _) -> ok. 1891: 1892: 1893: write_newlines_file(Fname, F, Newline) -> 1894: Bytes = list_to_binary(digit_lines(F, Newline)), 1895: io:format("Data: ~w~n~w~n", [Newline,Bytes]), 1896: ok = file:write_file(Fname, Bytes), 1897: size(Bytes). 1898: 1899: digit_lines([L], _) -> 1900: digit_line(L); 1901: digit_lines([L|Ls], Newline) -> 1902: [digit_line(L),Newline|digit_lines(Ls, Newline)]. 1903: 1904: digit_line([D]) -> 1905: integer_to_list(D); 1906: digit_line([D|Ds]) -> 1907: [integer_to_list(D), " ", digit_line(Ds)]. 1908: 1909: read_newlines_file(Fname) -> 1910: {ok,Fd} = file:open(Fname, [read]), 1911: try {L, N0} = R0 = read_newlines(Fd, [], 0), 1912: case io:fread(Fd, "", "~*s~l") of 1913: eof -> R0; 1914: {ok,[N]} -> {L,N0+N} 1915: end 1916: after 1917: file:close(Fd) 1918: end. 1919: 1920: 1921: read_newlines(Fd, Acc, N0) -> 1922: case io:fread(Fd, "", "~d~l") of 1923: {ok,[D,N]} -> 1924: read_newlines(Fd, [D|Acc], N0+N); 1925: eof -> 1926: {lists:reverse(Acc),N0} 1927: end. 1928: 1929: 1930: 1931: otp_8989(doc) -> 1932: "OTP-8989 io:format for ~F.Ps ignores P in some cases"; 1933: otp_8989(Suite) when is_list(Suite) -> 1934: Hello = "Hello", 1935: ?line " Hello" = fmt("~6.6s", [Hello]), 1936: ?line " Hello" = fmt("~*.6s", [6,Hello]), 1937: ?line " Hello" = fmt("~6.*s", [6,Hello]), 1938: ?line " Hello" = fmt("~*.*s", [6,6,Hello]), 1939: %% 1940: ?line " Hello" = fmt("~6.5s", [Hello]), 1941: ?line " Hello" = fmt("~*.5s", [6,Hello]), 1942: ?line " Hello" = fmt("~6.*s", [5,Hello]), 1943: ?line " Hello" = fmt("~*.*s", [6,5,Hello]), 1944: %% 1945: ?line " Hell" = fmt("~6.4s", [Hello]), 1946: ?line " Hell" = fmt("~*.4s", [6,Hello]), 1947: ?line " Hell" = fmt("~6.*s", [4,Hello]), 1948: ?line " Hell" = fmt("~*.*s", [6,4,Hello]), 1949: %% 1950: ?line "Hello" = fmt("~5.5s", [Hello]), 1951: ?line "Hello" = fmt("~*.5s", [5,Hello]), 1952: ?line "Hello" = fmt("~5.*s", [5,Hello]), 1953: ?line "Hello" = fmt("~*.*s", [5,5,Hello]), 1954: %% 1955: ?line " Hell" = fmt("~5.4s", [Hello]), 1956: ?line " Hell" = fmt("~*.4s", [5,Hello]), 1957: ?line " Hell" = fmt("~5.*s", [4,Hello]), 1958: ?line " Hell" = fmt("~*.*s", [5,4,Hello]), 1959: %% 1960: ?line "Hell" = fmt("~4.4s", [Hello]), 1961: ?line "Hell" = fmt("~*.4s", [4,Hello]), 1962: ?line "Hell" = fmt("~4.*s", [4,Hello]), 1963: ?line "Hell" = fmt("~*.*s", [4,4,Hello]), 1964: %% 1965: ?line " Hel" = fmt("~4.3s", [Hello]), 1966: ?line " Hel" = fmt("~*.3s", [4,Hello]), 1967: ?line " Hel" = fmt("~4.*s", [3,Hello]), 1968: ?line " Hel" = fmt("~*.*s", [4,3,Hello]), 1969: %% 1970: %% 1971: ?line "Hello " = fmt("~-6.6s", [Hello]), 1972: ?line "Hello " = fmt("~*.6s", [-6,Hello]), 1973: ?line "Hello " = fmt("~-6.*s", [6,Hello]), 1974: ?line "Hello " = fmt("~*.*s", [-6,6,Hello]), 1975: %% 1976: ?line "Hello " = fmt("~-6.5s", [Hello]), 1977: ?line "Hello " = fmt("~*.5s", [-6,Hello]), 1978: ?line "Hello " = fmt("~-6.*s", [5,Hello]), 1979: ?line "Hello " = fmt("~*.*s", [-6,5,Hello]), 1980: %% 1981: ?line "Hell " = fmt("~-6.4s", [Hello]), 1982: ?line "Hell " = fmt("~*.4s", [-6,Hello]), 1983: ?line "Hell " = fmt("~-6.*s", [4,Hello]), 1984: ?line "Hell " = fmt("~*.*s", [-6,4,Hello]), 1985: %% 1986: ?line "Hello" = fmt("~-5.5s", [Hello]), 1987: ?line "Hello" = fmt("~*.5s", [-5,Hello]), 1988: ?line "Hello" = fmt("~-5.*s", [5,Hello]), 1989: ?line "Hello" = fmt("~*.*s", [-5,5,Hello]), 1990: %% 1991: ?line "Hell " = fmt("~-5.4s", [Hello]), 1992: ?line "Hell " = fmt("~*.4s", [-5,Hello]), 1993: ?line "Hell " = fmt("~-5.*s", [4,Hello]), 1994: ?line "Hell " = fmt("~*.*s", [-5,4,Hello]), 1995: %% 1996: ?line "Hell" = fmt("~-4.4s", [Hello]), 1997: ?line "Hell" = fmt("~*.4s", [-4,Hello]), 1998: ?line "Hell" = fmt("~-4.*s", [4,Hello]), 1999: ?line "Hell" = fmt("~*.*s", [-4,4,Hello]), 2000: %% 2001: ?line "Hel " = fmt("~-4.3s", [Hello]), 2002: ?line "Hel " = fmt("~*.3s", [-4,Hello]), 2003: ?line "Hel " = fmt("~-4.*s", [3,Hello]), 2004: ?line "Hel " = fmt("~*.*s", [-4,3,Hello]), 2005: ok. 2006: 2007: io_lib_fread_literal(doc) -> 2008: "OTP-9439 io_lib:fread bug for literate at end"; 2009: io_lib_fread_literal(Suite) when is_list(Suite) -> 2010: ?line {more,"~d",0,""} = io_lib:fread("~d", ""), 2011: ?line {error,{fread,integer}} = io_lib:fread("~d", " "), 2012: ?line {more,"~d",1,""} = io_lib:fread(" ~d", " "), 2013: ?line {ok,[17],"X"} = io_lib:fread(" ~d", " 17X"), 2014: %% 2015: ?line {more,"d",0,""} = io_lib:fread("d", ""), 2016: ?line {error,{fread,input}} = io_lib:fread("d", " "), 2017: ?line {more,"d",1,""} = io_lib:fread(" d", " "), 2018: ?line {ok,[],"X"} = io_lib:fread(" d", " dX"), 2019: %% 2020: ?line {done,eof,_} = io_lib:fread([], eof, "~d"), 2021: ?line {done,eof,_} = io_lib:fread([], eof, " ~d"), 2022: ?line {more,C1} = io_lib:fread([], " \n", " ~d"), 2023: ?line {done,{error,{fread,input}},_} = io_lib:fread(C1, eof, " ~d"), 2024: ?line {done,{ok,[18]},""} = io_lib:fread(C1, "18\n", " ~d"), 2025: %% 2026: ?line {done,eof,_} = io_lib:fread([], eof, "d"), 2027: ?line {done,eof,_} = io_lib:fread([], eof, " d"), 2028: ?line {more,C2} = io_lib:fread([], " \n", " d"), 2029: ?line {done,{error,{fread,input}},_} = io_lib:fread(C2, eof, " d"), 2030: ?line {done,{ok,[]},[]} = io_lib:fread(C2, "d\n", " d"), 2031: ok. 2032: 2033: 2034: printable_range(doc) -> 2035: "Check that the printable range set by the user actually works"; 2036: printable_range(Suite) when is_list(Suite) -> 2037: Pa = filename:dirname(code:which(?MODULE)), 2038: {ok, UNode} = test_server:start_node(printable_range_unicode, slave, 2039: [{args, " +pc unicode -pa " ++ Pa}]), 2040: {ok, LNode} = test_server:start_node(printable_range_latin1, slave, 2041: [{args, " +pc latin1 -pa " ++ Pa}]), 2042: {ok, DNode} = test_server:start_node(printable_range_default, slave, 2043: [{args, " -pa " ++ Pa}]), 2044: unicode = rpc:call(UNode,io,printable_range,[]), 2045: latin1 = rpc:call(LNode,io,printable_range,[]), 2046: latin1 = rpc:call(DNode,io,printable_range,[]), 2047: test_server:stop_node(UNode), 2048: test_server:stop_node(LNode), 2049: {ok, UNode} = test_server:start_node(printable_range_unicode, slave, 2050: [{args, " +pcunicode -pa " ++ Pa}]), 2051: {ok, LNode} = test_server:start_node(printable_range_latin1, slave, 2052: [{args, " +pclatin1 -pa " ++ Pa}]), 2053: unicode = rpc:call(UNode,io,printable_range,[]), 2054: latin1 = rpc:call(LNode,io,printable_range,[]), 2055: {error, _} = test_server:start_node(printable_range_unnicode, slave, 2056: [{args, " +pcunnicode -pa " ++ Pa}]), 2057: PrettyOptions = [{column,1}, 2058: {line_length,109}, 2059: {depth,30}, 2060: {max_chars,60}, 2061: {record_print_fun, 2062: fun(_,_) -> no end}, 2063: {encoding,unicode}], 2064: 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib_pretty,print, 2065: [{hello, [1024,1025]}, 2066: PrettyOptions]))), 2067: 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib_pretty,print, 2068: [{hello, [1024,1025]}, 2069: PrettyOptions]))), 2070: 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib_pretty,print, 2071: [{hello, [1024,1025]}, 2072: PrettyOptions]))), 2073: 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib_pretty,print, 2074: [{hello, <<1024/utf8,1025/utf8>>}, 2075: PrettyOptions]))), 2076: 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib_pretty,print, 2077: [{hello, <<1024/utf8,1025/utf8>>}, 2078: PrettyOptions]))), 2079: 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib_pretty,print, 2080: [{hello, <<1024/utf8,1025/utf8>>}, 2081: PrettyOptions]))), 2082: 2083: 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib,format, 2084: ["~tp",[{hello, [1024,1025]}]]))), 2085: 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib,format, 2086: ["~tp",[{hello, [1024,1025]}]]))), 2087: 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib,format, 2088: ["~tp",[{hello, [1024,1025]}]]))), 2089: 1025 = lists:max(lists:flatten(rpc:call(UNode,io_lib,format, 2090: ["~tp", 2091: [{hello, 2092: <<1024/utf8,1025/utf8>>}]]))), 2093: 125 = lists:max(lists:flatten(rpc:call(LNode,io_lib,format, 2094: ["~tp", 2095: [{hello, 2096: <<1024/utf8,1025/utf8>>}]]))), 2097: 125 = lists:max(lists:flatten(rpc:call(DNode,io_lib,format, 2098: ["~tp", 2099: [{hello, 2100: <<1024/utf8,1025/utf8>>}]]))), 2101: test_server:stop_node(UNode), 2102: test_server:stop_node(LNode), 2103: test_server:stop_node(DNode), 2104: ok. 2105: 2106: io_lib_print_binary_depth_one(doc) -> 2107: "Test binaries printed with a depth of one behave correctly"; 2108: io_lib_print_binary_depth_one(Suite) when is_list(Suite) -> 2109: ?line "<<>>" = fmt("~W", [<<>>, 1]), 2110: ?line "<<>>" = fmt("~P", [<<>>, 1]), 2111: ?line "<<...>>" = fmt("~W", [<<1>>, 1]), 2112: ?line "<<...>>" = fmt("~P", [<<1>>, 1]), 2113: ?line "<<...>>" = fmt("~W", [<<1:7>>, 1]), 2114: ?line "<<...>>" = fmt("~P", [<<1:7>>, 1]), 2115: ok. 2116: 2117: otp_10302(doc) -> 2118: "OTP-10302. Unicode"; 2119: otp_10302(Suite) when is_list(Suite) -> 2120: Pa = filename:dirname(code:which(?MODULE)), 2121: {ok, UNode} = test_server:start_node(printable_range_unicode, slave, 2122: [{args, " +pc unicode -pa " ++ Pa}]), 2123: {ok, LNode} = test_server:start_node(printable_range_latin1, slave, 2124: [{args, " +pc latin1 -pa " ++ Pa}]), 2125: "\"\x{400}\"" = rpc:call(UNode,?MODULE,pretty,["\x{400}", -1]), 2126: "<<\"\x{400}\"/utf8>>" = rpc:call(UNode,?MODULE,pretty, 2127: [<<"\x{400}"/utf8>>, -1]), 2128: 2129: "<<\"\x{400}foo\"/utf8>>" = rpc:call(UNode,?MODULE,pretty, 2130: [<<"\x{400}foo"/utf8>>, 2]), 2131: "[1024]" = rpc:call(LNode,?MODULE,pretty,["\x{400}", -1]), 2132: "<<208,128>>" = rpc:call(LNode,?MODULE,pretty,[<<"\x{400}"/utf8>>, -1]), 2133: 2134: "<<208,...>>" = rpc:call(LNode,?MODULE,pretty,[<<"\x{400}foo"/utf8>>, 2]), 2135: test_server:stop_node(UNode), 2136: test_server:stop_node(LNode), 2137: 2138: "<<\"äppl\"/utf8>>" = pretty(<<"äppl"/utf8>>, 2), 2139: "<<\"äppl\"/utf8...>>" = pretty(<<"äpple"/utf8>>, 2), 2140: "<<\"apel\">>" = pretty(<<"apel">>, 2), 2141: "<<\"apel\"...>>" = pretty(<<"apelsin">>, 2), 2142: "<<\"äppl\">>" = fmt("~tp", [<<"äppl">>]), 2143: "<<\"äppl\"...>>" = fmt("~tP", [<<"äpple">>, 2]), 2144: "<<0,0,0,0,0,0,1,0>>" = fmt("~p", [<<256:64/unsigned-integer>>]), 2145: "<<0,0,0,0,0,0,1,0>>" = fmt("~tp", [<<256:64/unsigned-integer>>]), 2146: 2147: Chars = lists:seq(0, 512), % just a few... 2148: [] = [C || C <- Chars, S <- io_lib:write_char_as_latin1(C), 2149: not is_latin1(S)], 2150: L1 = [S || C <- Chars, S <- io_lib:write_char(C), 2151: not is_latin1(S)], 2152: L1 = lists:seq(256, 512), 2153: 2154: [] = [C || C <- Chars, S <- io_lib:write_string_as_latin1([C]), 2155: not is_latin1(S)], 2156: L2 = [S || C <- Chars, S <- io_lib:write_string([C]), 2157: not is_latin1(S)], 2158: L2 = lists:seq(256, 512), 2159: 2160: ok. 2161: 2162: pretty(Term, Depth) when is_integer(Depth) -> 2163: Opts = [{column, 1}, {line_length, 20}, 2164: {depth, Depth}, {max_chars, 60}, 2165: {encoding, unicode}], 2166: pretty(Term, Opts); 2167: pretty(Term, Opts) when is_list(Opts) -> 2168: R = io_lib_pretty:print(Term, Opts), 2169: lists:flatten(io_lib:format("~ts", [R])). 2170: 2171: is_latin1(S) -> 2172: S >= 0 andalso S =< 255. 2173: 2174: otp_10836(doc) -> 2175: "OTP-10836. ~ts extended to latin1"; 2176: otp_10836(Suite) when is_list(Suite) -> 2177: S = io_lib:format("~ts", [[<<"äpple"/utf8>>, <<"äpple">>]]), 2178: "äppleäpple" = lists:flatten(S), 2179: ok. 2180: 2181: otp_10755(doc) -> 2182: "OTP-10755. The 'l' modifier"; 2183: otp_10755(Suite) when is_list(Suite) -> 2184: S = "string", 2185: "\"string\"" = fmt("~p", [S]), 2186: "[115,116,114,105,110,103]" = fmt("~lp", [S]), 2187: "\"string\"" = fmt("~P", [S, 2]), 2188: "[115|...]" = fmt("~lP", [S, 2]), 2189: {'EXIT',{badarg,_}} = (catch fmt("~ltp", [S])), 2190: {'EXIT',{badarg,_}} = (catch fmt("~tlp", [S])), 2191: {'EXIT',{badarg,_}} = (catch fmt("~ltP", [S])), 2192: {'EXIT',{badarg,_}} = (catch fmt("~tlP", [S])), 2193: Text = 2194: "-module(l_mod).\n" 2195: "-export([t/0]).\n" 2196: "t() ->\n" 2197: " S = \"string\",\n" 2198: " io:format(\"~ltp\", [S]),\n" 2199: " io:format(\"~tlp\", [S]),\n" 2200: " io:format(\"~ltP\", [S, 1]),\n" 2201: " io:format(\"~tlP\", [S, 1]).\n", 2202: {ok,l_mod,[{_File,Ws}]} = compile_file("l_mod.erl", Text, Suite), 2203: ["format string invalid (invalid control ~lt)", 2204: "format string invalid (invalid control ~tl)", 2205: "format string invalid (invalid control ~lt)", 2206: "format string invalid (invalid control ~tl)"] = 2207: [lists:flatten(M:format_error(E)) || {_L,M,E} <- Ws], 2208: ok. 2209: 2210: compile_file(File, Text, Config) -> 2211: PrivDir = ?privdir(Config), 2212: Fname = filename:join(PrivDir, File), 2213: ok = file:write_file(Fname, Text), 2214: try compile:file(Fname, [return]) 2215: after ok %file:delete(Fname) 2216: end.