diff options
Diffstat (limited to 'lib/stdlib')
39 files changed, 611 insertions, 334 deletions
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml index f6f3d18d6a..95af2b77a5 100644 --- a/lib/stdlib/doc/src/ets.xml +++ b/lib/stdlib/doc/src/ets.xml @@ -408,9 +408,9 @@ calls cannot be in the guard or body of the fun. Calls to built-in match specification functions is of course allowed:</p> <pre> -4> <input>ets:fun2ms(fun({M,N}) when N > X, is_atomm(M) -> M end).</input> +4> <input>ets:fun2ms(fun({M,N}) when N > X, my_fun(M) -> M end).</input> Error: fun containing local Erlang function calls -('is_atomm' called in guard) cannot be translated into match_spec +('my_fun' called in guard) cannot be translated into match_spec {error,transform_error} 5> <input>ets:fun2ms(fun({M,N}) when N > X, is_atom(M) -> M end).</input> [{{'$1','$2'},[{'>','$2',{const,3}},{is_atom,'$1'}],['$1']}]</pre> diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml index 60dbae70c2..7efafedc82 100644 --- a/lib/stdlib/doc/src/lists.xml +++ b/lib/stdlib/doc/src/lists.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2016</year> + <year>1996</year><year>2017</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -187,7 +187,7 @@ <desc> <p>Calls <c><anno>Fun</anno>(<anno>Elem</anno>)</c> on successive elements <c>Elem</c> of <c><anno>List1</anno></c>. - <c><anno>Fun</anno>/2</c> must return either a Boolean or a tuple + <c><anno>Fun</anno>/1</c> must return either a Boolean or a tuple <c>{true, <anno>Value</anno>}</c>. The function returns the list of elements for which <c><anno>Fun</anno></c> returns a new value, where a value of <c>true</c> is synonymous with diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml index 46454e9b80..bdd5b39cd3 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -31,6 +31,38 @@ </header> <p>This document describes the changes made to the STDLIB application.</p> +<section><title>STDLIB 3.4.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> A bug in <c>proc_lib:format()</c> introduced in + Erlang/OTP 20.0 is corrected. </p> + <p> + Own Id: OTP-14482 Aux Id: PR-1488 </p> + </item> + <item> + <p> + Fix string:len/1 to be compatible with previous versions.</p> + <p> + Own Id: OTP-14487 Aux Id: ERIERL-40 </p> + </item> + <item> + <p> + In OTP-20.0, the behavior of c, make, and ct_make was + changed so that in some cases the beam files by default + would be written to the directory where the source files + were found. This is now changed back to the old behavior + so beam files are by default written to current + directory.</p> + <p> + Own Id: OTP-14489 Aux Id: ERL-438 </p> + </item> + </list> + </section> + +</section> + <section><title>STDLIB 3.4</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml index e06d7e467d..a68fb7d55f 100644 --- a/lib/stdlib/doc/src/rand.xml +++ b/lib/stdlib/doc/src/rand.xml @@ -66,7 +66,7 @@ <p>Jump function: equivalent to 2^64 calls</p> <p> This is a corrected version of the previous default algorithm, - that now has been superseeded by Xoroshiro116+ (<c>exrop</c>). + that now has been superseded by Xoroshiro116+ (<c>exrop</c>). Since there is no native 58 bit rotate instruction this algorithm executes a little (say < 15%) faster than <c>exrop</c>. See the diff --git a/lib/stdlib/src/array.erl b/lib/stdlib/src/array.erl index 079b761463..a237eaa489 100644 --- a/lib/stdlib/src/array.erl +++ b/lib/stdlib/src/array.erl @@ -1603,7 +1603,7 @@ foldl_2(I, E, A, Ix, F, D, N, R, S) -> Ix + S, F, D, N, R, S). -spec foldl_3(pos_integer(), _, A, array_indx(), - fun((array_indx, _, A) -> B), integer()) -> B. + fun((array_indx(), _, A) -> B), integer()) -> B. foldl_3(I, E, A, Ix, F, N) when I =< N -> foldl_3(I+1, E, F(Ix, element(I, E), A), Ix+1, F, N); diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl index 4ab9234b81..c04a201ce1 100644 --- a/lib/stdlib/src/c.erl +++ b/lib/stdlib/src/c.erl @@ -255,7 +255,7 @@ safe_recompile(File, Options, BeamFile) -> compile_and_load(File, Opts0) when is_list(Opts0) -> Opts = [report_errors, report_warnings | ensure_from(filename:extension(File), - ensure_outdir(filename:dirname(File), Opts0))], + ensure_outdir(".", Opts0))], case compile:file(File, Opts) of {ok,Mod} -> %Listing file. purge_and_load(Mod, File, Opts); diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl index 10e8c9c800..4e3fe0e5c1 100644 --- a/lib/stdlib/src/dets.erl +++ b/lib/stdlib/src/dets.erl @@ -1354,7 +1354,7 @@ open_file_loop2(Head, N) -> ?MODULE, [], Head); Message -> error_logger:format("** dets: unexpected message" - "(ignored): ~w~n", [Message]), + "(ignored): ~tw~n", [Message]), open_file_loop(Head, N) end. @@ -1403,7 +1403,7 @@ apply_op(Op, From, Head, N) -> Head; _Dirty when N =:= 0 -> % dirty or new_dirty %% The updates seems to have declined - dets_utils:vformat("** dets: Auto save of ~p\n", + dets_utils:vformat("** dets: Auto save of ~tp\n", [Head#head.name]), {NewHead, _Res} = perform_save(Head, true), erlang:garbage_collect(), @@ -1587,13 +1587,13 @@ bug_found(Name, Op, Bad, From) -> %% If stream_op/5 found more requests, this is not %% the last operation. error_logger:format - ("** dets: Bug was found when accessing table ~w,~n" - "** dets: operation was ~p and reply was ~w.~n" - "** dets: Stacktrace: ~w~n", + ("** dets: Bug was found when accessing table ~tw,~n" + "** dets: operation was ~tp and reply was ~tw.~n" + "** dets: Stacktrace: ~tw~n", [Name, Op, Bad, erlang:get_stacktrace()]); false -> error_logger:format - ("** dets: Bug was found when accessing table ~w~n", + ("** dets: Bug was found when accessing table ~tw~n", [Name]) end, if @@ -2117,7 +2117,7 @@ do_open_file([Fname, Verbose], Parent, Server, Ref) -> Error; Bad -> error_logger:format - ("** dets: Bug was found in open_file/1, reply was ~w.~n", + ("** dets: Bug was found in open_file/1, reply was ~tw.~n", [Bad]), {error, {dets_bug, Fname, Bad}} end; @@ -2135,7 +2135,7 @@ do_open_file([Tab, OpenArgs, Verb], Parent, Server, _Ref) -> Bad -> error_logger:format ("** dets: Bug was found in open_file/2, arguments were~n" - "** dets: ~w and reply was ~w.~n", + "** dets: ~tw and reply was ~tw.~n", [OpenArgs, Bad]), {error, {dets_bug, Tab, {open_file, OpenArgs}, Bad}} end. @@ -3123,7 +3123,7 @@ check_safe_fixtable(Head) -> ((get(verbose) =:= yes) orelse dets_utils:debug_mode()) of true -> error_logger:format - ("** dets: traversal of ~p needs safe_fixtable~n", + ("** dets: traversal of ~tp needs safe_fixtable~n", [Head#head.name]); false -> ok @@ -3189,7 +3189,7 @@ scan_read(H, From, _To, Min, _L, Ts, R, C) -> err(Error) -> case get(verbose) of yes -> - error_logger:format("** dets: failed with ~w~n", [Error]), + error_logger:format("** dets: failed with ~tw~n", [Error]), Error; undefined -> Error diff --git a/lib/stdlib/src/dets_utils.erl b/lib/stdlib/src/dets_utils.erl index da6ebd18f2..17f55ebdc2 100644 --- a/lib/stdlib/src/dets_utils.erl +++ b/lib/stdlib/src/dets_utils.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2016. All Rights Reserved. +%% Copyright Ericsson AB 2001-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -387,7 +387,7 @@ corrupt_reason(Head, Reason0) -> corrupt(Head, Error) -> case get(verbose) of yes -> - error_logger:format("** dets: Corrupt table ~p: ~tp\n", + error_logger:format("** dets: Corrupt table ~tp: ~tp\n", [Head#head.name, Error]); _ -> ok end, diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl index 71e8471c45..64d5a71f3c 100644 --- a/lib/stdlib/src/edlin.erl +++ b/lib/stdlib/src/edlin.erl @@ -83,7 +83,7 @@ edit_line(Cs, {line,P,L,M}) -> edit_line1(Cs, {line,P,L,{blink,N}}) -> edit(Cs, P, L, none, [{move_rel,N}]); edit_line1(Cs, {line,P,{[],[]},none}) -> - {more_chars, {line,P,{lists:reverse(Cs),[]},none},[{put_chars, unicode, Cs}]}; + {more_chars, {line,P,{string:reverse(Cs),[]},none},[{put_chars, unicode, Cs}]}; edit_line1(Cs, {line,P,L,M}) -> edit(Cs, P, L, M, []). @@ -93,14 +93,14 @@ edit([C|Cs], P, {Bef,Aft}, Prefix, Rs0) -> case key_map(C, Prefix) of meta -> edit(Cs, P, {Bef,Aft}, meta, Rs0); - meta_o -> - edit(Cs, P, {Bef,Aft}, meta_o, Rs0); - meta_csi -> - edit(Cs, P, {Bef,Aft}, meta_csi, Rs0); - meta_meta -> - edit(Cs, P, {Bef,Aft}, meta_meta, Rs0); - {csi, _} = Csi -> - edit(Cs, P, {Bef,Aft}, Csi, Rs0); + meta_o -> + edit(Cs, P, {Bef,Aft}, meta_o, Rs0); + meta_csi -> + edit(Cs, P, {Bef,Aft}, meta_csi, Rs0); + meta_meta -> + edit(Cs, P, {Bef,Aft}, meta_meta, Rs0); + {csi, _} = Csi -> + edit(Cs, P, {Bef,Aft}, Csi, Rs0); meta_left_sq_bracket -> edit(Cs, P, {Bef,Aft}, meta_left_sq_bracket, Rs0); search_meta -> @@ -110,8 +110,8 @@ edit([C|Cs], P, {Bef,Aft}, Prefix, Rs0) -> ctlx -> edit(Cs, P, {Bef,Aft}, ctlx, Rs0); new_line -> - {done, reverse(Bef, Aft ++ "\n"), Cs, - reverse(Rs0, [{move_rel,length(Aft)},{put_chars,unicode,"\n"}])}; + {done, get_line(Bef, Aft ++ "\n"), Cs, + reverse(Rs0, [{move_rel,cp_len(Aft)},{put_chars,unicode,"\n"}])}; redraw_line -> Rs1 = erase(P, Bef, Aft, Rs0), Rs = redraw(P, Bef, Aft, Rs1), @@ -157,7 +157,7 @@ edit([], P, L, {blink,N}, Rs) -> edit([], P, L, Prefix, Rs) -> {more_chars,{line,P,L,Prefix},reverse(Rs)}; edit(eof, _, {Bef,Aft}, _, Rs) -> - {done,reverse(Bef, Aft),[],reverse(Rs, [{move_rel,length(Aft)}])}. + {done,get_line(Bef, Aft),[],reverse(Rs, [{move_rel,cp_len(Aft)}])}. %% %% Assumes that arg is a string %% %% Horizontal whitespace only. @@ -279,11 +279,21 @@ key_map(C, search) -> {insert_search,C}; key_map(C, _) -> {undefined,C}. %% do_op(Action, Before, After, Requests) - -do_op({insert,C}, Bef, [], Rs) -> - {{[C|Bef],[]},[{put_chars, unicode,[C]}|Rs]}; -do_op({insert,C}, Bef, Aft, Rs) -> - {{[C|Bef],Aft},[{insert_chars, unicode, [C]}|Rs]}; +%% Before and After are of lists of type string:grapheme_cluster() +do_op({insert,C}, [], [], Rs) -> + {{[C],[]},[{put_chars, unicode,[C]}|Rs]}; +do_op({insert,C}, [Bef|Bef0], [], Rs) -> + case string:to_graphemes([Bef,C]) of + [GC] -> {{[GC|Bef0],[]},[{put_chars, unicode,[C]}|Rs]}; + _ -> {{[C,Bef|Bef0],[]},[{put_chars, unicode,[C]}|Rs]} + end; +do_op({insert,C}, [], Aft, Rs) -> + {{[C],Aft},[{insert_chars, unicode,[C]}|Rs]}; +do_op({insert,C}, [Bef|Bef0], Aft, Rs) -> + case string:to_graphemes([Bef,C]) of + [GC] -> {{[GC|Bef0],Aft},[{insert_chars, unicode,[C]}|Rs]}; + _ -> {{[C,Bef|Bef0],Aft},[{insert_chars, unicode,[C]}|Rs]} + end; %% Search mode prompt always looks like (search)`$TERMS': $RESULT. %% the {insert_search, _} handlings allow to share this implementation %% correctly with group.erl. This module provides $TERMS, and group.erl @@ -299,13 +309,13 @@ do_op({insert_search, C}, Bef, [], Rs) -> [{insert_chars, unicode, [C]++Aft}, {delete_chars,-3} | Rs], search}; do_op({insert_search, C}, Bef, Aft, Rs) -> - Offset= length(Aft), + Offset= cp_len(Aft), NAft = "': ", {{[C|Bef],NAft}, [{insert_chars, unicode, [C]++NAft}, {delete_chars,-Offset} | Rs], search}; do_op({search, backward_delete_char}, [_|Bef], Aft, Rs) -> - Offset= length(Aft)+1, + Offset= cp_len(Aft)+1, NAft = "': ", {{Bef,NAft}, [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], @@ -314,13 +324,13 @@ do_op({search, backward_delete_char}, [], _Aft, Rs) -> Aft="': ", {{[],Aft}, Rs, search}; do_op({search, skip_up}, Bef, Aft, Rs) -> - Offset= length(Aft), + Offset= cp_len(Aft), NAft = "': ", {{[$\^R|Bef],NAft}, % we insert ^R as a flag to whoever called us [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], search}; do_op({search, skip_down}, Bef, Aft, Rs) -> - Offset= length(Aft), + Offset= cp_len(Aft), NAft = "': ", {{[$\^S|Bef],NAft}, % we insert ^S as a flag to whoever called us [{insert_chars, unicode, NAft}, {delete_chars,-Offset}|Rs], @@ -328,12 +338,12 @@ do_op({search, skip_down}, Bef, Aft, Rs) -> do_op({search, search_found}, _Bef, Aft, Rs) -> "': "++NAft = Aft, {{[],NAft}, - [{put_chars, unicode, "\n"}, {move_rel,-length(Aft)} | Rs], + [{put_chars, unicode, "\n"}, {move_rel,-cp_len(Aft)} | Rs], search_found}; do_op({search, search_quit}, _Bef, Aft, Rs) -> "': "++NAft = Aft, {{[],NAft}, - [{put_chars, unicode, "\n"}, {move_rel,-length(Aft)} | Rs], + [{put_chars, unicode, "\n"}, {move_rel,-cp_len(Aft)} | Rs], search_quit}; %% do blink after $$ do_op({blink,C,M}, Bef=[$$,$$|_], Aft, Rs) -> @@ -361,14 +371,16 @@ do_op(auto_blink, Bef, Aft, Rs) -> N -> {blink,N+1,{Bef,Aft}, [{move_rel,-(N+1)}|Rs]} end; -do_op(forward_delete_char, Bef, [_|Aft], Rs) -> - {{Bef,Aft},[{delete_chars,1}|Rs]}; -do_op(backward_delete_char, [_|Bef], Aft, Rs) -> - {{Bef,Aft},[{delete_chars,-1}|Rs]}; +do_op(forward_delete_char, Bef, [GC|Aft], Rs) -> + {{Bef,Aft},[{delete_chars,gc_len(GC)}|Rs]}; +do_op(backward_delete_char, [GC|Bef], Aft, Rs) -> + {{Bef,Aft},[{delete_chars,-gc_len(GC)}|Rs]}; do_op(transpose_char, [C1,C2|Bef], [], Rs) -> - {{[C2,C1|Bef],[]},[{put_chars, unicode,[C1,C2]},{move_rel,-2}|Rs]}; + Len = gc_len(C1)+gc_len(C2), + {{[C2,C1|Bef],[]},[{put_chars, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; do_op(transpose_char, [C2|Bef], [C1|Aft], Rs) -> - {{[C2,C1|Bef],Aft},[{put_chars, unicode,[C1,C2]},{move_rel,-1}|Rs]}; + Len = gc_len(C2), + {{[C2,C1|Bef],Aft},[{put_chars, unicode,[C1,C2]},{move_rel,-Len}|Rs]}; do_op(kill_word, Bef, Aft0, Rs) -> {Aft1,Kill0,N0} = over_non_word(Aft0, [], 0), {Aft,Kill,N} = over_word(Aft1, Kill0, N0), @@ -381,7 +393,7 @@ do_op(backward_kill_word, Bef0, Aft, Rs) -> {{Bef,Aft},[{delete_chars,-N}|Rs]}; do_op(kill_line, Bef, Aft, Rs) -> put(kill_buffer, Aft), - {{Bef,[]},[{delete_chars,length(Aft)}|Rs]}; + {{Bef,[]},[{delete_chars,cp_len(Aft)}|Rs]}; do_op(yank, Bef, [], Rs) -> Kill = get(kill_buffer), {{reverse(Kill, Bef),[]},[{put_chars, unicode,Kill}|Rs]}; @@ -389,9 +401,9 @@ do_op(yank, Bef, Aft, Rs) -> Kill = get(kill_buffer), {{reverse(Kill, Bef),Aft},[{insert_chars, unicode,Kill}|Rs]}; do_op(forward_char, Bef, [C|Aft], Rs) -> - {{[C|Bef],Aft},[{move_rel,1}|Rs]}; + {{[C|Bef],Aft},[{move_rel,gc_len(C)}|Rs]}; do_op(backward_char, [C|Bef], Aft, Rs) -> - {{Bef,[C|Aft]},[{move_rel,-1}|Rs]}; + {{Bef,[C|Aft]},[{move_rel,-gc_len(C)}|Rs]}; do_op(forward_word, Bef0, Aft0, Rs) -> {Aft1,Bef1,N0} = over_non_word(Aft0, Bef0, 0), {Aft,Bef,N} = over_word(Aft1, Bef1, N0), @@ -401,16 +413,16 @@ do_op(backward_word, Bef0, Aft0, Rs) -> {Bef,Aft,N} = over_word(Bef1, Aft1, N0), {{Bef,Aft},[{move_rel,-N}|Rs]}; do_op(beginning_of_line, [C|Bef], Aft, Rs) -> - {{[],reverse(Bef, [C|Aft])},[{move_rel,-(length(Bef)+1)}|Rs]}; + {{[],reverse(Bef, [C|Aft])},[{move_rel,-(cp_len(Bef)+1)}|Rs]}; do_op(beginning_of_line, [], Aft, Rs) -> {{[],Aft},Rs}; do_op(end_of_line, Bef, [C|Aft], Rs) -> - {{reverse(Aft, [C|Bef]),[]},[{move_rel,length(Aft)+1}|Rs]}; + {{reverse(Aft, [C|Bef]),[]},[{move_rel,cp_len(Aft)+1}|Rs]}; do_op(end_of_line, Bef, [], Rs) -> {{Bef,[]},Rs}; do_op(ctlu, Bef, Aft, Rs) -> put(kill_buffer, reverse(Bef)), - {{[], Aft}, [{delete_chars, -length(Bef)} | Rs]}; + {{[], Aft}, [{delete_chars, -cp_len(Bef)} | Rs]}; do_op(beep, Bef, Aft, Rs) -> {{Bef,Aft},[beep|Rs]}; do_op(_, Bef, Aft, Rs) -> @@ -436,7 +448,7 @@ over_word(Cs, Stack, N) -> until_quote([$\'|Cs], Stack, N) -> {Cs, [$\'|Stack], N+1}; until_quote([C|Cs], Stack, N) -> - until_quote(Cs, [C|Stack], N+1). + until_quote(Cs, [C|Stack], N+gc_len(C)). over_word1([$\'=C|Cs], Stack, N) -> until_quote(Cs, [C|Stack], N+1); @@ -445,7 +457,7 @@ over_word1(Cs, Stack, N) -> over_word2([C|Cs], Stack, N) -> case word_char(C) of - true -> over_word2(Cs, [C|Stack], N+1); + true -> over_word2(Cs, [C|Stack], N+gc_len(C)); false -> {[C|Cs],Stack,N} end; over_word2([], Stack, N) when is_integer(N) -> @@ -454,7 +466,7 @@ over_word2([], Stack, N) when is_integer(N) -> over_non_word([C|Cs], Stack, N) -> case word_char(C) of true -> {[C|Cs],Stack,N}; - false -> over_non_word(Cs, [C|Stack], N+1) + false -> over_non_word(Cs, [C|Stack], N+gc_len(C)) end; over_non_word([], Stack, N) -> {[],Stack,N}. @@ -465,6 +477,7 @@ word_char(C) when C >= $a, C =< $z -> true; word_char(C) when C >= $ß, C =< $ÿ, C =/= $÷ -> true; word_char(C) when C >= $0, C =< $9 -> true; word_char(C) when C =:= $_ -> true; +word_char([_|_]) -> true; %% Is grapheme word_char(_) -> false. %% over_white(Chars, InitialStack, InitialCount) -> @@ -488,8 +501,8 @@ over_paren(Chars, Paren, Match) -> over_paren([C,$$,$$|Cs], Paren, Match, D, N, L) -> over_paren([C|Cs], Paren, Match, D, N+2, L); -over_paren([_,$$|Cs], Paren, Match, D, N, L) -> - over_paren(Cs, Paren, Match, D, N+2, L); +over_paren([GC,$$|Cs], Paren, Match, D, N, L) -> + over_paren(Cs, Paren, Match, D, N+1+gc_len(GC), L); over_paren([Match|_], _Paren, Match, 1, N, _) -> N; over_paren([Match|Cs], Paren, Match, D, N, [Match|L]) -> @@ -518,8 +531,8 @@ over_paren([$[|_], _, _, _, _, _) -> over_paren([${|_], _, _, _, _, _) -> beep; -over_paren([_|Cs], Paren, Match, D, N, L) -> - over_paren(Cs, Paren, Match, D, N+1, L); +over_paren([GC|Cs], Paren, Match, D, N, L) -> + over_paren(Cs, Paren, Match, D, N+gc_len(GC), L); over_paren([], _, _, _, _, _) -> 0. @@ -529,8 +542,8 @@ over_paren_auto(Chars) -> over_paren_auto([C,$$,$$|Cs], D, N, L) -> over_paren_auto([C|Cs], D, N+2, L); -over_paren_auto([_,$$|Cs], D, N, L) -> - over_paren_auto(Cs, D, N+2, L); +over_paren_auto([GC,$$|Cs], D, N, L) -> + over_paren_auto(Cs, D, N+1+gc_len(GC), L); over_paren_auto([$(|_], _, N, []) -> {N, $)}; @@ -553,8 +566,8 @@ over_paren_auto([$[|Cs], D, N, [$[|L]) -> over_paren_auto([${|Cs], D, N, [${|L]) -> over_paren_auto(Cs, D, N+1, L); -over_paren_auto([_|Cs], D, N, L) -> - over_paren_auto(Cs, D, N+1, L); +over_paren_auto([GC|Cs], D, N, L) -> + over_paren_auto(Cs, D, N+gc_len(GC), L); over_paren_auto([], _, _, _) -> 0. @@ -574,28 +587,43 @@ erase_inp({line,_,{Bef,Aft},_}) -> reverse(erase([], Bef, Aft, [])). erase(Pbs, Bef, Aft, Rs) -> - [{delete_chars,-length(Pbs)-length(Bef)},{delete_chars,length(Aft)}|Rs]. + [{delete_chars,-cp_len(Pbs)-cp_len(Bef)},{delete_chars,cp_len(Aft)}|Rs]. redraw_line({line,Pbs,{Bef,Aft},_}) -> reverse(redraw(Pbs, Bef, Aft, [])). redraw(Pbs, Bef, Aft, Rs) -> - [{move_rel,-length(Aft)},{put_chars, unicode,reverse(Bef, Aft)},{put_chars, unicode,Pbs}|Rs]. + [{move_rel,-cp_len(Aft)},{put_chars, unicode,reverse(Bef, Aft)},{put_chars, unicode,Pbs}|Rs]. length_before({line,Pbs,{Bef,_Aft},_}) -> - length(Pbs) + length(Bef). + cp_len(Pbs) + cp_len(Bef). length_after({line,_,{_Bef,Aft},_}) -> - length(Aft). + cp_len(Aft). prompt({line,Pbs,_,_}) -> Pbs. current_line({line,_,{Bef, Aft},_}) -> - reverse(Bef, Aft ++ "\n"). + get_line(Bef, Aft ++ "\n"). current_chars({line,_,{Bef,Aft},_}) -> - reverse(Bef, Aft). + get_line(Bef, Aft). + +get_line(Bef, Aft) -> + unicode:characters_to_list(reverse(Bef, Aft)). + +%% Grapheme length in codepoints +gc_len(CP) when is_integer(CP) -> 1; +gc_len(CPs) when is_list(CPs) -> length(CPs). + +%% String length in codepoints +cp_len(Str) -> + cp_len(Str, 0). + +cp_len([GC|R], Len) -> + cp_len(R, Len + gc_len(GC)); +cp_len([], Len) -> Len. %% %% expand(CurrentBefore) -> %% %% {yes,Expansion} | no diff --git a/lib/stdlib/src/edlin_expand.erl b/lib/stdlib/src/edlin_expand.erl index a1a97af4c5..bdcefda6e5 100644 --- a/lib/stdlib/src/edlin_expand.erl +++ b/lib/stdlib/src/edlin_expand.erl @@ -23,7 +23,7 @@ -export([expand/1, format_matches/1]). --import(lists, [reverse/1, nthtail/2, prefix/2]). +-import(lists, [reverse/1, prefix/2]). %% expand(CurrentBefore) -> %% {yes, Expansion, Matches} | {no, Matches} @@ -75,15 +75,15 @@ to_atom(Str) -> end. match(Prefix, Alts, Extra0) -> - Len = length(Prefix), + Len = string:length(Prefix), Matches = lists:sort( [{S, A} || {H, A} <- Alts, - prefix(Prefix, S=hd(io_lib:fwrite("~w",[H])))]), + prefix(Prefix, S=flat_write(H))]), case longest_common_head([N || {N, _} <- Matches]) of {partial, []} -> {no, [], Matches}; % format_matches(Matches)}; {partial, Str} -> - case nthtail(Len, Str) of + case string:slice(Str, Len) of [] -> {yes, [], Matches}; % format_matches(Matches)}; Remain -> @@ -94,18 +94,21 @@ match(Prefix, Alts, Extra0) -> {"(",[{Str,0}]} -> "()"; {_,_} -> Extra0 end, - {yes, nthtail(Len, Str) ++ Extra, []}; + {yes, string:slice(Str, Len) ++ Extra, []}; no -> {no, [], []} end. +flat_write(T) -> + lists:flatten(io_lib:fwrite("~tw",[T])). + %% Return the list of names L in multiple columns. format_matches(L) -> {S1, Dots} = format_col(lists:sort(L), []), S = case Dots of true -> {_, Prefix} = longest_common_head(vals(L)), - PrefixLen = length(Prefix), + PrefixLen = string:length(Prefix), case PrefixLen =< 3 of true -> S1; % Do not replace the prefix with "...". false -> @@ -128,7 +131,7 @@ format_col([A|T], Width, Len, Acc0, LL, Dots) -> {H0, R} = format_val(A), Hmax = LL - length(R), {H, NewDots} = - case length(H0) > Hmax of + case string:length(H0) > Hmax of true -> {io_lib:format("~-*ts", [Hmax - 3, H0]) ++ "...", true}; false -> {H0, Dots} end, @@ -149,12 +152,12 @@ format_val(H) -> field_width(L, LL) -> field_width(L, 0, LL). field_width([{H,_}|T], W, LL) -> - case length(H) of + case string:length(H) of L when L > W -> field_width(T, L, LL); _ -> field_width(T, W, LL) end; field_width([H|T], W, LL) -> - case length(H) of + case string:length(H) of L when L > W -> field_width(T, L, LL); _ -> field_width(T, W, LL) end; @@ -169,10 +172,11 @@ vals([S|L]) -> [S|vals(L)]. leading_dots([], _Len) -> []; leading_dots([{H, I}|L], Len) -> - [{"..." ++ nthtail(Len, H), I}|leading_dots(L, Len)]; + [{"..." ++ string:slice(H, Len), I}|leading_dots(L, Len)]; leading_dots([H|L], Len) -> - ["..." ++ nthtail(Len, H)|leading_dots(L, Len)]. + ["..." ++ string:slice(H, Len)|leading_dots(L, Len)]. +%% Strings are handled naively, but it should be OK here. longest_common_head([]) -> no; longest_common_head(LL) -> diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index fcfd0d8493..9cd4727dc3 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -194,8 +194,6 @@ format_error({bad_nowarn_bif_clash,{F,A}}) -> format_error(disallowed_nowarn_bif_clash) -> io_lib:format("compile directive nowarn_bif_clash is no longer allowed,~n" " - use explicit module names or -compile({no_auto_import, [F/A]})", []); -format_error({bad_nowarn_deprecated_function,{M,F,A}}) -> - io_lib:format("~tw:~tw/~w is not a deprecated function", [M,F,A]); format_error({bad_on_load,Term}) -> io_lib:format("badly formed on_load attribute: ~tw", [Term]); format_error(multiple_on_loads) -> @@ -856,14 +854,11 @@ not_deprecated(Forms, St0) -> {nowarn_deprecated_function, MFAs0} <- lists:flatten([Args]), MFA <- lists:flatten([MFAs0])], Nowarn = [MFA || {MFA,_L} <- MFAsL], - Bad = [MFAL || {{M,F,A},_L}=MFAL <- MFAsL, - otp_internal:obsolete(M, F, A) =:= no], - St1 = func_line_warning(bad_nowarn_deprecated_function, Bad, St0), ML = [{M,L} || {{M,_F,_A},L} <- MFAsL, is_atom(M)], - St3 = foldl(fun ({M,L}, St2) -> + St1 = foldl(fun ({M,L}, St2) -> check_module_name(M, L, St2) - end, St1, ML), - St3#lint{not_deprecated = ordsets:from_list(Nowarn)}. + end, St0, ML), + St1#lint{not_deprecated = ordsets:from_list(Nowarn)}. %% The nowarn_bif_clash directive is not only deprecated, it's actually an error from R14A disallowed_compile_flags(Forms, St0) -> @@ -3243,13 +3238,13 @@ icrt_clauses(Cs, In, Vt, St0) -> icrt_clauses(Cs, Vt, St) -> mapfoldl(fun (C, St0) -> icrt_clause(C, Vt, St0) end, St, Cs). -icrt_clause({clause,_Line,H,G,B}, Vt0, St0) -> +icrt_clause({clause,_Line,H,G,B}, Vt0, #lint{catch_scope=Scope}=St0) -> {Hvt,Binvt,St1} = head(H, Vt0, St0), Vt1 = vtupdate(Hvt, Binvt), {Gvt,St2} = guard(G, vtupdate(Vt1, Vt0), St1), Vt2 = vtupdate(Gvt, Vt1), {Bvt,St3} = exprs(B, vtupdate(Vt2, Vt0), St2), - {vtupdate(Bvt, Vt2),St3}. + {vtupdate(Bvt, Vt2),St3#lint{catch_scope=Scope}}. icrt_export(Vts, Vt, {Tag,Attrs}, St) -> {_File,Loc} = loc(Attrs, St), diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl index b7c193f965..58da0cbdd6 100644 --- a/lib/stdlib/src/error_logger_file_h.erl +++ b/lib/stdlib/src/error_logger_file_h.erl @@ -126,7 +126,7 @@ format_body(State, [{Format,Args}|T]) -> S0 catch _:_ -> - format(State, "ERROR: ~p - ~p\n", [Format,Args]) + format(State, "ERROR: ~tp - ~tp\n", [Format,Args]) end, [S|format_body(State, T)]; format_body(_State, []) -> @@ -165,44 +165,26 @@ parse_event({warning_report, _GL, {Pid, std_warning, Args}}) -> parse_event(_) -> ignore. format_term(Term) when is_list(Term) -> - case string_p(Term) of + case string_p(lists:flatten(Term)) of true -> - [{"~s\n",[Term]}]; + [{"~ts\n",[Term]}]; false -> format_term_list(Term) end; format_term(Term) -> - [{"~p\n",[Term]}]. + [{"~tp\n",[Term]}]. format_term_list([{Tag,Data}|T]) -> - [{" ~p: ~p\n",[Tag,Data]}|format_term_list(T)]; + [{" ~tp: ~tp\n",[Tag,Data]}|format_term_list(T)]; format_term_list([Data|T]) -> - [{" ~p\n",[Data]}|format_term_list(T)]; + [{" ~tp\n",[Data]}|format_term_list(T)]; format_term_list([]) -> - []; -format_term_list(_) -> - %% Continue to allow non-proper lists for now. - %% FIXME: Remove this clause in OTP 19. []. string_p([]) -> false; -string_p(Term) -> - string_p1(Term). - -string_p1([H|T]) when is_integer(H), H >= $\s, H < 255 -> - string_p1(T); -string_p1([$\n|T]) -> string_p1(T); -string_p1([$\r|T]) -> string_p1(T); -string_p1([$\t|T]) -> string_p1(T); -string_p1([$\v|T]) -> string_p1(T); -string_p1([$\b|T]) -> string_p1(T); -string_p1([$\f|T]) -> string_p1(T); -string_p1([$\e|T]) -> string_p1(T); -string_p1([H|T]) when is_list(H) -> - string_p1(H) andalso string_p1(T); -string_p1([]) -> true; -string_p1(_) -> false. +string_p(FlatList) -> + io_lib:printable_list(FlatList). get_utc_config() -> %% SASL utc_log configuration overrides stdlib config @@ -225,7 +207,7 @@ header(Time, Title) -> end. header({{Y,Mo,D},{H,Mi,S}}, Title, UTC) -> - io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ~s===~n", + io_lib:format("~n=~ts==== ~p-~s-~p::~s:~s:~s ~s===~n", [Title,D,month(Mo),Y,t(H),t(Mi),t(S),UTC]). t(X) when is_integer(X) -> diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl index 8f0d7b0362..fa940b7264 100644 --- a/lib/stdlib/src/error_logger_tty_h.erl +++ b/lib/stdlib/src/error_logger_tty_h.erl @@ -39,13 +39,16 @@ {user, prev_handler, io_mod=io, - depth=unlimited}). + depth=unlimited, + modifier=""}). %% This one is used when we takeover from the simple error_logger. init({[], {error_logger, Buf}}) -> User = set_group_leader(), Depth = error_logger:get_format_depth(), - State = #st{user=User,prev_handler=error_logger,depth=Depth}, + Modifier = modifier(), + State = #st{user=User,prev_handler=error_logger, + depth=Depth,modifier=Modifier}, write_events(State, Buf), {ok, State}; %% This one is used if someone took over from us, and now wants to @@ -57,7 +60,8 @@ init({[], {error_logger_tty_h, PrevHandler}}) -> init([]) -> User = set_group_leader(), Depth = error_logger:get_format_depth(), - {ok, #st{user=User,prev_handler=[],depth=Depth}}. + Modifier = modifier(), + {ok, #st{user=User,prev_handler=[],depth=Depth,modifier=Modifier}}. handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() -> {ok, State}; @@ -91,8 +95,9 @@ code_change(_OldVsn, State, _Extra) -> write_event(Event, IoMod) -> do_write_event(#st{io_mod=IoMod}, Event). -write_event(Event, IoMod, Depth) -> - do_write_event(#st{io_mod=IoMod,depth=Depth}, Event). +write_event(Event, IoMod, {Depth, Enc}) -> + Modifier = modifier(Enc), + do_write_event(#st{io_mod=IoMod,depth=Depth,modifier=Modifier}, Event). %%% ------------------------------------------------------ @@ -120,12 +125,12 @@ write_events(State, [Ev|Es]) -> write_events(_State, []) -> ok. -do_write_event(State, {Time, Event}) -> - case parse_event(Event) of +do_write_event(#st{modifier=M}=State, {Time, Event}) -> + case parse_event(Event,M) of ignore -> ok; {Title,Pid,FormatList} -> - Header = header(Time, Title), + Header = header(Time, Title, M), Body = format_body(State, FormatList), AtNode = if node(Pid) =/= node() -> @@ -144,13 +149,13 @@ do_write_event(State, {Time, Event}) -> do_write_event(_, _) -> ok. -format_body(State, [{Format,Args}|T]) -> +format_body(#st{modifier=M}=State, [{Format,Args}|T]) -> S = try format(State, Format, Args) of S0 -> S0 catch _:_ -> - format(State, "ERROR: ~p - ~p\n", [Format,Args]) + format(State, "ERROR: ~"++M++"p - ~"++M++"p\n", [Format,Args]) end, [S|format_body(State, T)]; format_body(_State, []) -> @@ -174,62 +179,41 @@ limit_format([H|T], Depth) -> limit_format([], _) -> []. -parse_event({error, _GL, {Pid, Format, Args}}) -> +parse_event({error, _GL, {Pid, Format, Args}},_) -> {"ERROR REPORT",Pid,[{Format,Args}]}; -parse_event({info_msg, _GL, {Pid, Format, Args}}) -> +parse_event({info_msg, _GL, {Pid, Format, Args}},_) -> {"INFO REPORT",Pid,[{Format, Args}]}; -parse_event({warning_msg, _GL, {Pid, Format, Args}}) -> +parse_event({warning_msg, _GL, {Pid, Format, Args}},_) -> {"WARNING REPORT",Pid,[{Format,Args}]}; -parse_event({error_report, _GL, {Pid, std_error, Args}}) -> - {"ERROR REPORT",Pid,format_term(Args)}; -parse_event({info_report, _GL, {Pid, std_info, Args}}) -> - {"INFO REPORT",Pid,format_term(Args)}; -parse_event({warning_report, _GL, {Pid, std_warning, Args}}) -> - {"WARNING REPORT",Pid,format_term(Args)}; -parse_event(_) -> ignore. - -format_term(Term) when is_list(Term) -> - case string_p(Term) of +parse_event({error_report, _GL, {Pid, std_error, Args}},M) -> + {"ERROR REPORT",Pid,format_term(Args,M)}; +parse_event({info_report, _GL, {Pid, std_info, Args}},M) -> + {"INFO REPORT",Pid,format_term(Args,M)}; +parse_event({warning_report, _GL, {Pid, std_warning, Args}},M) -> + {"WARNING REPORT",Pid,format_term(Args,M)}; +parse_event(_,_) -> ignore. + +format_term(Term,M) when is_list(Term) -> + case string_p(lists:flatten(Term)) of true -> - [{"~s\n",[Term]}]; + [{"~"++M++"s\n",[Term]}]; false -> - format_term_list(Term) + format_term_list(Term,M) end; -format_term(Term) -> - [{"~p\n",[Term]}]. - -format_term_list([{Tag,Data}|T]) -> - [{" ~p: ~p\n",[Tag,Data]}|format_term_list(T)]; -format_term_list([Data|T]) -> - [{" ~p\n",[Data]}|format_term_list(T)]; -format_term_list([]) -> - []; -format_term_list(_) -> - %% Continue to allow non-proper lists for now. - %% FIXME: Remove this clause in OTP 19. +format_term(Term,M) -> + [{"~"++M++"p\n",[Term]}]. + +format_term_list([{Tag,Data}|T],M) -> + [{" ~"++M++"p: ~"++M++"p\n",[Tag,Data]}|format_term_list(T,M)]; +format_term_list([Data|T],M) -> + [{" ~"++M++"p\n",[Data]}|format_term_list(T,M)]; +format_term_list([],_) -> []. string_p([]) -> false; -string_p(Term) -> - string_p1(Term). - -string_p1([H|T]) when is_integer(H), H >= $\s, H < 255 -> - string_p1(T); -string_p1([$\n|T]) -> string_p1(T); -string_p1([$\r|T]) -> string_p1(T); -string_p1([$\t|T]) -> string_p1(T); -string_p1([$\v|T]) -> string_p1(T); -string_p1([$\b|T]) -> string_p1(T); -string_p1([$\f|T]) -> string_p1(T); -string_p1([$\e|T]) -> string_p1(T); -string_p1([H|T]) when is_list(H) -> - case string_p1(H) of - true -> string_p1(T); - _ -> false - end; -string_p1([]) -> true; -string_p1(_) -> false. +string_p(FlatList) -> + io_lib:printable_list(FlatList). get_utc_config() -> %% SASL utc_log configuration overrides stdlib config @@ -243,16 +227,16 @@ get_utc_config() -> end end. -header(Time, Title) -> +header(Time, Title, M) -> case get_utc_config() of true -> - header(Time, Title, "UTC "); + header(Time, Title, "UTC ", M); _ -> - header(calendar:universal_time_to_local_time(Time), Title, "") + header(calendar:universal_time_to_local_time(Time), Title, "", M) end. -header({{Y,Mo,D},{H,Mi,S}}, Title, UTC) -> - io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ~s===~n", +header({{Y,Mo,D},{H,Mi,S}}, Title, UTC, M) -> + io_lib:format("~n=~"++M++"s==== ~p-~s-~p::~s:~s:~s ~s===~n", [Title,D,month(Mo),Y,t(H),t(Mi),t(S),UTC]). t(X) when is_integer(X) -> @@ -274,3 +258,13 @@ month(9) -> "Sep"; month(10) -> "Oct"; month(11) -> "Nov"; month(12) -> "Dec". + +modifier() -> + modifier(encoding()). +modifier(latin1) -> + ""; +modifier(_) -> + "t". + +encoding() -> + proplists:get_value(encoding,io:getopts(),latin1). diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl index 2093916a7c..2b9d8ff65b 100644 --- a/lib/stdlib/src/escript.erl +++ b/lib/stdlib/src/escript.erl @@ -860,7 +860,7 @@ code_handler(Name, Args, Dict, File) -> %% io:format("Calling:~p~n",[{Mod,Name,Args}]), apply(Mod, Name, Args); error -> - io:format("Script does not export ~w/~w\n", [Name,Arity]), + io:format("Script does not export ~tw/~w\n", [Name,Arity]), my_halt(127) end end. diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl index 898b2f5bba..b5d3cd3c8d 100644 --- a/lib/stdlib/src/ets.erl +++ b/lib/stdlib/src/ets.erl @@ -1693,7 +1693,7 @@ choice(Height, Width, P, Mode, Tab, Key, Turn, Opos) -> end, choice(Height, Width, P, Mode, Tab, Key, Turn, Opos); [$/|Regexp] -> %% from regexp - case re:compile(nonl(Regexp)) of + case re:compile(nonl(Regexp),[unicode]) of {ok,Re} -> re_search(Height, Width, Tab, ets:first(Tab), Re, 1, 1); {error,{ErrorString,_Pos}} -> diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl index 32f43fc706..33af0aed8f 100644 --- a/lib/stdlib/src/gen.erl +++ b/lib/stdlib/src/gen.erl @@ -422,7 +422,7 @@ debug_options(Name, Opts) -> try sys:debug_options(Options) catch _:_ -> error_logger:format( - "~p: ignoring erroneous debug options - ~p~n", + "~tp: ignoring erroneous debug options - ~tp~n", [Name,Options]), [] end; diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl index da2b0da3ca..a9b98911e2 100644 --- a/lib/stdlib/src/gen_event.erl +++ b/lib/stdlib/src/gen_event.erl @@ -441,15 +441,15 @@ system_replace_state(StateFun, [ServerName, MSL, HibernateAfterTimeout, Hib]) -> print_event(Dev, {in, Msg}, Name) -> case Msg of {notify, Event} -> - io:format(Dev, "*DBG* ~p got event ~p~n", [Name, Event]); + io:format(Dev, "*DBG* ~tp got event ~tp~n", [Name, Event]); {_,_,{call, Handler, Query}} -> - io:format(Dev, "*DBG* ~p(~p) got call ~p~n", + io:format(Dev, "*DBG* ~tp(~tp) got call ~tp~n", [Name, Handler, Query]); _ -> - io:format(Dev, "*DBG* ~p got ~p~n", [Name, Msg]) + io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg]) end; print_event(Dev, Dbg, Name) -> - io:format(Dev, "*DBG* ~p : ~p~n", [Name, Dbg]). + io:format(Dev, "*DBG* ~tp : ~tp~n", [Name, Dbg]). %% server_add_handler(Handler, Args, MSL) -> {Ret, MSL'}. @@ -582,8 +582,8 @@ server_update(Handler1, Func, Event, SName) -> remove, SName, normal), no; {'EXIT', {undef, [{Mod1, handle_info, [_,_], _}|_]}} -> - error_logger:warning_msg("** Undefined handle_info in ~p~n" - "** Unhandled message: ~p~n", [Mod1, Event]), + error_logger:warning_msg("** Undefined handle_info in ~tp~n" + "** Unhandled message: ~tp~n", [Mod1, Event]), {ok, Handler1}; Other -> do_terminate(Mod1, Handler1, {error, Other}, State, @@ -767,10 +767,10 @@ report_error(Handler, Reason, State, LastIn, SName) -> State end, error_msg("** gen_event handler ~p crashed.~n" - "** Was installed in ~p~n" - "** Last event was: ~p~n" - "** When handler state == ~p~n" - "** Reason == ~p~n", + "** Was installed in ~tp~n" + "** Last event was: ~tp~n" + "** When handler state == ~tp~n" + "** Reason == ~tp~n", [handler(Handler),SName,LastIn,FmtState,Reason1]). handler(Handler) when not Handler#handler.id -> diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index 9ef0ca818c..96a53426e2 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -452,30 +452,30 @@ system_replace_state(StateFun, [Name, StateName, StateData, Mod, Time, Hibernate print_event(Dev, {in, Msg}, {Name, StateName}) -> case Msg of {'$gen_event', Event} -> - io:format(Dev, "*DBG* ~p got event ~p in state ~w~n", + io:format(Dev, "*DBG* ~tp got event ~tp in state ~tw~n", [Name, Event, StateName]); {'$gen_all_state_event', Event} -> io:format(Dev, - "*DBG* ~p got all_state_event ~p in state ~w~n", + "*DBG* ~tp got all_state_event ~tp in state ~tw~n", [Name, Event, StateName]); {timeout, Ref, {'$gen_timer', Message}} -> io:format(Dev, - "*DBG* ~p got timer ~p in state ~w~n", + "*DBG* ~tp got timer ~tp in state ~tw~n", [Name, {timeout, Ref, Message}, StateName]); {timeout, _Ref, {'$gen_event', Event}} -> io:format(Dev, - "*DBG* ~p got timer ~p in state ~w~n", + "*DBG* ~tp got timer ~tp in state ~tw~n", [Name, Event, StateName]); _ -> - io:format(Dev, "*DBG* ~p got ~p in state ~w~n", + io:format(Dev, "*DBG* ~tp got ~tp in state ~tw~n", [Name, Msg, StateName]) end; print_event(Dev, {out, Msg, To, StateName}, Name) -> - io:format(Dev, "*DBG* ~p sent ~p to ~w~n" - " and switched to state ~w~n", + io:format(Dev, "*DBG* ~tp sent ~tp to ~tw~n" + " and switched to state ~tw~n", [Name, Msg, To, StateName]); print_event(Dev, return, {Name, StateName}) -> - io:format(Dev, "*DBG* ~p switched to state ~w~n", + io:format(Dev, "*DBG* ~tp switched to state ~tw~n", [Name, StateName]). handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, HibernateAfterTimeout) -> %No debug here @@ -500,7 +500,7 @@ handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, HibernateAfterTi exit(R); {'EXIT', {undef, [{Mod, handle_info, [_,_,_], _}|_]}} -> error_logger:warning_msg("** Undefined handle_info in ~p~n" - "** Unhandled message: ~p~n", [Mod, Msg]), + "** Unhandled message: ~tp~n", [Mod, Msg]), loop(Parent, Name, StateName, StateData, Mod, infinity, HibernateAfterTimeout, []); {'EXIT', What} -> terminate(What, Name, Msg, Mod, StateName, StateData, []); @@ -620,29 +620,29 @@ error_info(Reason, Name, Msg, StateName, StateData, Debug) -> _ -> Reason end, - Str = "** State machine ~p terminating \n" ++ + Str = "** State machine ~tp terminating \n" ++ get_msg_str(Msg) ++ - "** When State == ~p~n" - "** Data == ~p~n" - "** Reason for termination = ~n** ~p~n", + "** When State == ~tp~n" + "** Data == ~tp~n" + "** Reason for termination = ~n** ~tp~n", format(Str, [Name, get_msg(Msg), StateName, StateData, Reason1]), sys:print_log(Debug), ok. get_msg_str({'$gen_event', _Event}) -> - "** Last event in was ~p~n"; + "** Last event in was ~tp~n"; get_msg_str({'$gen_sync_event', _Event}) -> - "** Last sync event in was ~p~n"; + "** Last sync event in was ~tp~n"; get_msg_str({'$gen_all_state_event', _Event}) -> - "** Last event in was ~p (for all states)~n"; + "** Last event in was ~tp (for all states)~n"; get_msg_str({'$gen_sync_all_state_event', _Event}) -> - "** Last sync event in was ~p (for all states)~n"; + "** Last sync event in was ~tp (for all states)~n"; get_msg_str({timeout, _Ref, {'$gen_timer', _Msg}}) -> - "** Last timer event in was ~p~n"; + "** Last timer event in was ~tp~n"; get_msg_str({timeout, _Ref, {'$gen_event', _Msg}}) -> - "** Last timer event in was ~p~n"; + "** Last timer event in was ~tp~n"; get_msg_str(_Msg) -> - "** Last message in was ~p~n". + "** Last message in was ~tp~n". get_msg({'$gen_event', Event}) -> Event; get_msg({'$gen_sync_event', Event}) -> Event; diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index a3d53efd0d..7daa7a9fe4 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -621,7 +621,7 @@ try_dispatch(Mod, Func, Msg, State) -> case erlang:function_exported(Mod, handle_info, 2) of false -> error_logger:warning_msg("** Undefined handle_info in ~p~n" - "** Unhandled message: ~p~n", + "** Unhandled message: ~tp~n", [Mod, Msg]), {ok, {noreply, State}}; true -> @@ -785,21 +785,21 @@ system_replace_state(StateFun, [Name, State, Mod, Time, HibernateAfterTimeout]) print_event(Dev, {in, Msg}, Name) -> case Msg of {'$gen_call', {From, _Tag}, Call} -> - io:format(Dev, "*DBG* ~p got call ~p from ~w~n", + io:format(Dev, "*DBG* ~tp got call ~tp from ~w~n", [Name, Call, From]); {'$gen_cast', Cast} -> - io:format(Dev, "*DBG* ~p got cast ~p~n", + io:format(Dev, "*DBG* ~tp got cast ~tp~n", [Name, Cast]); _ -> - io:format(Dev, "*DBG* ~p got ~p~n", [Name, Msg]) + io:format(Dev, "*DBG* ~tp got ~tp~n", [Name, Msg]) end; print_event(Dev, {out, Msg, To, State}, Name) -> - io:format(Dev, "*DBG* ~p sent ~p to ~w, new state ~w~n", + io:format(Dev, "*DBG* ~tp sent ~tp to ~w, new state ~tp~n", [Name, Msg, To, State]); print_event(Dev, {noreply, State}, Name) -> - io:format(Dev, "*DBG* ~p new state ~w~n", [Name, State]); + io:format(Dev, "*DBG* ~tp new state ~tp~n", [Name, State]); print_event(Dev, Event, Name) -> - io:format(Dev, "*DBG* ~p dbg ~p~n", [Name, Event]). + io:format(Dev, "*DBG* ~tp dbg ~tp~n", [Name, Event]). %%% --------------------------------------------------- @@ -881,10 +881,10 @@ error_info(Reason, Name, From, Msg, State, Debug) -> end, {ClientFmt, ClientArgs} = client_stacktrace(From), LimitedState = error_logger:limit_term(State), - error_logger:format("** Generic server ~p terminating \n" - "** Last message in was ~p~n" - "** When Server state == ~p~n" - "** Reason for termination == ~n** ~p~n" ++ ClientFmt, + error_logger:format("** Generic server ~tp terminating \n" + "** Last message in was ~tp~n" + "** When Server state == ~tp~n" + "** Reason for termination == ~n** ~tp~n" ++ ClientFmt, [Name, Msg, LimitedState, Reason1] ++ ClientArgs), sys:print_log(Debug), ok. @@ -898,11 +898,11 @@ client_stacktrace(From) when is_pid(From), node(From) =:= node() -> {"** Client ~p is dead~n", [From]}; [{current_stacktrace, Stacktrace}, {registered_name, []}] -> {"** Client ~p stacktrace~n" - "** ~p~n", + "** ~tp~n", [From, Stacktrace]}; [{current_stacktrace, Stacktrace}, {registered_name, Name}] -> - {"** Client ~p stacktrace~n" - "** ~p~n", + {"** Client ~tp stacktrace~n" + "** ~tp~n", [Name, Stacktrace]} end; client_stacktrace(From) when is_pid(From) -> diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl index b5e9da1e66..1110d18af6 100644 --- a/lib/stdlib/src/gen_statem.erl +++ b/lib/stdlib/src/gen_statem.erl @@ -791,34 +791,34 @@ format_status( print_event(Dev, {in,Event}, {Name,State}) -> io:format( - Dev, "*DBG* ~p receive ~s in state ~p~n", + Dev, "*DBG* ~tp receive ~ts in state ~tp~n", [Name,event_string(Event),State]); print_event(Dev, {out,Reply,{To,_Tag}}, {Name,State}) -> io:format( - Dev, "*DBG* ~p send ~p to ~p from state ~p~n", + Dev, "*DBG* ~tp send ~tp to ~p from state ~tp~n", [Name,Reply,To,State]); print_event(Dev, {terminate,Reason}, {Name,State}) -> io:format( - Dev, "*DBG* ~p terminate ~p in state ~p~n", + Dev, "*DBG* ~tp terminate ~tp in state ~tp~n", [Name,Reason,State]); print_event(Dev, {Tag,Event,NextState}, {Name,State}) -> StateString = case NextState of State -> - io_lib:format("~p", [State]); + io_lib:format("~tp", [State]); _ -> - io_lib:format("~p => ~p", [State,NextState]) + io_lib:format("~tp => ~tp", [State,NextState]) end, io:format( - Dev, "*DBG* ~p ~w ~s in state ~s~n", + Dev, "*DBG* ~tp ~tw ~ts in state ~ts~n", [Name,Tag,event_string(Event),StateString]). event_string(Event) -> case Event of {{call,{Pid,_Tag}},Request} -> - io_lib:format("call ~p from ~w", [Request,Pid]); + io_lib:format("call ~tp from ~w", [Request,Pid]); {EventType,EventContent} -> - io_lib:format("~w ~p", [EventType,EventContent]) + io_lib:format("~tw ~tp", [EventType,EventContent]) end. sys_debug(Debug, #{name := Name}, State, Entry) -> @@ -1732,25 +1732,25 @@ error_info( CallbackMode end, error_logger:format( - "** State machine ~p terminating~n" ++ + "** State machine ~tp terminating~n" ++ case Q of [] -> ""; - _ -> "** Last event = ~p~n" + _ -> "** Last event = ~tp~n" end ++ - "** When server state = ~p~n" ++ - "** Reason for termination = ~w:~p~n" ++ + "** When server state = ~tp~n" ++ + "** Reason for termination = ~w:~tp~n" ++ "** Callback mode = ~p~n" ++ case Q of - [_,_|_] -> "** Queued = ~p~n"; + [_,_|_] -> "** Queued = ~tp~n"; _ -> "" end ++ case P of [] -> ""; - _ -> "** Postponed = ~p~n" + _ -> "** Postponed = ~tp~n" end ++ case FixedStacktrace of [] -> ""; - _ -> "** Stacktrace =~n** ~p~n" + _ -> "** Stacktrace =~n** ~tp~n" end, [Name | case Q of diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 9e9c0dc413..c59db903dc 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -63,9 +63,9 @@ obsolete_1(gen_fsm, start, 4) -> {deprecated, {gen_statem, start, 4}}; obsolete_1(gen_fsm, start_link, 3) -> - {deprecated, {gen_statem, start, 3}}; + {deprecated, {gen_statem, start_link, 3}}; obsolete_1(gen_fsm, start_link, 4) -> - {deprecated, {gen_statem, start, 4}}; + {deprecated, {gen_statem, start_link, 4}}; obsolete_1(gen_fsm, stop, 1) -> {deprecated, {gen_statem, stop, 1}}; @@ -83,9 +83,9 @@ obsolete_1(gen_fsm, reply, 2) -> {deprecated, {gen_statem, reply, 2}}; obsolete_1(gen_fsm, send_event, 2) -> - {deprecated, {gen_statem, cast, 1}}; + {deprecated, {gen_statem, cast, 2}}; obsolete_1(gen_fsm, send_all_state_event, 2) -> - {deprecated, {gen_statem, cast, 1}}; + {deprecated, {gen_statem, cast, 2}}; obsolete_1(gen_fsm, sync_send_event, 2) -> {deprecated, {gen_statem, call, 2}}; @@ -98,11 +98,11 @@ obsolete_1(gen_fsm, sync_send_all_state_event, 3) -> {deprecated, {gen_statem, call, 3}}; obsolete_1(gen_fsm, start_timer, 2) -> - {deprecated, {erlang, start_timer, 2}}; + {deprecated, {erlang, start_timer, 3}}; obsolete_1(gen_fsm, cancel_timer, 1) -> {deprecated, {erlang, cancel_timer, 1}}; obsolete_1(gen_fsm, send_event_after, 2) -> - {deprecated, {erlang, send_after, 2}}; + {deprecated, {erlang, send_after, 3}}; %% *** CRYPTO added in OTP 20 *** @@ -112,7 +112,7 @@ obsolete_1(crypto, rand_uniform, 2) -> %% *** CRYPTO added in OTP 19 *** obsolete_1(crypto, rand_bytes, 1) -> - {deprecated, {crypto, strong_rand_bytes, 1}}; + {removed, {crypto, strong_rand_bytes, 1}, "20.0"}; %% *** CRYPTO added in R16B01 *** @@ -485,10 +485,6 @@ obsolete_1(wxPaintDC, new, 0) -> {deprecated,"deprecated function not available in wxWidgets-2.9 and later"}; obsolete_1(wxWindowDC, new, 0) -> {deprecated,"deprecated function not available in wxWidgets-2.9 and later"}; -obsolete_1(wxGraphicsContext, createLinearGradientBrush, 7) -> - {deprecated,"deprecated function not available in wxWidgets-2.9 and later"}; -obsolete_1(wxGraphicsContext, createRadialGradientBrush, 8) -> - {deprecated,"deprecated function not available in wxWidgets-2.9 and later"}; obsolete_1(wxGraphicsRenderer, createLinearGradientBrush, 7) -> {deprecated,"deprecated function not available in wxWidgets-2.9 and later"}; obsolete_1(wxGraphicsRenderer, createRadialGradientBrush, 8) -> diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl index 9ce8e7d60e..8e10cbe93b 100644 --- a/lib/stdlib/src/proc_lib.erl +++ b/lib/stdlib/src/proc_lib.erl @@ -779,11 +779,13 @@ format_link_report([Link|Reps], Indent, Extra) -> LinkIndent = [" ",Indent], [Indent,"neighbour:\n",format_report(Rep, LinkIndent, Extra)| format_link_report(Reps, Indent, Extra)]; -format_link_report([], _, _) -> - []. +format_link_report(Rep, Indent, Extra) -> + format_report(Rep, Indent, Extra). format_report(Rep, Indent, Extra) when is_list(Rep) -> format_rep(Rep, Indent, Extra); +format_report(Rep, Indent, {Enc,unlimited}) -> + io_lib:format("~s~"++modifier(Enc)++"p~n", [Indent, Rep]); format_report(Rep, Indent, {Enc,Depth}) -> io_lib:format("~s~"++modifier(Enc)++"P~n", [Indent, Rep, Depth]). @@ -821,22 +823,22 @@ to_string(A, _) -> io_lib:write_atom(A). pp_fun({Enc,Depth}) -> - {Letter,Tl} = case Depth of - unlimited -> {"p",[]}; - _ -> {"P",[Depth]} - end, - P = modifier(Enc) ++ Letter, + {P,Tl} = p(Enc, Depth), fun(Term, I) -> io_lib:format("~." ++ integer_to_list(I) ++ P, [Term|Tl]) end. -format_tag(Indent, Tag, Data, {_Enc,Depth}) -> - case Depth of - unlimited -> - io_lib:format("~s~p: ~80.18p~n", [Indent, Tag, Data]); - _ -> - io_lib:format("~s~p: ~80.18P~n", [Indent, Tag, Data, Depth]) - end. +format_tag(Indent, Tag, Data, {Enc,Depth}) -> + {P,Tl} = p(Enc, Depth), + io_lib:format("~s~p: ~80.18" ++ P ++ "\n", [Indent, Tag, Data|Tl]). + +p(Encoding, Depth) -> + {Letter, Tl} = case Depth of + unlimited -> {"p", []}; + _ -> {"P", [Depth]} + end, + P = modifier(Encoding) ++ Letter, + {P, Tl}. modifier(latin1) -> ""; modifier(_) -> "t". diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl index 535ca57a6b..f11f9d0a0b 100644 --- a/lib/stdlib/src/qlc.erl +++ b/lib/stdlib/src/qlc.erl @@ -1132,7 +1132,7 @@ wait_for_request(Parent, MonRef, Post) -> wait_for_request(Parent, MonRef, Post); Other -> error_logger:error_msg( - "The qlc cursor ~w received an unexpected message:\n~p\n", + "The qlc cursor ~w received an unexpected message:\n~tp\n", [self(), Other]), wait_for_request(Parent, MonRef, Post) end. diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl index 6eafc7b209..212b143b1d 100644 --- a/lib/stdlib/src/shell.erl +++ b/lib/stdlib/src/shell.erl @@ -727,7 +727,7 @@ result_will_be_saved() -> used_record_defs(E, RT) -> %% Be careful to return a list where used records come before %% records that use them. The linter wants them ordered that way. - UR = case used_records(E, [], RT) of + UR = case used_records(E, [], RT, []) of [] -> []; L0 -> @@ -737,13 +737,19 @@ used_record_defs(E, RT) -> end, record_defs(RT, UR). -used_records(E, U0, RT) -> +used_records(E, U0, RT, Skip) -> case used_records(E) of {name,Name,E1} -> - U = used_records(ets:lookup(RT, Name), [Name | U0], RT), - used_records(E1, U, RT); + U = case lists:member(Name, Skip) of + true -> + U0; + false -> + R = ets:lookup(RT, Name), + used_records(R, [Name | U0], RT, [Name | Skip]) + end, + used_records(E1, U, RT, Skip); {expr,[E1 | Es]} -> - used_records(Es, used_records(E1, U0, RT), RT); + used_records(Es, used_records(E1, U0, RT, Skip), RT, Skip); _ -> U0 end. @@ -1453,7 +1459,7 @@ check_env(V) -> {ok, Val} -> Txt = io_lib:fwrite ("Invalid value of STDLIB configuration parameter" - "~w: ~tp\n", [V, Val]), + "~tw: ~tp\n", [V, Val]), error_logger:info_report(lists:flatten(Txt)) end. diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl index 5b5c328c0c..d7cf6386f5 100644 --- a/lib/stdlib/src/slave.erl +++ b/lib/stdlib/src/slave.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -77,7 +77,7 @@ start_pseudo(_,_,_) -> ok. %% It's already there Pid :: pid(). relay({badrpc,Reason}) -> - error_msg(" ** exiting relay server ~w :~w **~n", [self(),Reason]), + error_msg(" ** exiting relay server ~w :~tw **~n", [self(),Reason]), exit(Reason); relay(undefined) -> error_msg(" ** exiting relay server ~w **~n", [self()]), diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl index 6f7009b5d9..4972da297d 100644 --- a/lib/stdlib/src/string.erl +++ b/lib/stdlib/src/string.erl @@ -384,7 +384,7 @@ to_float(String) -> end. to_number(String, Number, Rest, List, _Tail) when is_binary(String) -> - BSz = length(List)-length(Rest), + BSz = erlang:length(List)-erlang:length(Rest), <<_:BSz/binary, Cont/binary>> = String, {Number, Cont}; to_number(_, Number, Rest, _, Tail) -> @@ -1344,7 +1344,7 @@ bin_search_str(Bin0, Start, Cont, [CP|_]=SearchCPs) -> String :: string(), Length :: non_neg_integer(). -len(S) -> length(S). +len(S) -> erlang:length(S). %% equal(String1, String2) %% Test if 2 strings are equal. @@ -1689,7 +1689,7 @@ left(String, Len) when is_integer(Len) -> left(String, Len, $\s). Character :: char(). left(String, Len, Char) when is_integer(Char) -> - Slen = length(String), + Slen = erlang:length(String), if Slen > Len -> substr(String, 1, Len); Slen < Len -> l_pad(String, Len-Slen, Char); @@ -1714,7 +1714,7 @@ right(String, Len) when is_integer(Len) -> right(String, Len, $\s). Character :: char(). right(String, Len, Char) when is_integer(Char) -> - Slen = length(String), + Slen = erlang:length(String), if Slen > Len -> substr(String, Slen-Len+1); Slen < Len -> r_pad(String, Len-Slen, Char); @@ -1741,7 +1741,7 @@ centre(String, Len) when is_integer(Len) -> centre(String, Len, $\s). centre(String, 0, Char) when is_list(String), is_integer(Char) -> []; % Strange cases to centre string centre(String, Len, Char) when is_integer(Char) -> - Slen = length(String), + Slen = erlang:length(String), if Slen > Len -> substr(String, (Slen-Len) div 2 + 1, Len); Slen < Len -> diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 1cd65fbf18..7920e55930 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2016. All Rights Reserved. +%% Copyright Ericsson AB 1996-2017. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -628,7 +628,7 @@ handle_info({'EXIT', Pid, Reason}, State) -> end; handle_info(Msg, State) -> - error_logger:error_msg("Supervisor received unexpected message: ~p~n", + error_logger:error_msg("Supervisor received unexpected message: ~tp~n", [Msg]), {noreply, State}. diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index 72211332e9..7b79dcf04d 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -36,6 +36,7 @@ MODULES= \ ets_tough_SUITE \ expand_test \ expand_test1 \ + unicode_expand \ ExpandTestCaps \ ExpandTestCaps1 \ filelib_SUITE \ diff --git a/lib/stdlib/test/c_SUITE.erl b/lib/stdlib/test/c_SUITE.erl index 4bd32a30f8..f01988478c 100644 --- a/lib/stdlib/test/c_SUITE.erl +++ b/lib/stdlib/test/c_SUITE.erl @@ -21,7 +21,9 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). -export([c_1/1, c_2/1, c_3/1, c_4/1, nc_1/1, nc_2/1, nc_3/1, nc_4/1, - ls/1, memory/1]). + c_default_outdir_1/1, c_default_outdir_2/1, + nc_default_outdir_1/1, nc_default_outdir_2/1, + ls/1, memory/1]). -include_lib("common_test/include/ct.hrl"). @@ -30,7 +32,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [c_1, c_2, c_3, c_4, nc_1, nc_2, nc_3, nc_4, ls, memory]. + [c_1, c_2, c_3, c_4, nc_1, nc_2, nc_3, nc_4, + c_default_outdir_1, c_default_outdir_2, + nc_default_outdir_1, nc_default_outdir_2, + ls, memory]. groups() -> []. @@ -124,6 +129,50 @@ nc_4(Config) when is_list(Config) -> Result = nc(R,[{outdir,W}]), {ok, m} = Result. +c_default_outdir_1(Config) -> + R = filename:join(proplists:get_value(data_dir, Config), "m.erl"), + W = proplists:get_value(priv_dir, Config), + file:set_cwd(W), + Obj = "m" ++ code:objfile_extension(), + _ = file:delete(Obj), + false = filelib:is_file(Obj), + Result = c:c(R), + {ok, m} = Result, + true = filelib:is_file(Obj). + +c_default_outdir_2(Config) -> + R = filename:join(proplists:get_value(data_dir, Config), "m"), + W = proplists:get_value(priv_dir, Config), + file:set_cwd(W), + Obj = "m" ++ code:objfile_extension(), + _ = file:delete(Obj), + false = filelib:is_file(Obj), + Result = c:c(R), + {ok, m} = Result, + true = filelib:is_file(Obj). + +nc_default_outdir_1(Config) -> + R = filename:join(proplists:get_value(data_dir, Config), "m.erl"), + W = proplists:get_value(priv_dir, Config), + file:set_cwd(W), + Obj = "m" ++ code:objfile_extension(), + _ = file:delete(Obj), + false = filelib:is_file(Obj), + Result = c:nc(R), + {ok, m} = Result, + true = filelib:is_file(Obj). + +nc_default_outdir_2(Config) -> + R = filename:join(proplists:get_value(data_dir, Config), "m"), + W = proplists:get_value(priv_dir, Config), + file:set_cwd(W), + Obj = "m" ++ code:objfile_extension(), + _ = file:delete(Obj), + false = filelib:is_file(Obj), + Result = c:nc(R), + {ok, m} = Result, + true = filelib:is_file(Obj). + ls(Config) when is_list(Config) -> Directory = proplists:get_value(data_dir, Config), ok = c:ls(Directory), diff --git a/lib/stdlib/test/edlin_expand_SUITE.erl b/lib/stdlib/test/edlin_expand_SUITE.erl index 1f694ea549..5c2b1965ba 100644 --- a/lib/stdlib/test/edlin_expand_SUITE.erl +++ b/lib/stdlib/test/edlin_expand_SUITE.erl @@ -22,7 +22,7 @@ init_per_testcase/2, end_per_testcase/2, init_per_group/2,end_per_group/2]). -export([normal/1, quoted_fun/1, quoted_module/1, quoted_both/1, erl_1152/1, - erl_352/1]). + erl_352/1, unicode/1]). -include_lib("common_test/include/ct.hrl"). @@ -37,7 +37,8 @@ suite() -> {timetrap,{minutes,1}}]. all() -> - [normal, quoted_fun, quoted_module, quoted_both, erl_1152, erl_352]. + [normal, quoted_fun, quoted_module, quoted_both, erl_1152, erl_352, + unicode]. groups() -> []. @@ -150,6 +151,7 @@ quoted_both(Config) when is_list(Config) -> {yes,"weird-fun-name'()",[]} = do_expand("'ExpandTestCaps1':'#"), ok. +%% Note: pull request #1152. erl_1152(Config) when is_list(Config) -> "\n"++"foo"++" "++[1089]++_ = do_format(["foo",[1089]]), ok. @@ -226,6 +228,26 @@ check_trailing([I|Str], ArityStr, Suffix, Dots) -> Rest =:= Suffix end. +unicode(Config) when is_list(Config) -> + {module,unicode_expand} = c:l('unicode_expand'), + {no,[],[{"'кlирилли́ческий атом'",0}, + {"'кlирилли́ческий атом'",1}, + {"'кlирилли́ческий атомB'",1}, + {"module_info",0}, + {"module_info",1}]} = do_expand("unicode_expand:"), + {yes,"рилли́ческий атом", []} = do_expand("unicode_expand:'кlи"), + {yes,"еский атом", []} = do_expand("unicode_expand:'кlирилли́ч"), + {yes,"(",[]} = do_expand("unicode_expand:'кlирилли́ческий атомB'"), + "\n'кlирилли́ческий атом'/0 'кlирилли́ческий атом'/1 " + "'кlирилли́ческий атомB'/1 \nmodule_info/0 " + "module_info/1 \n" = + do_format([{"'кlирилли́ческий атом'",0}, + {"'кlирилли́ческий атом'",1}, + {"'кlирилли́ческий атомB'",1}, + {"module_info",0}, + {"module_info",1}]), + ok. + do_expand(String) -> edlin_expand:expand(lists:reverse(String)). diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 6a75eaa737..b76bece07f 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -66,7 +66,7 @@ otp_11851/1,otp_11879/1,otp_13230/1, record_errors/1, otp_11879_cont/1, non_latin1_module/1, otp_14323/1, - get_stacktrace/1, otp_14285/1]). + get_stacktrace/1, otp_14285/1, otp_14378/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -87,7 +87,7 @@ all() -> maps, maps_type, maps_parallel_match, otp_11851, otp_11879, otp_13230, record_errors, otp_11879_cont, non_latin1_module, otp_14323, - get_stacktrace, otp_14285]. + get_stacktrace, otp_14285, otp_14378]. groups() -> [{unused_vars_warn, [], @@ -2054,12 +2054,10 @@ otp_5362(Config) when is_list(Config) -> spawn(A). ">>, {[nowarn_unused_function]}, - {error,[{3,erl_lint,disallowed_nowarn_bif_clash}, - {4,erl_lint,disallowed_nowarn_bif_clash}, - {4,erl_lint,{bad_nowarn_bif_clash,{spawn,2}}}], - [{5,erl_lint,{bad_nowarn_deprecated_function,{3,now,-1}}}, - {5,erl_lint,{bad_nowarn_deprecated_function,{erlang,now,-1}}}, - {5,erl_lint,{bad_nowarn_deprecated_function,{{a,b,c},now,-1}}}]} + {errors,[{3,erl_lint,disallowed_nowarn_bif_clash}, + {4,erl_lint,disallowed_nowarn_bif_clash}, + {4,erl_lint,{bad_nowarn_bif_clash,{spawn,2}}}], + []} }, {otp_5362_8, @@ -3937,10 +3935,6 @@ non_latin1_module(Config) -> UndefBehav = {undefined_behaviour,'кирилли́ческий атом'}, "behaviour 'кирилли́ческий атом' undefined" = format_error(UndefBehav), - BadDepr = {bad_nowarn_deprecated_function, - {'кирилли́ческий атом','кирилли́ческий атом',18}}, - "'кирилли́ческий атом':'кирилли́ческий атом'/18 is not a deprecated " - "function" = format_error(BadDepr), Ts = [{non_latin1_module, <<" %% Report uses of module names with non-Latin-1 characters. @@ -3951,9 +3945,6 @@ non_latin1_module(Config) -> -callback 'кирилли́ческий атом':'кирилли́ческий атом'() -> a. - -compile([{nowarn_deprecated_function, - [{'кирилли́ческий атом','кирилли́ческий атом',18}]}]). - %% erl_lint:gexpr/3 is not extended to check module name here: t1() when 'кирилли́ческий атом':'кирилли́ческий атом'(1) -> b. @@ -3977,16 +3968,14 @@ non_latin1_module(Config) -> {6,erl_lint,non_latin1_module_unsupported}, {8,erl_lint,non_latin1_module_unsupported}, {8,erl_lint,BadCallback}, - {10,erl_lint,non_latin1_module_unsupported}, - {14,erl_lint,illegal_guard_expr}, - {18,erl_lint,non_latin1_module_unsupported}, + {11,erl_lint,illegal_guard_expr}, + {15,erl_lint,non_latin1_module_unsupported}, + {17,erl_lint,non_latin1_module_unsupported}, {20,erl_lint,non_latin1_module_unsupported}, {23,erl_lint,non_latin1_module_unsupported}, - {26,erl_lint,non_latin1_module_unsupported}, - {28,erl_lint,non_latin1_module_unsupported}], + {25,erl_lint,non_latin1_module_unsupported}], [{5,erl_lint,UndefBehav}, - {6,erl_lint,UndefBehav}, - {10,erl_lint,BadDepr}]}}], + {6,erl_lint,UndefBehav}]}}], run(Config, Ts), ok. @@ -4000,6 +3989,22 @@ do_non_latin1_module(Mod) -> ok. +otp_14378(Config) -> + Ts = [ + {otp_14378_1, + <<"-export([t/0]). + -compile({nowarn_deprecated_function,{erlang,now,1}}). + t() -> + erlang:now().">>, + [], + {warnings,[{4,erl_lint, + {deprecated,{erlang,now,0}, + "Deprecated BIF. See the \"Time and Time Correction" + " in Erlang\" chapter of the ERTS User's Guide" + " for more information."}}]}}], + [] = run(Config, Ts), + ok. + %% OTP-14323: Check the dialyzer attribute. otp_14323(Config) -> Ts = [ @@ -4099,7 +4104,27 @@ get_stacktrace(Config) -> [], {warnings,[{4,erl_lint,{get_stacktrace,wrong_part_of_try}}, {13,erl_lint,{get_stacktrace,after_try}}, - {22,erl_lint,{get_stacktrace,after_try}}]}}], + {22,erl_lint,{get_stacktrace,after_try}}]}}, + {multiple_catch_clauses, + <<"maybe_error(Arg) -> + try 5 / Arg + catch + error:badarith -> + _Stacktrace = erlang:get_stacktrace(), + try io:nl() + catch + error:_ -> io:format('internal error') + end; + error:badarg -> + _Stacktrace = erlang:get_stacktrace(), + try io:format(qwe) + catch + error:_ -> io:format('internal error') + end + end. + ">>, + [], + []}], run(Config, Ts), ok. diff --git a/lib/stdlib/test/error_logger_h_SUITE.erl b/lib/stdlib/test/error_logger_h_SUITE.erl index 30f96e0522..1f2a9fda0b 100644 --- a/lib/stdlib/test/error_logger_h_SUITE.erl +++ b/lib/stdlib/test/error_logger_h_SUITE.erl @@ -162,7 +162,7 @@ tty_log_open(Log) -> {ok,D} -> D; _ -> unlimited end, - error_logger:add_report_handler(?MODULE, {Fd,Depth}), + error_logger:add_report_handler(?MODULE, {Fd,Depth,latin1}), Fd. tty_log_close() -> @@ -393,11 +393,11 @@ dl_format_1([], [], _, Facc, Aacc) -> %%% calling error_logger_tty_h:write_event/2. %%% -init({_,_}=St) -> +init({_,_,_}=St) -> {ok,St}. -handle_event(Event, {Fd,Depth}=St) -> - case error_logger_tty_h:write_event(tag_event(Event), io_lib, Depth) of +handle_event(Event, {Fd,Depth,Enc}=St) -> + case error_logger_tty_h:write_event(tag_event(Event), io_lib, {Depth,Enc}) of ok -> ok; Str when is_list(Str) -> @@ -405,7 +405,7 @@ handle_event(Event, {Fd,Depth}=St) -> end, {ok,St}. -terminate(_Reason, {Fd,_}) -> +terminate(_Reason, {Fd,_,_}) -> ok = file:close(Fd), []. diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl index 3d4ae1a189..186df41d3f 100644 --- a/lib/stdlib/test/id_transform_SUITE.erl +++ b/lib/stdlib/test/id_transform_SUITE.erl @@ -61,8 +61,13 @@ id_transform(Config) when is_list(Config) -> "erl_id_trans.erl"]), {ok,erl_id_trans,Bin} = compile:file(File,[binary]), {module,erl_id_trans} = code:load_binary(erl_id_trans, File, Bin), - ct:timetrap({hours,1}), - run_in_test_suite(). + case test_server:is_valgrind() of + false -> + ct:timetrap({hours,1}), + run_in_test_suite(); + true -> + {skip,"Valgrind (too slow)"} + end. run_in_test_suite() -> SuperDir = filename:dirname(filename:dirname(code:which(?MODULE))), diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl index 029e6286e4..7686889360 100644 --- a/lib/stdlib/test/proc_lib_SUITE.erl +++ b/lib/stdlib/test/proc_lib_SUITE.erl @@ -28,7 +28,7 @@ init_per_group/2,end_per_group/2, crash/1, stacktrace/1, sync_start_nolink/1, sync_start_link/1, spawn_opt/1, sp1/0, sp2/0, sp3/1, sp4/2, sp5/1, '\x{447}'/0, - hibernate/1, stop/1, t_format/1]). + hibernate/1, stop/1, t_format/1, t_format_arbitrary/1]). -export([ otp_6345/1, init_dont_hang/1]). -export([hib_loop/1, awaken/1]). @@ -51,7 +51,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [crash, stacktrace, {group, sync_start}, spawn_opt, hibernate, - {group, tickets}, stop, t_format]. + {group, tickets}, stop, t_format, t_format_arbitrary]. groups() -> [{tickets, [], [otp_6345, init_dont_hang]}, @@ -78,6 +78,14 @@ end_per_group(_GroupName, Config) -> %% synchronous, and we want to test that the crash report is ok. %%----------------------------------------------------------------- crash(Config) when is_list(Config) -> + ok = application:unset_env(kernel, error_logger_format_depth), + crash_1(Config), + ok = application:set_env(kernel, error_logger_format_depth, 30), + crash_1(Config), + ok = application:unset_env(kernel, error_logger_format_depth), + ok. + +crash_1(_Config) -> error_logger:add_report_handler(?MODULE, self()), %% Make sure that we don't get a crash report if a process @@ -544,14 +552,17 @@ t_format(_Config) -> t_format() -> error_logger:add_report_handler(?MODULE, self()), - Pid = proc_lib:spawn(fun t_format_looper/0), + Pid = proc_lib:spawn(fun '\x{aaa}t_format_looper'/0), HugeData = gb_sets:from_list(lists:seq(1, 100)), - Pid ! {die,HugeData}, + SomeData1 = list_to_atom([246]), + SomeData2 = list_to_atom([1024]), + Pid ! {SomeData1,SomeData2}, + Pid ! {die,{HugeData,SomeData1,SomeData2}}, Report = receive {crash_report, Pid, Report0} -> Report0 end, - Usz = do_test_format(Report, unlimited), - Tsz = do_test_format(Report, 20), + Usz = do_test_format(Report, latin1, unlimited), + Tsz = do_test_format(Report, latin1, 20), if Tsz >= Usz -> @@ -560,21 +571,58 @@ t_format() -> ok end, + UszU = do_test_format(Report, unicode, unlimited), + TszU = do_test_format(Report, unicode, 20), + + if + TszU >= UszU -> + ct:fail(failed); + true -> + ok + end, + ok. +t_format_arbitrary(_Config) -> + error_logger:tty(false), + try + t_format_arbitrary() + after + error_logger:tty(true) + end, + ok. + +t_format_arbitrary() -> + A = list_to_atom([1024]), + do_test_format([fake_report, A], unlimited), + do_test_format([fake_report, A], 20), + + do_test_format([fake_report, foo], unlimited), + do_test_format([fake_report, foo], 20), + do_test_format([fake_report, []], unlimited), + do_test_format([fake_report, []], 20). + do_test_format(Report, Depth) -> - io:format("*** Depth = ~p", [Depth]), - S0 = proc_lib:format(Report, latin1, Depth), + do_test_format(Report, latin1, Depth), + do_test_format(Report, unicode, Depth). + +do_test_format(Report, Encoding, Depth) -> + io:format("*** Depth = ~p, Encoding = ~p", [Depth, Encoding]), + S0 = proc_lib:format(Report, Encoding, Depth), S = lists:flatten(S0), - io:put_chars(S), + case Encoding of + latin1 -> io:format("~s\n", [S]); + _ -> io:format("~ts\n", [S]) + end, length(S). -t_format_looper() -> +'\x{aaa}t_format_looper'() -> receive {die,Data} -> exit(Data); - _ -> - t_format_looper() + M -> + put(M, M), + '\x{aaa}t_format_looper'() end. %%----------------------------------------------------------------- @@ -584,7 +632,7 @@ init(Tester) -> {ok, Tester}. handle_event({error_report, _GL, {Pid, crash_report, Report}}, Tester) -> - io:format("~s\n", [proc_lib:format(Report)]), + io:format("~ts\n", [proc_lib:format(Report)]), Tester ! {crash_report, Pid, Report}, {ok, Tester}; handle_event(_Event, State) -> diff --git a/lib/stdlib/test/re_SUITE_data/testoutput1 b/lib/stdlib/test/re_SUITE_data/testoutput1 index a2b3cffe9d..eff8ecc948 100644 --- a/lib/stdlib/test/re_SUITE_data/testoutput1 +++ b/lib/stdlib/test/re_SUITE_data/testoutput1 @@ -9442,4 +9442,8 @@ No match \ X 0: X +/X+(?#comment)?/ + >XXX< + 0: X + /-- End of testinput1 --/ diff --git a/lib/stdlib/test/re_SUITE_data/testoutput8 b/lib/stdlib/test/re_SUITE_data/testoutput8 index 17b667a980..4984376d3c 100644 --- a/lib/stdlib/test/re_SUITE_data/testoutput8 +++ b/lib/stdlib/test/re_SUITE_data/testoutput8 @@ -7801,4 +7801,8 @@ No match ** Show all captures ignored after DFA matching 0: a +/(02-)?[0-9]{3}-[0-9]{3}/ + 02-123-123 + 0: 02-123-123 + /-- End of testinput8 --/ diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl index 4f0fdc4c6a..217e8cc252 100644 --- a/lib/stdlib/test/shell_SUITE.erl +++ b/lib/stdlib/test/shell_SUITE.erl @@ -31,7 +31,7 @@ progex_lc/1, progex_funs/1, otp_5990/1, otp_6166/1, otp_6554/1, otp_7184/1, otp_7232/1, otp_8393/1, otp_10302/1, otp_13719/1, - otp_14285/1, otp_14296/1]). + otp_14285/1, otp_14296/1, typed_records/1]). -export([ start_restricted_from_shell/1, start_restricted_on_command_line/1,restricted_local/1]). @@ -74,10 +74,10 @@ suite() -> {timetrap,{minutes,10}}]. all() -> - [forget, records, known_bugs, otp_5226, otp_5327, + [forget, known_bugs, otp_5226, otp_5327, otp_5435, otp_5195, otp_5915, otp_5916, {group, bits}, {group, refman}, {group, progex}, {group, tickets}, - {group, restricted}]. + {group, restricted}, {group, records}]. groups() -> [{restricted, [], @@ -86,6 +86,8 @@ groups() -> {bits, [], [bs_match_misc_SUITE, bs_match_tail_SUITE, bs_match_bin_SUITE, bs_construct_SUITE]}, + {records, [], + [records, typed_records]}, {refman, [], [refman_bit_syntax]}, {progex, [], [progex_bit_syntax, progex_records, progex_lc, @@ -486,6 +488,48 @@ records(Config) when is_list(Config) -> ok. +%% Test of typed record support. +typed_records(Config) when is_list(Config) -> + Test = filename:join(proplists:get_value(priv_dir, Config), "test.hrl"), + Contents = <<"-module(test). + -record(r0,{f :: any()}). + -record(r1,{f1 :: #r1{} | undefined, f2 :: #r0{} | atom()}). + -record(r2,{f :: #r2{} | undefined}). + ">>, + ok = file:write_file(Test, Contents), + + RR1 = "rr(\"" ++ Test ++ "\"), + #r1{} = (#r1{f1=#r1{f1=undefined, f2=x}, f2 = #r0{}})#r1.f1, + ok.", + RR2 = "rr(\"" ++ Test ++ "\"), + #r0{} = (#r1{f1=#r1{f1=undefined, f2=x}, f2 = #r0{}})#r1.f2, + ok. ", + RR3 = "rr(\"" ++ Test ++ "\"), + #r1{f2=#r0{}} = (#r1{f1=#r1{f1=undefined, f2=#r0{}}, f2 = x})#r1.f1, + ok.", + RR4 = "rr(\"" ++ Test ++ "\"), + (#r1{f2 = #r0{}})#r1{f2 = x}, + ok. ", + RR5 = "rr(\"" ++ Test ++ "\"), + (#r1{f2 = #r0{}})#r1{f1 = #r1{}}, + ok. ", + RR6 = "rr(\"" ++ Test ++ "\"), + (#r2{f=#r2{f=undefined}})#r2.f, + ok.", + RR7 = "rr(\"" ++ Test ++ "\"), + #r2{} = (#r2{f=#r2{f=undefined}})#r2.f, + ok.", + [ok] = scan(RR1), + [ok] = scan(RR2), + [ok] = scan(RR3), + [ok] = scan(RR4), + [ok] = scan(RR5), + [ok] = scan(RR6), + [ok] = scan(RR7), + + file:delete(Test), + ok. + %% Known bugs. known_bugs(Config) when is_list(Config) -> %% erl_eval:merge_bindings/2 cannot handle _removal_ of bindings. diff --git a/lib/stdlib/test/unicode_expand.erl b/lib/stdlib/test/unicode_expand.erl new file mode 100644 index 0000000000..41f741fa84 --- /dev/null +++ b/lib/stdlib/test/unicode_expand.erl @@ -0,0 +1,36 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2017. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(unicode_expand). + +-export(['кlирилли́ческий атом'/0, 'кlирилли́ческий атом'/1, + 'кlирилли́ческий атомB'/1]). + +-export_type(['кlирилли́ческий атом'/0]). + +-type 'кlирилли́ческий атом'() :: integer(). + +'кlирилли́ческий атом'() -> + 'кlирилли́ческий атом'('кlирилли́ческий атом'). + +'кlирилли́ческий атом'(_Atom) -> + ok. + +'кlирилли́ческий атомB'(_B) -> + true. diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index f062c7fe6e..8a83cdec1e 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 3.4 +STDLIB_VSN = 3.4.1 |