aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/src')
-rw-r--r--lib/stdlib/src/dets.erl30
-rw-r--r--lib/stdlib/src/dets_server.erl18
-rw-r--r--lib/stdlib/src/edlin.erl2
-rw-r--r--lib/stdlib/src/epp.erl16
-rw-r--r--lib/stdlib/src/erl_eval.erl2
-rw-r--r--lib/stdlib/src/erl_expand_records.erl35
-rw-r--r--lib/stdlib/src/erl_parse.yrl14
-rw-r--r--lib/stdlib/src/erl_pp.erl10
-rw-r--r--lib/stdlib/src/erl_scan.erl4
-rw-r--r--lib/stdlib/src/erl_tar.erl93
-rw-r--r--lib/stdlib/src/filelib.erl16
-rw-r--r--lib/stdlib/src/gen_event.erl48
-rw-r--r--lib/stdlib/src/gen_fsm.erl49
-rw-r--r--lib/stdlib/src/gen_server.erl193
-rw-r--r--lib/stdlib/src/io.erl43
-rw-r--r--lib/stdlib/src/io_lib_format.erl2
-rw-r--r--lib/stdlib/src/maps.erl17
-rw-r--r--lib/stdlib/src/ms_transform.erl4
-rw-r--r--lib/stdlib/src/otp_internal.erl14
-rw-r--r--lib/stdlib/src/proc_lib.erl6
-rw-r--r--lib/stdlib/src/shell.erl8
-rw-r--r--lib/stdlib/src/stdlib.app.src2
-rw-r--r--lib/stdlib/src/stdlib.appup.src6
-rw-r--r--lib/stdlib/src/sys.erl10
24 files changed, 427 insertions, 215 deletions
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index c32da1624f..a4bd45ea19 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -440,9 +440,10 @@ insert(Tab, Objs) when is_list(Objs) ->
insert(Tab, Obj) ->
badarg(treq(Tab, {insert, [Obj]}), [Tab, Obj]).
--spec insert_new(Name, Objects) -> boolean() when
+-spec insert_new(Name, Objects) -> boolean() | {'error', Reason} when
Name :: tab_name(),
- Objects :: object() | [object()].
+ Objects :: object() | [object()],
+ Reason :: term().
insert_new(Tab, Objs) when is_list(Objs) ->
badarg(treq(Tab, {insert_new, Objs}), [Tab, Objs]);
@@ -2838,17 +2839,22 @@ fsck_try(Fd, Tab, FH, Fname, SlotNumbers, Version) ->
tempfile(Fname) ->
Tmp = lists:concat([Fname, ".TMP"]),
- tempfile(Tmp, 10).
-
-tempfile(Tmp, 0) ->
- Tmp;
-tempfile(Tmp, N) ->
case file:delete(Tmp) of
- {error, eacces} -> % 'dets_process_died' happened anyway... (W-nd-ws)
- timer:sleep(1000),
- tempfile(Tmp, N-1);
- _ ->
- Tmp
+ {error, _Reason} -> % typically enoent
+ ok;
+ ok ->
+ assure_no_file(Tmp)
+ end,
+ Tmp.
+
+assure_no_file(File) ->
+ case file:read_file_info(File) of
+ {ok, _FileInfo} ->
+ %% Wait for some other process to close the file:
+ timer:sleep(100),
+ assure_no_file(File);
+ {error, _} ->
+ ok
end.
%% -> {ok, NewHead} | {try_again, integer()} | Error
diff --git a/lib/stdlib/src/dets_server.erl b/lib/stdlib/src/dets_server.erl
index 268c201047..3164d40f35 100644
--- a/lib/stdlib/src/dets_server.erl
+++ b/lib/stdlib/src/dets_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -171,9 +171,15 @@ handle_info({pending_reply, {Ref, Result0}}, State) ->
link(Pid),
do_link(Store, FromPid),
true = ets:insert(Store, {FromPid, Tab}),
- true = ets:insert(?REGISTRY, {Tab, 1, Pid}),
- true = ets:insert(?OWNERS, {Pid, Tab}),
+ %% do_internal_open() has already done the following:
+ %% true = ets:insert(?REGISTRY, {Tab, 1, Pid}),
+ %% true = ets:insert(?OWNERS, {Pid, Tab}),
{ok, Tab};
+ {Reply, internal_open} ->
+ %% Clean up what do_internal_open() did:
+ true = ets:delete(?REGISTRY, Tab),
+ true = ets:delete(?OWNERS, Pid),
+ Reply;
{Reply, _} -> % ok or Error
Reply
end,
@@ -309,6 +315,12 @@ do_internal_open(State, From, Args) ->
[T, _, _] -> T;
[_, _] -> Ref
end,
+ %% Pretend the table is open. If someone else tries to
+ %% open the file it will always become a pending
+ %% 'add_user' request. If someone tries to use the table
+ %% there will be a delay, but that is OK.
+ true = ets:insert(?REGISTRY, {Tab, 1, Pid}),
+ true = ets:insert(?OWNERS, {Pid, Tab}),
pending_call(Tab, Pid, Ref, From, Args, internal_open, State);
Error ->
{Error, State}
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index be9a4f5107..b3bc5f6d92 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -390,7 +390,7 @@ do_op(end_of_line, Bef, [C|Aft], Rs) ->
do_op(end_of_line, Bef, [], Rs) ->
{{Bef,[]},Rs};
do_op(ctlu, Bef, Aft, Rs) ->
- put(kill_buffer, Bef),
+ put(kill_buffer, reverse(Bef)),
{{[], Aft}, [{delete_chars, -length(Bef)} | Rs]};
do_op(beep, Bef, Aft, Rs) ->
{{Bef,Aft},[beep|Rs]};
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 9b506b0a44..5f8637c118 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -1121,8 +1121,20 @@ skip_toks(From, St, [I|Sis]) ->
skip_toks(From, St#epp{location=Cl}, Sis);
{ok,_Toks,Cl} ->
skip_toks(From, St#epp{location=Cl}, [I|Sis]);
- {error,_E,Cl} ->
- skip_toks(From, St#epp{location=Cl}, [I|Sis]);
+ {error,E,Cl} ->
+ case E of
+ {_,file_io_server,invalid_unicode} ->
+ %% The compiler needs to know that there was
+ %% invalid unicode characters in the file
+ %% (and there is no point in continuing anyway
+ %% since io server process has terminated).
+ epp_reply(From, {error,E}),
+ leave_file(wait_request(St), St);
+ _ ->
+ %% Some other invalid token, such as a bad floating
+ %% point number. Just ignore it.
+ skip_toks(From, St#epp{location=Cl}, [I|Sis])
+ end;
{eof,Cl} ->
leave_file(From, St#epp{location=Cl,istk=[I|Sis]});
{error,_E} ->
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 3cfedfee97..639ddfc214 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -77,7 +77,7 @@
%% Only exprs/2 checks the command by calling erl_lint. The reason is
%% that if there is a function handler present, then it is possible
%% that there are valid constructs in Expression to be taken care of
-%% by a function handler but considerad errors by erl_lint.
+%% by a function handler but considered errors by erl_lint.
-spec(exprs(Expressions, Bindings) -> {value, Value, NewBindings} when
Expressions :: expressions(),
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index 57e768ba9d..64a00acd88 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,6 +38,8 @@
checked_ra=[] % successfully accessed records
}).
+-define(REC_OFFSET, 100000000). % A hundred millions. Also in v3_core.
+
-spec(module(AbsForms, CompileOptions) -> AbsForms when
AbsForms :: [erl_parse:abstract_form()],
CompileOptions :: [compile:option()]).
@@ -144,10 +146,11 @@ pattern({map_field_exact,Line,K0,V0}, St0) ->
%% {{struct,Line,Tag,TPs},TPsvs,St1};
pattern({record_index,Line,Name,Field}, St) ->
{index_expr(Line, Field, Name, record_fields(Name, St)),St};
-pattern({record,Line,Name,Pfs}, St0) ->
+pattern({record,Line0,Name,Pfs}, St0) ->
Fs = record_fields(Name, St0),
{TMs,St1} = pattern_list(pattern_fields(Fs, Pfs), St0),
- {{tuple,Line,[{atom,Line,Name} | TMs]},St1};
+ Line = record_offset(Line0, St1),
+ {{tuple,Line,[{atom,Line0,Name} | TMs]},St1};
pattern({bin,Line,Es0}, St0) ->
{Es1,St1} = pattern_bin(Es0, St0),
{{bin,Line,Es1},St1};
@@ -329,8 +332,9 @@ expr({map_field_exact,Line,K0,V0}, St0) ->
expr({record_index,Line,Name,F}, St) ->
I = index_expr(Line, F, Name, record_fields(Name, St)),
expr(I, St);
-expr({record,Line,Name,Is}, St) ->
- expr({tuple,Line,[{atom,Line,Name} |
+expr({record,Line0,Name,Is}, St) ->
+ Line = record_offset(Line0, St),
+ expr({tuple,Line,[{atom,Line0,Name} |
record_inits(record_fields(Name, St), Is)]},
St);
expr({record_field,Line,R,Name,F}, St) ->
@@ -582,8 +586,9 @@ strict_get_record_field(Line, R, {atom,_,F}=Index, Name, St0) ->
I = index_expr(F, Fs, 2),
P = record_pattern(2, I, Var, length(Fs)+1, Line, [{atom,Line,Name}]),
NLine = neg_line(Line),
+ RLine = record_offset(NLine, St),
E = {'case',NLine,R,
- [{clause,NLine,[{tuple,NLine,P}],[],[Var]},
+ [{clause,NLine,[{tuple,RLine,P}],[],[Var]},
{clause,NLine,[{var,NLine,'_'}],[],
[{call,NLine,{remote,NLine,
{atom,NLine,erlang},
@@ -697,9 +702,10 @@ record_update(R, Name, Fs, Us0, St0) ->
record_match(R, Name, Lr, Fs, Us, St0) ->
{Ps,News,St1} = record_upd_fs(Fs, Us, St0),
NLr = neg_line(Lr),
+ RLine = record_offset(Lr, St1),
{{'case',Lr,R,
- [{clause,Lr,[{tuple,Lr,[{atom,Lr,Name} | Ps]}],[],
- [{tuple,Lr,[{atom,Lr,Name} | News]}]},
+ [{clause,Lr,[{tuple,RLine,[{atom,Lr,Name} | Ps]}],[],
+ [{tuple,RLine,[{atom,Lr,Name} | News]}]},
{clause,NLr,[{var,NLr,'_'}],[],
[call_error(NLr, {tuple,NLr,[{atom,NLr,badrecord},{atom,NLr,Name}]})]}
]},
@@ -728,6 +734,10 @@ record_setel(R, Name, Fs, Us0) ->
Lr = element(2, hd(Us)),
Wildcards = duplicate(length(Fs), {var,Lr,'_'}),
NLr = neg_line(Lr),
+ %% Note: calling record_offset() here is not necessary since it is
+ %% targeted at Dialyzer which always calls the compiler with
+ %% 'strict_record_updates' meaning that record_setel() will never
+ %% be called.
{'case',Lr,R,
[{clause,Lr,[{tuple,Lr,[{atom,Lr,Name} | Wildcards]}],[],
[foldr(fun ({I,Lf,Val}, Acc) ->
@@ -836,7 +846,7 @@ optimize_is_record(H0, G0, #exprec{compile=Opts}) ->
[] ->
{H0,G0};
Rs0 ->
- case lists:member(no_is_record_optimization, Opts) of
+ case lists:member(dialyzer, Opts) of % no_is_record_optimization
true ->
{H0,G0};
false ->
@@ -961,3 +971,10 @@ opt_remove_2(A, _) -> A.
neg_line(L) ->
erl_parse:set_line(L, fun(Line) -> -abs(Line) end).
+
+record_offset(L, St) ->
+ case lists:member(dialyzer, St#exprec.compile) of
+ true when L >= 0 -> L+?REC_OFFSET;
+ true when L < 0 -> L-?REC_OFFSET;
+ false -> L
+ end.
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index e1ae3b7aea..1d4a2a1fef 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -753,6 +753,9 @@ attribute_farity({cons,L,H,T}) ->
attribute_farity({tuple,L,Args0}) ->
Args = attribute_farity_list(Args0),
{tuple,L,Args};
+attribute_farity({map,L,Args0}) ->
+ Args = attribute_farity_map(Args0),
+ {map,L,Args};
attribute_farity({op,L,'/',{atom,_,_}=Name,{integer,_,_}=Arity}) ->
{tuple,L,[Name,Arity]};
attribute_farity(Other) -> Other.
@@ -760,6 +763,10 @@ attribute_farity(Other) -> Other.
attribute_farity_list(Args) ->
[attribute_farity(A) || A <- Args].
+%% It is not meaningful to have farity keys.
+attribute_farity_map(Args) ->
+ [{Op,L,K,attribute_farity(V)} || {Op,L,K,V} <- Args].
+
-spec error_bad_decl(integer(), attributes()) -> no_return().
error_bad_decl(L, S) ->
@@ -954,7 +961,9 @@ abstract([H|T], L, none=E) ->
abstract(List, L, E) when is_list(List) ->
abstract_list(List, [], L, E);
abstract(Tuple, L, E) when is_tuple(Tuple) ->
- {tuple,L,abstract_tuple_list(tuple_to_list(Tuple), L, E)}.
+ {tuple,L,abstract_tuple_list(tuple_to_list(Tuple), L, E)};
+abstract(Map, L, E) when is_map(Map) ->
+ {map,L,abstract_map_fields(maps:to_list(Map),L,E)}.
abstract_list([H|T], String, L, E) ->
case is_integer(H) andalso H >= 0 andalso E(H) of
@@ -979,6 +988,9 @@ abstract_tuple_list([H|T], L, E) ->
abstract_tuple_list([], _L, _E) ->
[].
+abstract_map_fields(Fs,L,E) ->
+ [{map_field_assoc,L,abstract(K,L,E),abstract(V,L,E)}||{K,V}<-Fs].
+
abstract_byte(Byte, L) when is_integer(Byte) ->
{bin_element, L, {integer, L, Byte}, default, default};
abstract_byte(Bits, L) ->
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 82bc2c1460..1fd6d2a8df 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -300,7 +300,15 @@ map_pair_types(Fs) ->
tuple_type(Fs, fun map_pair_type/1).
map_pair_type({type,_Line,map_field_assoc,Ktype,Vtype}) ->
- {seq,[],[]," =>",[ltype(Ktype),ltype(Vtype)]}.
+ map_assoc_typed(ltype(Ktype), Vtype).
+
+map_assoc_typed(B, {type,_,union,Ts}) ->
+ {first,[B,$\s],{seq,[],[],[],map_assoc_union_type(Ts)}};
+map_assoc_typed(B, Type) ->
+ {list,[{cstep,[B," =>"],ltype(Type)}]}.
+
+map_assoc_union_type([T|Ts]) ->
+ [[leaf("=> "),ltype(T)] | ltypes(Ts, fun union_elem/1)].
record_type(Name, Fields) ->
{first,[record_name(Name)],field_types(Fields)}.
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index ae59d5f44f..6fd6bb888b 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -1075,7 +1075,7 @@ scan_number([$#|Cs]=Cs0, St, Line, Col, Toks, Ncs0) ->
Ncs = lists:reverse(Ncs0),
case catch list_to_integer(Ncs) of
B when B >= 2, B =< 1+$Z-$A+10 ->
- Bcs = ?STR(St, Ncs++[$#]),
+ Bcs = Ncs++[$#],
scan_based_int(Cs, St, Line, Col, Toks, {B,[],Bcs});
B ->
Len = length(Ncs),
@@ -1108,7 +1108,7 @@ scan_based_int(Cs, St, Line, Col, Toks, {B,Ncs0,Bcs}) ->
Ncs = lists:reverse(Ncs0),
case catch erlang:list_to_integer(Ncs, B) of
N when is_integer(N) ->
- tok3(Cs, St, Line, Col, Toks, integer, ?STR(St, Bcs++Ncs), N);
+ tok3(Cs, St, Line, Col, Toks, integer, Bcs++Ncs, N);
_ ->
Len = length(Bcs)+length(Ncs),
Ncol = incr_column(Col, Len),
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index acf7a5cd40..ab6223c0fe 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -22,7 +22,7 @@
%% Purpose: Unix tar (tape archive) utility.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([create/2, create/3, extract/1, extract/2, table/1, table/2,
+-export([init/3, create/2, create/3, extract/1, extract/2, table/1, table/2,
open/2, close/1, add/3, add/4,
t/1, tt/1, format_error/1]).
@@ -30,10 +30,16 @@
-record(add_opts,
{read_info, % Fun to use for read file/link info.
+ chunk_size = 0, % For file reading when sending to sftp. 0=do not chunk
verbose = false :: boolean()}). % Verbose on/off.
%% Opens a tar archive.
+init(UsrHandle, AccessMode, Fun) when is_function(Fun,2) ->
+ {ok, {AccessMode,{UsrHandle,Fun}}}.
+
+%%%================================================================
+%%% The open function with friends is to keep the file and binary api of this module
open(Name, Mode) ->
case open_mode(Mode) of
{ok, Access, Raw, Opts} ->
@@ -46,27 +52,37 @@ open1({binary,Bin}, read, _Raw, Opts) ->
case file:open(Bin, [ram,binary,read]) of
{ok,File} ->
_ = [ram_file:uncompress(File) || Opts =:= [compressed]],
- {ok,{read,File}};
+ init(File,read,file_fun());
Error ->
Error
end;
open1({file, Fd}, read, _Raw, _Opts) ->
- {ok, {read, Fd}};
+ init(Fd, read, file_fun());
open1(Name, Access, Raw, Opts) ->
case file:open(Name, Raw ++ [binary, Access|Opts]) of
{ok, File} ->
- {ok, {Access, File}};
+ init(File, Access, file_fun());
{error, Reason} ->
{error, {Name, Reason}}
end.
+file_fun() ->
+ fun(write, {Fd,Data}) -> file:write(Fd, Data);
+ (position, {Fd,Pos}) -> file:position(Fd, Pos);
+ (read2, {Fd,Size}) -> file:read(Fd,Size);
+ (close, Fd) -> file:close(Fd)
+ end.
+
+%%% End of file and binary api (except for open_mode/1 downwards
+%%%================================================================
+
%% Closes a tar archive.
close({read, File}) ->
- ok = file:close(File);
+ ok = do_close(File);
close({write, File}) ->
PadResult = pad_file(File),
- ok = file:close(File),
+ ok = do_close(File),
PadResult;
close(_) ->
{error, einval}.
@@ -75,7 +91,6 @@ close(_) ->
add(File, Name, Options) ->
add(File, Name, Name, Options).
-
add({write, File}, Name, NameInArchive, Options) ->
Opts = #add_opts{read_info=fun(F) -> file:read_link_info(F) end},
add1(File, Name, NameInArchive, add_opts(Options, Opts));
@@ -88,6 +103,8 @@ add_opts([dereference|T], Opts) ->
add_opts(T, Opts#add_opts{read_info=fun(F) -> file:read_file_info(F) end});
add_opts([verbose|T], Opts) ->
add_opts(T, Opts#add_opts{verbose=true});
+add_opts([{chunks,N}|T], Opts) ->
+ add_opts(T, Opts#add_opts{chunk_size=N});
add_opts([_|T], Opts) ->
add_opts(T, Opts);
add_opts([], Opts) ->
@@ -321,16 +338,46 @@ add1(TarFile, Name, NameInArchive, Opts) ->
{error, {Name, Reason}}
end.
+add1(Tar, Name, Header, chunked, Options) ->
+ add_verbose(Options, "a ~ts [chunked ", [Name]),
+ try
+ ok = do_write(Tar, Header),
+ {ok,D} = file:open(Name, [read,binary]),
+ {ok,NumBytes} = add_read_write_chunks(D, Tar, Options#add_opts.chunk_size, 0, Options),
+ _ = file:close(D),
+ ok = do_write(Tar, padding(NumBytes,?record_size))
+ of
+ ok ->
+ add_verbose(Options, "~n", []),
+ ok
+ catch
+ error:{badmatch,{error,Error}} ->
+ add_verbose(Options, "~n", []),
+ {error,{Name,Error}}
+ end;
add1(Tar, Name, Header, Bin, Options) ->
add_verbose(Options, "a ~ts~n", [Name]),
- file:write(Tar, [Header, Bin, padding(byte_size(Bin), ?record_size)]).
+ do_write(Tar, [Header, Bin, padding(byte_size(Bin), ?record_size)]).
+
+add_read_write_chunks(D, Tar, ChunkSize, SumNumBytes, Options) ->
+ case file:read(D, ChunkSize) of
+ {ok,Bin} ->
+ ok = do_write(Tar, Bin),
+ add_verbose(Options, ".", []),
+ add_read_write_chunks(D, Tar, ChunkSize, SumNumBytes+byte_size(Bin), Options);
+ eof ->
+ add_verbose(Options, "]", []),
+ {ok,SumNumBytes};
+ Other ->
+ Other
+ end.
add_directory(TarFile, DirName, NameInArchive, Info, Options) ->
case file:list_dir(DirName) of
{ok, []} ->
add_verbose(Options, "a ~ts~n", [DirName]),
Header = create_header(NameInArchive, Info),
- file:write(TarFile, Header);
+ do_write(TarFile, Header);
{ok, Files} ->
Add = fun (File) ->
add1(TarFile,
@@ -396,7 +443,7 @@ to_string(Str0, Count) ->
%% Pads out end of file.
pad_file(File) ->
- {ok,Position} = file:position(File, {cur,0}),
+ {ok,Position} = do_position(File, {cur,0}),
%% There must be at least two zero records at the end.
Fill = case ?block_size - (Position rem ?block_size) of
Fill0 when Fill0 < 2*?record_size ->
@@ -407,7 +454,7 @@ pad_file(File) ->
%% Large enough.
Fill0
end,
- file:write(File, zeroes(Fill)).
+ do_write(File, zeroes(Fill)).
split_filename(Name) when length(Name) =< ?th_name_len ->
{"", Name};
@@ -500,7 +547,7 @@ foldl_read(TarName, Fun, Accu, Opts) ->
Ok ->
Ok
end,
- ok = file:close(File),
+ ok = do_close(File),
Result;
Error ->
Error
@@ -559,7 +606,7 @@ check_extract(Name, #read_opts{files=Files}) ->
ordsets:is_element(Name, Files).
get_header(File) ->
- case file:read(File, ?record_size) of
+ case do_read(File, ?record_size) of
eof ->
throw({error,eof});
{ok, Bin} when is_binary(Bin) ->
@@ -690,7 +737,7 @@ get_element(File, #tar_header{size = 0}) ->
skip_to_next(File),
{ok,<<>>};
get_element(File, #tar_header{size = Size}) ->
- case file:read(File, Size) of
+ case do_read(File, Size) of
{ok,Bin}=Res when byte_size(Bin) =:= Size ->
skip_to_next(File),
Res;
@@ -880,7 +927,7 @@ skip(File, Size) ->
%% Note: There is no point in handling failure to get the current position
%% in the file. If it doesn't work, something serious is wrong.
Amount = ((Size + ?record_size - 1) div ?record_size) * ?record_size,
- {ok,_} = file:position(File, {cur, Amount}),
+ {ok,_} = do_position(File, {cur, Amount}),
ok.
%% Skips to the next record in the file.
@@ -888,9 +935,9 @@ skip(File, Size) ->
skip_to_next(File) ->
%% Note: There is no point in handling failure to get the current position
%% in the file. If it doesn't work, something serious is wrong.
- {ok, Position} = file:position(File, {cur, 0}),
+ {ok, Position} = do_position(File, {cur, 0}),
NewPosition = ((Position + ?record_size - 1) div ?record_size) * ?record_size,
- {ok,NewPosition} = file:position(File, NewPosition),
+ {ok,NewPosition} = do_position(File, NewPosition),
ok.
%% Prints the message on if the verbose option is given.
@@ -916,6 +963,9 @@ posix_to_erlang_time(Sec) ->
read_file_and_info(Name, Opts) ->
ReadInfo = Opts#add_opts.read_info,
case ReadInfo(Name) of
+ {ok,Info} when Info#file_info.type =:= regular,
+ Opts#add_opts.chunk_size>0 ->
+ {ok,chunked,Info};
{ok,Info} when Info#file_info.type =:= regular ->
case file:read_file(Name) of
{ok,Bin} ->
@@ -962,3 +1012,12 @@ open_mode([], Access, Raw, Opts) ->
{ok, Access, Raw, Opts};
open_mode(_, _, _, _) ->
{error, einval}.
+
+%%%================================================================
+do_write({UsrHandle,Fun}, Data) -> Fun(write,{UsrHandle,Data}).
+
+do_position({UsrHandle,Fun}, Pos) -> Fun(position,{UsrHandle,Pos}).
+
+do_read({UsrHandle,Fun}, Len) -> Fun(read2,{UsrHandle,Len}).
+
+do_close({UsrHandle,Fun}) -> Fun(close,UsrHandle).
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index c0921e4cf1..daae1fd2d2 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -265,7 +265,7 @@ do_wildcard(Pattern, Cwd, Mod) ->
lists:sort(Files).
do_wildcard_1({exists,File}, Mod) ->
- case eval_read_file_info(File, Mod) of
+ case eval_read_link_info(File, Mod) of
{ok,_} -> [File];
_ -> []
end;
@@ -371,7 +371,7 @@ compile_wildcard(Pattern, Cwd0) ->
[Root|Rest] = filename:split(Pattern),
case filename:pathtype(Root) of
relative ->
- Cwd = filename:join([Cwd0]),
+ Cwd = prepare_base(Cwd0),
compile_wildcard_2([Root|Rest], {cwd,Cwd});
_ ->
compile_wildcard_2(Rest, {root,0,Root})
@@ -488,7 +488,7 @@ badpattern(Reason) ->
error({badpattern,Reason}).
eval_read_file_info(File, file) ->
- file:read_link_info(File);
+ file:read_file_info(File);
eval_read_file_info(File, erl_prim_loader) ->
case erl_prim_loader:read_file_info(File) of
error -> {error, erl_prim_loader};
@@ -497,6 +497,16 @@ eval_read_file_info(File, erl_prim_loader) ->
eval_read_file_info(File, Mod) ->
Mod:read_file_info(File).
+eval_read_link_info(File, file) ->
+ file:read_link_info(File);
+eval_read_link_info(File, erl_prim_loader) ->
+ case erl_prim_loader:read_link_info(File) of
+ error -> {error, erl_prim_loader};
+ Res-> Res
+ end;
+eval_read_link_info(File, Mod) ->
+ Mod:read_link_info(File).
+
eval_list_dir(Dir, file) ->
file:list_dir(Dir);
eval_list_dir(Dir, erl_prim_loader) ->
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index d39dd89d3a..469acdc37c 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -49,8 +49,6 @@
-import(error_logger, [error_msg/2]).
--define(reply(X), From ! {element(2,Tag), X}).
-
-record(handler, {module :: atom(),
id = false,
state,
@@ -249,49 +247,49 @@ handle_msg(Msg, Parent, ServerName, MSL, Debug) ->
{notify, Event} ->
{Hib,MSL1} = server_notify(Event, handle_event, MSL, ServerName),
loop(Parent, ServerName, MSL1, Debug, Hib);
- {From, Tag, {sync_notify, Event}} ->
+ {_From, Tag, {sync_notify, Event}} ->
{Hib, MSL1} = server_notify(Event, handle_event, MSL, ServerName),
- ?reply(ok),
+ reply(Tag, ok),
loop(Parent, ServerName, MSL1, Debug, Hib);
{'EXIT', From, Reason} ->
MSL1 = handle_exit(From, Reason, MSL, ServerName),
loop(Parent, ServerName, MSL1, Debug, false);
- {From, Tag, {call, Handler, Query}} ->
+ {_From, Tag, {call, Handler, Query}} ->
{Hib, Reply, MSL1} = server_call(Handler, Query, MSL, ServerName),
- ?reply(Reply),
+ reply(Tag, Reply),
loop(Parent, ServerName, MSL1, Debug, Hib);
- {From, Tag, {add_handler, Handler, Args}} ->
+ {_From, Tag, {add_handler, Handler, Args}} ->
{Hib, Reply, MSL1} = server_add_handler(Handler, Args, MSL),
- ?reply(Reply),
+ reply(Tag, Reply),
loop(Parent, ServerName, MSL1, Debug, Hib);
- {From, Tag, {add_sup_handler, Handler, Args, SupP}} ->
+ {_From, Tag, {add_sup_handler, Handler, Args, SupP}} ->
{Hib, Reply, MSL1} = server_add_sup_handler(Handler, Args, MSL, SupP),
- ?reply(Reply),
+ reply(Tag, Reply),
loop(Parent, ServerName, MSL1, Debug, Hib);
- {From, Tag, {delete_handler, Handler, Args}} ->
+ {_From, Tag, {delete_handler, Handler, Args}} ->
{Reply, MSL1} = server_delete_handler(Handler, Args, MSL,
ServerName),
- ?reply(Reply),
+ reply(Tag, Reply),
loop(Parent, ServerName, MSL1, Debug, false);
- {From, Tag, {swap_handler, Handler1, Args1, Handler2, Args2}} ->
+ {_From, Tag, {swap_handler, Handler1, Args1, Handler2, Args2}} ->
{Hib, Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2,
Args2, MSL, ServerName),
- ?reply(Reply),
+ reply(Tag, Reply),
loop(Parent, ServerName, MSL1, Debug, Hib);
- {From, Tag, {swap_sup_handler, Handler1, Args1, Handler2, Args2,
+ {_From, Tag, {swap_sup_handler, Handler1, Args1, Handler2, Args2,
Sup}} ->
{Hib, Reply, MSL1} = server_swap_handler(Handler1, Args1, Handler2,
Args2, MSL, Sup, ServerName),
- ?reply(Reply),
+ reply(Tag, Reply),
loop(Parent, ServerName, MSL1, Debug, Hib);
- {From, Tag, stop} ->
+ {_From, Tag, stop} ->
catch terminate_server(normal, Parent, MSL, ServerName),
- ?reply(ok);
- {From, Tag, which_handlers} ->
- ?reply(the_handlers(MSL)),
+ reply(Tag, ok);
+ {_From, Tag, which_handlers} ->
+ reply(Tag, the_handlers(MSL)),
loop(Parent, ServerName, MSL, Debug, false);
- {From, Tag, get_modules} ->
- ?reply(get_modules(MSL)),
+ {_From, Tag, get_modules} ->
+ reply(Tag, get_modules(MSL)),
loop(Parent, ServerName, MSL, Debug, false);
Other ->
{Hib, MSL1} = server_notify(Other, handle_info, MSL, ServerName),
@@ -303,6 +301,10 @@ terminate_server(Reason, Parent, MSL, ServerName) ->
do_unlink(Parent, MSL),
exit(Reason).
+reply({From, Ref}, Msg) ->
+ From ! {Ref, Msg},
+ ok.
+
%% unlink the supervisor process of all supervised handlers.
%% We do not want a handler supervisor to EXIT due to the
%% termination of the event manager (server).
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index e914f7d0b2..5afe3e8b09 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -594,7 +594,8 @@ reply(Name, {To, Tag}, Reply, Debug, StateName) ->
terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
case catch Mod:terminate(Reason, StateName, StateData) of
{'EXIT', R} ->
- error_info(R, Name, Msg, StateName, StateData, Debug),
+ FmtStateData = format_status(terminate, Mod, get(), StateData),
+ error_info(R, Name, Msg, StateName, FmtStateData, Debug),
exit(R);
_ ->
case Reason of
@@ -605,17 +606,7 @@ terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
{shutdown,_}=Shutdown ->
exit(Shutdown);
_ ->
- FmtStateData =
- case erlang:function_exported(Mod, format_status, 2) of
- true ->
- Args = [get(), StateData],
- case catch Mod:format_status(terminate, Args) of
- {'EXIT', _} -> StateData;
- Else -> Else
- end;
- _ ->
- StateData
- end,
+ FmtStateData = format_status(terminate, Mod, get(), StateData),
error_info(Reason,Name,Msg,StateName,FmtStateData,Debug),
exit(Reason)
end
@@ -680,21 +671,29 @@ format_status(Opt, StatusData) ->
Header = gen:format_status_header("Status for state machine",
Name),
Log = sys:get_debug(log, Debug, []),
- DefaultStatus = [{data, [{"StateData", StateData}]}],
- Specfic =
- case erlang:function_exported(Mod, format_status, 2) of
- true ->
- case catch Mod:format_status(Opt,[PDict,StateData]) of
- {'EXIT', _} -> DefaultStatus;
- StatusList when is_list(StatusList) -> StatusList;
- Else -> [Else]
- end;
- _ ->
- DefaultStatus
- end,
+ Specfic = format_status(Opt, Mod, PDict, StateData),
+ Specfic = case format_status(Opt, Mod, PDict, StateData) of
+ S when is_list(S) -> S;
+ S -> [S]
+ end,
[{header, Header},
{data, [{"Status", SysState},
{"Parent", Parent},
{"Logged events", Log},
{"StateName", StateName}]} |
Specfic].
+
+format_status(Opt, Mod, PDict, State) ->
+ DefStatus = case Opt of
+ terminate -> State;
+ _ -> [{data, [{"StateData", State}]}]
+ end,
+ case erlang:function_exported(Mod, format_status, 2) of
+ true ->
+ case catch Mod:format_status(Opt, [PDict, State]) of
+ {'EXIT', _} -> DefStatus;
+ Else -> Else
+ end;
+ _ ->
+ DefStatus
+ end.
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 202a931fae..528dd23e1c 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -567,28 +567,88 @@ start_monitor(Node, Name) when is_atom(Node), is_atom(Name) ->
end
end.
+%% ---------------------------------------------------
+%% Helper functions for try-catch of callbacks.
+%% Returns the return value of the callback, or
+%% {'EXIT', ExitReason, ReportReason} (if an exception occurs)
+%%
+%% ExitReason is the reason that shall be used when the process
+%% terminates.
+%%
+%% ReportReason is the reason that shall be printed in the error
+%% report.
+%%
+%% These functions are introduced in order to add the stack trace in
+%% the error report produced when a callback is terminated with
+%% erlang:exit/1 (OTP-12263).
+%% ---------------------------------------------------
+
+try_dispatch({'$gen_cast', Msg}, Mod, State) ->
+ try_dispatch(Mod, handle_cast, Msg, State);
+try_dispatch(Info, Mod, State) ->
+ try_dispatch(Mod, handle_info, Info, State).
+
+try_dispatch(Mod, Func, Msg, State) ->
+ try
+ {ok, Mod:Func(Msg, State)}
+ catch
+ throw:R ->
+ {ok, R};
+ error:R ->
+ Stacktrace = erlang:get_stacktrace(),
+ {'EXIT', {R, Stacktrace}, {R, Stacktrace}};
+ exit:R ->
+ Stacktrace = erlang:get_stacktrace(),
+ {'EXIT', R, {R, Stacktrace}}
+ end.
+
+try_handle_call(Mod, Msg, From, State) ->
+ try
+ {ok, Mod:handle_call(Msg, From, State)}
+ catch
+ throw:R ->
+ {ok, R};
+ error:R ->
+ Stacktrace = erlang:get_stacktrace(),
+ {'EXIT', {R, Stacktrace}, {R, Stacktrace}};
+ exit:R ->
+ Stacktrace = erlang:get_stacktrace(),
+ {'EXIT', R, {R, Stacktrace}}
+ end.
+
+try_terminate(Mod, Reason, State) ->
+ try
+ {ok, Mod:terminate(Reason, State)}
+ catch
+ throw:R ->
+ {ok, R};
+ error:R ->
+ Stacktrace = erlang:get_stacktrace(),
+ {'EXIT', {R, Stacktrace}, {R, Stacktrace}};
+ exit:R ->
+ Stacktrace = erlang:get_stacktrace(),
+ {'EXIT', R, {R, Stacktrace}}
+ end.
+
+
%%% ---------------------------------------------------
%%% Message handling functions
%%% ---------------------------------------------------
-dispatch({'$gen_cast', Msg}, Mod, State) ->
- Mod:handle_cast(Msg, State);
-dispatch(Info, Mod, State) ->
- Mod:handle_info(Info, State).
-
handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod) ->
- case catch Mod:handle_call(Msg, From, State) of
- {reply, Reply, NState} ->
+ Result = try_handle_call(Mod, Msg, From, State),
+ case Result of
+ {ok, {reply, Reply, NState}} ->
reply(From, Reply),
loop(Parent, Name, NState, Mod, infinity, []);
- {reply, Reply, NState, Time1} ->
+ {ok, {reply, Reply, NState, Time1}} ->
reply(From, Reply),
loop(Parent, Name, NState, Mod, Time1, []);
- {noreply, NState} ->
+ {ok, {noreply, NState}} ->
loop(Parent, Name, NState, Mod, infinity, []);
- {noreply, NState, Time1} ->
+ {ok, {noreply, NState, Time1}} ->
loop(Parent, Name, NState, Mod, Time1, []);
- {stop, Reason, Reply, NState} ->
+ {ok, {stop, Reason, Reply, NState}} ->
{'EXIT', R} =
(catch terminate(Reason, Name, Msg, Mod, NState, [])),
reply(From, Reply),
@@ -596,26 +656,27 @@ handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod) ->
Other -> handle_common_reply(Other, Parent, Name, Msg, Mod, State)
end;
handle_msg(Msg, Parent, Name, State, Mod) ->
- Reply = (catch dispatch(Msg, Mod, State)),
+ Reply = try_dispatch(Msg, Mod, State),
handle_common_reply(Reply, Parent, Name, Msg, Mod, State).
handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, Debug) ->
- case catch Mod:handle_call(Msg, From, State) of
- {reply, Reply, NState} ->
+ Result = try_handle_call(Mod, Msg, From, State),
+ case Result of
+ {ok, {reply, Reply, NState}} ->
Debug1 = reply(Name, From, Reply, NState, Debug),
loop(Parent, Name, NState, Mod, infinity, Debug1);
- {reply, Reply, NState, Time1} ->
+ {ok, {reply, Reply, NState, Time1}} ->
Debug1 = reply(Name, From, Reply, NState, Debug),
loop(Parent, Name, NState, Mod, Time1, Debug1);
- {noreply, NState} ->
+ {ok, {noreply, NState}} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name,
{noreply, NState}),
loop(Parent, Name, NState, Mod, infinity, Debug1);
- {noreply, NState, Time1} ->
+ {ok, {noreply, NState, Time1}} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name,
{noreply, NState}),
loop(Parent, Name, NState, Mod, Time1, Debug1);
- {stop, Reason, Reply, NState} ->
+ {ok, {stop, Reason, Reply, NState}} ->
{'EXIT', R} =
(catch terminate(Reason, Name, Msg, Mod, NState, Debug)),
_ = reply(Name, From, Reply, NState, Debug),
@@ -624,39 +685,39 @@ handle_msg({'$gen_call', From, Msg}, Parent, Name, State, Mod, Debug) ->
handle_common_reply(Other, Parent, Name, Msg, Mod, State, Debug)
end;
handle_msg(Msg, Parent, Name, State, Mod, Debug) ->
- Reply = (catch dispatch(Msg, Mod, State)),
+ Reply = try_dispatch(Msg, Mod, State),
handle_common_reply(Reply, Parent, Name, Msg, Mod, State, Debug).
handle_common_reply(Reply, Parent, Name, Msg, Mod, State) ->
case Reply of
- {noreply, NState} ->
+ {ok, {noreply, NState}} ->
loop(Parent, Name, NState, Mod, infinity, []);
- {noreply, NState, Time1} ->
+ {ok, {noreply, NState, Time1}} ->
loop(Parent, Name, NState, Mod, Time1, []);
- {stop, Reason, NState} ->
+ {ok, {stop, Reason, NState}} ->
terminate(Reason, Name, Msg, Mod, NState, []);
- {'EXIT', What} ->
- terminate(What, Name, Msg, Mod, State, []);
- _ ->
- terminate({bad_return_value, Reply}, Name, Msg, Mod, State, [])
+ {'EXIT', ExitReason, ReportReason} ->
+ terminate(ExitReason, ReportReason, Name, Msg, Mod, State, []);
+ {ok, BadReply} ->
+ terminate({bad_return_value, BadReply}, Name, Msg, Mod, State, [])
end.
handle_common_reply(Reply, Parent, Name, Msg, Mod, State, Debug) ->
case Reply of
- {noreply, NState} ->
+ {ok, {noreply, NState}} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name,
{noreply, NState}),
loop(Parent, Name, NState, Mod, infinity, Debug1);
- {noreply, NState, Time1} ->
+ {ok, {noreply, NState, Time1}} ->
Debug1 = sys:handle_debug(Debug, fun print_event/3, Name,
{noreply, NState}),
loop(Parent, Name, NState, Mod, Time1, Debug1);
- {stop, Reason, NState} ->
+ {ok, {stop, Reason, NState}} ->
terminate(Reason, Name, Msg, Mod, NState, Debug);
- {'EXIT', What} ->
- terminate(What, Name, Msg, Mod, State, Debug);
- _ ->
- terminate({bad_return_value, Reply}, Name, Msg, Mod, State, Debug)
+ {'EXIT', ExitReason, ReportReason} ->
+ terminate(ExitReason, ReportReason, Name, Msg, Mod, State, Debug);
+ {ok, BadReply} ->
+ terminate({bad_return_value, BadReply}, Name, Msg, Mod, State, Debug)
end.
reply(Name, {To, Tag}, Reply, State, Debug) ->
@@ -718,12 +779,16 @@ print_event(Dev, Event, Name) ->
%%% ---------------------------------------------------
terminate(Reason, Name, Msg, Mod, State, Debug) ->
- case catch Mod:terminate(Reason, State) of
- {'EXIT', R} ->
- error_info(R, Name, Msg, State, Debug),
- exit(R);
+ terminate(Reason, Reason, Name, Msg, Mod, State, Debug).
+terminate(ExitReason, ReportReason, Name, Msg, Mod, State, Debug) ->
+ Reply = try_terminate(Mod, ExitReason, State),
+ case Reply of
+ {'EXIT', ExitReason1, ReportReason1} ->
+ FmtState = format_status(terminate, Mod, get(), State),
+ error_info(ReportReason1, Name, Msg, FmtState, Debug),
+ exit(ExitReason1);
_ ->
- case Reason of
+ case ExitReason of
normal ->
exit(normal);
shutdown ->
@@ -731,19 +796,9 @@ terminate(Reason, Name, Msg, Mod, State, Debug) ->
{shutdown,_}=Shutdown ->
exit(Shutdown);
_ ->
- FmtState =
- case erlang:function_exported(Mod, format_status, 2) of
- true ->
- Args = [get(), State],
- case catch Mod:format_status(terminate, Args) of
- {'EXIT', _} -> State;
- Else -> Else
- end;
- _ ->
- State
- end,
- error_info(Reason, Name, Msg, FmtState, Debug),
- exit(Reason)
+ FmtState = format_status(terminate, Mod, get(), State),
+ error_info(ReportReason, Name, Msg, FmtState, Debug),
+ exit(ExitReason)
end
end.
@@ -875,23 +930,29 @@ name_to_pid(Name) ->
%%-----------------------------------------------------------------
format_status(Opt, StatusData) ->
[PDict, SysState, Parent, Debug, [Name, State, Mod, _Time]] = StatusData,
- Header = gen:format_status_header("Status for generic server",
- Name),
+ Header = gen:format_status_header("Status for generic server", Name),
Log = sys:get_debug(log, Debug, []),
- DefaultStatus = [{data, [{"State", State}]}],
- Specfic =
- case erlang:function_exported(Mod, format_status, 2) of
- true ->
- case catch Mod:format_status(Opt, [PDict, State]) of
- {'EXIT', _} -> DefaultStatus;
- StatusList when is_list(StatusList) -> StatusList;
- Else -> [Else]
- end;
- _ ->
- DefaultStatus
- end,
+ Specfic = case format_status(Opt, Mod, PDict, State) of
+ S when is_list(S) -> S;
+ S -> [S]
+ end,
[{header, Header},
{data, [{"Status", SysState},
{"Parent", Parent},
{"Logged events", Log}]} |
Specfic].
+
+format_status(Opt, Mod, PDict, State) ->
+ DefStatus = case Opt of
+ terminate -> State;
+ _ -> [{data, [{"State", State}]}]
+ end,
+ case erlang:function_exported(Mod, format_status, 2) of
+ true ->
+ case catch Mod:format_status(Opt, [PDict, State]) of
+ {'EXIT', _} -> DefStatus;
+ Else -> Else
+ end;
+ _ ->
+ DefStatus
+ end.
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index 27e2a82b41..b9ace2f442 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -566,12 +566,23 @@ request(Name, Request) when is_atom(Name) ->
execute_request(Pid, {Convert,Converted}) ->
Mref = erlang:monitor(process, Pid),
- Pid ! {io_request,self(),Pid,Converted},
- if
- Convert ->
- convert_binaries(wait_io_mon_reply(Pid, Mref));
- true ->
- wait_io_mon_reply(Pid, Mref)
+ Pid ! {io_request,self(),Mref,Converted},
+
+ receive
+ {io_reply, Mref, Reply} ->
+ erlang:demonitor(Mref, [flush]),
+ if
+ Convert ->
+ convert_binaries(Reply);
+ true ->
+ Reply
+ end;
+ {'DOWN', Mref, _, _, _} ->
+ receive
+ {'EXIT', Pid, _What} -> true
+ after 0 -> true
+ end,
+ {error,terminated}
end.
requests(Requests) -> %Requests as atomic action
@@ -597,26 +608,6 @@ default_input() ->
default_output() ->
group_leader().
-wait_io_mon_reply(From, Mref) ->
- receive
- {io_reply, From, Reply} ->
- erlang:demonitor(Mref, [flush]),
- Reply;
- {'EXIT', From, _What} ->
- receive
- {'DOWN', Mref, _, _, _} -> true
- after 0 -> true
- end,
- {error,terminated};
- {'DOWN', Mref, _, _, _} ->
- receive
- {'EXIT', From, _What} -> true
- after 0 -> true
- end,
- {error,terminated}
- end.
-
-
%% io_requests(Requests)
%% Transform requests into correct i/o server messages. Only handle the
%% one we KNOW must be changed, others, including incorrect ones, are
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 56e15a17ec..89ae6fb187 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -255,7 +255,7 @@ term(T, none, _Adj, none, _Pad) -> T;
term(T, none, Adj, P, Pad) -> term(T, P, Adj, P, Pad);
term(T, F, Adj, P0, Pad) ->
L = lists:flatlength(T),
- P = case P0 of none -> erlang:min(L, F); _ -> P0 end,
+ P = erlang:min(L, case P0 of none -> F; _ -> min(P0, F) end),
if
L > P ->
adjust(chars($*, P), chars(Pad, F-P), Adj);
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index 4ef1638e6d..ba4d6a5c87 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -24,6 +24,7 @@
map/2,
size/1,
without/2,
+ with/2,
get/3
]).
@@ -133,10 +134,10 @@ to_list(_) -> erlang:nif_error(undef).
update(_,_,_) -> erlang:nif_error(undef).
--spec values(Map) -> Keys when
+-spec values(Map) -> Values when
Map :: map(),
- Keys :: [Key],
- Key :: term().
+ Values :: [Value],
+ Value :: term().
values(_) -> erlang:nif_error(undef).
@@ -201,3 +202,13 @@ size(Map) when is_map(Map) ->
without(Ks, M) when is_list(Ks), is_map(M) ->
maps:from_list([{K,V}||{K,V} <- maps:to_list(M), not lists:member(K, Ks)]).
+
+
+-spec with(Ks, Map1) -> Map2 when
+ Ks :: [K],
+ Map1 :: map(),
+ Map2 :: map(),
+ K :: term().
+
+with(Ks, M) when is_list(Ks), is_map(M) ->
+ maps:from_list([{K,V}||{K,V} <- maps:to_list(M), lists:member(K, Ks)]).
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 27dfcf52e1..97564e2e44 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -725,10 +725,10 @@ transform_head([V],OuterBound) ->
th(NewV,NewBind,OuterBound).
-toplevel_head_match({match,Line,{var,_,VName},Expr},B,OB) ->
+toplevel_head_match({match,_,{var,Line,VName},Expr},B,OB) ->
warn_var_clash(Line,VName,OB),
{Expr,new_bind({VName,'$_'},B)};
-toplevel_head_match({match,Line,Expr,{var,_,VName}},B,OB) ->
+toplevel_head_match({match,_,Expr,{var,Line,VName}},B,OB) ->
warn_var_clash(Line,VName,OB),
{Expr,new_bind({VName,'$_'},B)};
toplevel_head_match(Other,B,_OB) ->
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index c0ee8799c8..6c25beabe9 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -421,13 +421,13 @@ obsolete_1(ssh_cm, stop_listener, 1) ->
obsolete_1(ssh_cm, session_open, A) when A =:= 2; A =:= 4 ->
{removed,{ssh_connection,session_channel,A},"R14B"};
obsolete_1(ssh_cm, direct_tcpip, A) when A =:= 6; A =:= 8 ->
- {removed,{ssh_connection,direct_tcpip,A}};
+ {removed,{ssh_connection,direct_tcpip,A},"R14B"};
obsolete_1(ssh_cm, tcpip_forward, 3) ->
{removed,{ssh_connection,tcpip_forward,3},"R14B"};
obsolete_1(ssh_cm, cancel_tcpip_forward, 3) ->
{removed,{ssh_connection,cancel_tcpip_forward,3},"R14B"};
obsolete_1(ssh_cm, open_pty, A) when A =:= 3; A =:= 7; A =:= 9 ->
- {removed,{ssh_connection,open_pty,A},"R14"};
+ {removed,{ssh_connection,open_pty,A},"R14B"};
obsolete_1(ssh_cm, setenv, 5) ->
{removed,{ssh_connection,setenv,5},"R14B"};
obsolete_1(ssh_cm, shell, 2) ->
@@ -441,11 +441,11 @@ obsolete_1(ssh_cm, winch, A) when A =:= 4; A =:= 6 ->
obsolete_1(ssh_cm, signal, 3) ->
{removed,{ssh_connection,signal,3},"R14B"};
obsolete_1(ssh_cm, attach, A) when A =:= 2; A =:= 3 ->
- {removed,{ssh,attach,A}};
+ {removed,"no longer useful; removed in R14B"};
obsolete_1(ssh_cm, detach, 2) ->
- {removed,"no longer useful; will be removed in R14B"};
+ {removed,"no longer useful; removed in R14B"};
obsolete_1(ssh_cm, set_user_ack, 4) ->
- {removed,"no longer useful; will be removed in R14B"};
+ {removed,"no longer useful; removed in R14B"};
obsolete_1(ssh_cm, adjust_window, 3) ->
{removed,{ssh_connection,adjust_window,3},"R14B"};
obsolete_1(ssh_cm, close, 2) ->
@@ -461,9 +461,9 @@ obsolete_1(ssh_cm, send_ack, A) when 3 =< A, A =< 5 ->
obsolete_1(ssh_ssh, connect, A) when 1 =< A, A =< 3 ->
{removed,{ssh,shell,A},"R14B"};
obsolete_1(ssh_sshd, listen, A) when 0 =< A, A =< 3 ->
- {removed,{ssh,daemon,[1,2,3]},"R14"};
+ {removed,{ssh,daemon,[1,2,3]},"R14B"};
obsolete_1(ssh_sshd, stop, 1) ->
- {removed,{ssh,stop_listener,1}};
+ {removed,{ssh,stop_listener,1},"R14B"};
%% Added in R13A.
obsolete_1(regexp, _, _) ->
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 1eb6fc2e86..bf2a4e7ac5 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -216,10 +216,8 @@ ensure_link(SpawnOpts) ->
init_p(Parent, Ancestors, Fun) when is_function(Fun) ->
put('$ancestors', [Parent|Ancestors]),
- {module,Mod} = erlang:fun_info(Fun, module),
- {name,Name} = erlang:fun_info(Fun, name),
- {arity,Arity} = erlang:fun_info(Fun, arity),
- put('$initial_call', {Mod,Name,Arity}),
+ Mfa = erlang:fun_info_mfa(Fun),
+ put('$initial_call', Mfa),
try
Fun()
catch
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index 3b90542452..679c13f0cf 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -371,6 +371,14 @@ expand_expr({bc,L,E,Qs}, C) ->
{bc,L,expand_expr(E, C),expand_quals(Qs, C)};
expand_expr({tuple,L,Elts}, C) ->
{tuple,L,expand_exprs(Elts, C)};
+expand_expr({map,L,Es}, C) ->
+ {map,L,expand_exprs(Es, C)};
+expand_expr({map,L,Arg,Es}, C) ->
+ {map,L,expand_expr(Arg, C),expand_exprs(Es, C)};
+expand_expr({map_field_assoc,L,K,V}, C) ->
+ {map_field_assoc,L,expand_expr(K, C),expand_expr(V, C)};
+expand_expr({map_field_exact,L,K,V}, C) ->
+ {map_field_exact,L,expand_expr(K, C),expand_expr(V, C)};
expand_expr({record_index,L,Name,F}, C) ->
{record_index,L,Name,expand_expr(F, C)};
expand_expr({record,L,Name,Is}, C) ->
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index d388410de0..aa9899da3b 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -103,7 +103,7 @@
dets]},
{applications, [kernel]},
{env, []},
- {runtime_dependencies, ["sasl-2.4","kernel-3.0","erts-6.0","crypto-3.3",
+ {runtime_dependencies, ["sasl-2.4","kernel-3.0.2","erts-6.2","crypto-3.3",
"compiler-5.0"]}
]}.
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 22eefb2514..7802ea884f 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -17,9 +17,11 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R17
+ [{<<"2\\.[1-2](\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.1-17.3
+ {<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.0
{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R16
%% Down to - max one major revision back
- [{<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R17
+ [{<<"2\\.[1-2](\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.1-17.3
+ {<<"2\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% 17.0
{<<"1\\.19(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R16
}.
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index e25cc25f57..d3ba09ce82 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -46,7 +46,7 @@
{N :: non_neg_integer(),
[{Event :: system_event(),
FuncState :: _,
- FormFunc :: dbg_fun()}]}}
+ FormFunc :: format_fun()}]}}
| {'statistics', {file:date_time(),
{'reductions', non_neg_integer()},
MessagesIn :: non_neg_integer(),
@@ -57,6 +57,10 @@
Event :: system_event(),
ProcState :: _) -> 'done' | (NewFuncState :: _)).
+-type format_fun() :: fun((Device :: io:device() | file:io_device(),
+ Event :: system_event(),
+ Extra :: term()) -> any()).
+
%%-----------------------------------------------------------------
%% System messages
%%-----------------------------------------------------------------
@@ -346,7 +350,7 @@ handle_system_msg(SysState, Msg, From, Parent, Mod, Debug, Misc, Hib) ->
%%-----------------------------------------------------------------
-spec handle_debug(Debug, FormFunc, Extra, Event) -> [dbg_opt()] when
Debug :: [dbg_opt()],
- FormFunc :: dbg_fun(),
+ FormFunc :: format_fun(),
Extra :: term(),
Event :: system_event().
handle_debug([{trace, true} | T], FormFunc, State, Event) ->