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.