aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/src')
-rw-r--r--lib/stdlib/src/Makefile3
-rw-r--r--lib/stdlib/src/array.erl2
-rw-r--r--lib/stdlib/src/base64.erl2
-rw-r--r--lib/stdlib/src/binary.erl2
-rw-r--r--lib/stdlib/src/c.erl2
-rw-r--r--lib/stdlib/src/calendar.erl2
-rw-r--r--lib/stdlib/src/dets.hrl2
-rw-r--r--lib/stdlib/src/dets_server.erl2
-rw-r--r--lib/stdlib/src/dets_sup.erl2
-rw-r--r--lib/stdlib/src/digraph_utils.erl2
-rw-r--r--lib/stdlib/src/edlin.erl2
-rw-r--r--lib/stdlib/src/edlin_expand.erl2
-rw-r--r--lib/stdlib/src/epp.erl72
-rw-r--r--lib/stdlib/src/erl_bits.erl2
-rw-r--r--lib/stdlib/src/erl_compile.erl2
-rw-r--r--lib/stdlib/src/erl_internal.erl2
-rw-r--r--lib/stdlib/src/erl_lint.erl108
-rw-r--r--lib/stdlib/src/erl_parse.yrl14
-rw-r--r--lib/stdlib/src/erl_posix_msg.erl2
-rw-r--r--lib/stdlib/src/erl_pp.erl26
-rw-r--r--lib/stdlib/src/erl_tar.erl2
-rw-r--r--lib/stdlib/src/error_logger_file_h.erl2
-rw-r--r--lib/stdlib/src/error_logger_tty_h.erl2
-rw-r--r--lib/stdlib/src/ets.erl2
-rw-r--r--lib/stdlib/src/eval_bits.erl2
-rw-r--r--lib/stdlib/src/filelib.erl2
-rw-r--r--lib/stdlib/src/filename.erl181
-rw-r--r--lib/stdlib/src/gen.erl121
-rw-r--r--lib/stdlib/src/gen_event.erl11
-rw-r--r--lib/stdlib/src/gen_fsm.erl85
-rw-r--r--lib/stdlib/src/gen_server.erl112
-rw-r--r--lib/stdlib/src/gen_statem.erl1308
-rw-r--r--lib/stdlib/src/io_lib.erl18
-rw-r--r--lib/stdlib/src/io_lib_format.erl2
-rw-r--r--lib/stdlib/src/io_lib_fread.erl2
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl2
-rw-r--r--lib/stdlib/src/lib.erl2
-rw-r--r--lib/stdlib/src/lists.erl15
-rw-r--r--lib/stdlib/src/log_mf_h.erl2
-rw-r--r--lib/stdlib/src/maps.erl61
-rw-r--r--lib/stdlib/src/math.erl2
-rw-r--r--lib/stdlib/src/ordsets.erl2
-rw-r--r--lib/stdlib/src/otp_internal.erl121
-rw-r--r--lib/stdlib/src/pool.erl2
-rw-r--r--lib/stdlib/src/proc_lib.erl25
-rw-r--r--lib/stdlib/src/proplists.erl2
-rw-r--r--lib/stdlib/src/queue.erl2
-rw-r--r--lib/stdlib/src/rand.erl10
-rw-r--r--lib/stdlib/src/random.erl2
-rw-r--r--lib/stdlib/src/re.erl2
-rw-r--r--lib/stdlib/src/sets.erl2
-rw-r--r--lib/stdlib/src/shell_default.erl2
-rw-r--r--lib/stdlib/src/slave.erl2
-rw-r--r--lib/stdlib/src/sofs.erl2
-rw-r--r--lib/stdlib/src/stdlib.app.src3
-rw-r--r--lib/stdlib/src/stdlib.appup.src10
-rw-r--r--lib/stdlib/src/string.erl2
-rw-r--r--lib/stdlib/src/supervisor.erl6
-rw-r--r--lib/stdlib/src/supervisor_bridge.erl2
-rw-r--r--lib/stdlib/src/sys.erl2
-rw-r--r--lib/stdlib/src/timer.erl2
-rw-r--r--lib/stdlib/src/win32reg.erl2
62 files changed, 1926 insertions, 468 deletions
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 9f4a446ea0..302834f9d0 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2015. All Rights Reserved.
+# Copyright Ericsson AB 1996-2016. 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.
@@ -85,6 +85,7 @@ MODULES= \
gen_event \
gen_fsm \
gen_server \
+ gen_statem \
io \
io_lib \
io_lib_format \
diff --git a/lib/stdlib/src/array.erl b/lib/stdlib/src/array.erl
index c749dd008b..d5757dda5b 100644
--- a/lib/stdlib/src/array.erl
+++ b/lib/stdlib/src/array.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. 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.
diff --git a/lib/stdlib/src/base64.erl b/lib/stdlib/src/base64.erl
index ac532f7ee0..bf259e6691 100644
--- a/lib/stdlib/src/base64.erl
+++ b/lib/stdlib/src/base64.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2016. 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.
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index fb0c395d70..ccc827ca2d 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2016. 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.
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index a8844d757d..ad4915eabe 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl
index 074c504e00..55a0cfc9a1 100644
--- a/lib/stdlib/src/calendar.erl
+++ b/lib/stdlib/src/calendar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/dets.hrl b/lib/stdlib/src/dets.hrl
index be51e1a89c..6ebeb96156 100644
--- a/lib/stdlib/src/dets.hrl
+++ b/lib/stdlib/src/dets.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. 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.
diff --git a/lib/stdlib/src/dets_server.erl b/lib/stdlib/src/dets_server.erl
index e3c9447c6f..b02d6ae159 100644
--- a/lib/stdlib/src/dets_server.erl
+++ b/lib/stdlib/src/dets_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. 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.
diff --git a/lib/stdlib/src/dets_sup.erl b/lib/stdlib/src/dets_sup.erl
index e0087c58b4..43609cb8a1 100644
--- a/lib/stdlib/src/dets_sup.erl
+++ b/lib/stdlib/src/dets_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2016. 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.
diff --git a/lib/stdlib/src/digraph_utils.erl b/lib/stdlib/src/digraph_utils.erl
index ef4c2e94fe..4aa9ae810d 100644
--- a/lib/stdlib/src/digraph_utils.erl
+++ b/lib/stdlib/src/digraph_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. 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.
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index 0e9c457de2..71e8471c45 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/edlin_expand.erl b/lib/stdlib/src/edlin_expand.erl
index 6dd736da4c..ec64470461 100644
--- a/lib/stdlib/src/edlin_expand.erl
+++ b/lib/stdlib/src/edlin_expand.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. 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.
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 936c095aef..73934e0e3c 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -43,13 +43,18 @@
-type name() :: atom().
-type argspec() :: 'none' %No arguments
| non_neg_integer(). %Number of arguments
+-type argnames() :: [atom()].
-type tokens() :: [erl_scan:token()].
+-type predef() :: 'undefined' | {'none', tokens()}.
+-type userdef() :: {argspec(), {argnames(), tokens()}}.
-type used() :: {name(), argspec()}.
-type function_name_type() :: 'undefined'
| {atom(),non_neg_integer()}
| tokens().
+-type warning_info() :: {erl_anno:location(), module(), term()}.
+
-define(DEFAULT_ENCODING, utf8).
%% Epp state record.
@@ -63,7 +68,7 @@
sstk=[] :: [#epp{}], %State stack
path=[] :: [file:name()], %Include-path
macs = #{} %Macros (don't care locations)
- :: #{name() => {argspec(), tokens()}},
+ :: #{name() => predef() | [userdef()]},
uses = #{} %Macro use structure
:: #{name() => [{argspec(), [used()]}]},
default_encoding = ?DEFAULT_ENCODING :: source_encoding(),
@@ -155,11 +160,13 @@ scan_erl_form(Epp) ->
epp_request(Epp, scan_erl_form).
-spec parse_erl_form(Epp) ->
- {'ok', AbsForm} | {'eof', Line} | {error, ErrorInfo} when
+ {'ok', AbsForm} | {error, ErrorInfo} |
+ {'warning',WarningInfo} | {'eof',Line} when
Epp :: epp_handle(),
AbsForm :: erl_parse:abstract_form(),
Line :: erl_anno:line(),
- ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
+ WarningInfo :: warning_info().
parse_erl_form(Epp) ->
case epp_request(Epp, scan_erl_form) of
@@ -216,6 +223,10 @@ format_error({illegal_function_usage,Macro}) ->
io_lib:format("?~s must not begin a form", [Macro]);
format_error({'NYI',What}) ->
io_lib:format("not yet implemented '~s'", [What]);
+format_error({error,Term}) ->
+ io_lib:format("-error(~p).", [Term]);
+format_error({warning,Term}) ->
+ io_lib:format("-warning(~p).", [Term]);
format_error(E) -> file:format_error(E).
-spec parse_file(FileName, IncludePath, PredefMacros) ->
@@ -260,9 +271,11 @@ parse_file(Ifile, Options) ->
-spec parse_file(Epp) -> [Form] when
Epp :: epp_handle(),
- Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line},
+ Form :: erl_parse:abstract_form() | {'error', ErrorInfo} |
+ {'warning',WarningInfo} | {'eof',Line},
Line :: erl_anno:line(),
- ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
+ WarningInfo :: warning_info().
parse_file(Epp) ->
case parse_erl_form(Epp) of
@@ -270,6 +283,8 @@ parse_file(Epp) ->
[Form|parse_file(Epp)];
{error,E} ->
[{error,E}|parse_file(Epp)];
+ {warning,W} ->
+ [{warning,W}|parse_file(Epp)];
{eof,Location} ->
[{eof,erl_anno:new(Location)}]
end.
@@ -749,6 +764,10 @@ scan_toks([{'-',_Lh},{atom,_Ld,define}=Define|Toks], From, St) ->
scan_define(Toks, Define, From, St);
scan_toks([{'-',_Lh},{atom,_Ld,undef}=Undef|Toks], From, St) ->
scan_undef(Toks, Undef, From, St);
+scan_toks([{'-',_Lh},{atom,_Ld,error}=Error|Toks], From, St) ->
+ scan_err_warn(Toks, Error, From, St);
+scan_toks([{'-',_Lh},{atom,_Ld,warning}=Warn|Toks], From, St) ->
+ scan_err_warn(Toks, Warn, From, St);
scan_toks([{'-',_Lh},{atom,_Li,include}=Inc|Toks], From, St) ->
scan_include(Toks, Inc, From, St);
scan_toks([{'-',_Lh},{atom,_Li,include_lib}=IncLib|Toks], From, St) ->
@@ -804,6 +823,24 @@ scan_extends([{atom,Ln,A}=ModAtom,{')',_Lr}|_Ts], Ms0) ->
Ms#{'BASE_MODULE_STRING':={none,[{string,Ln,ModString}]}};
scan_extends(_Ts, Ms) -> Ms.
+scan_err_warn([{'(',_}|_]=Toks0, {atom,_,Tag}=Token, From, St) ->
+ try expand_macros(Toks0, St) of
+ Toks when is_list(Toks) ->
+ case erl_parse:parse_term(Toks) of
+ {ok,Term} ->
+ epp_reply(From, {Tag,{loc(Token),epp,{Tag,Term}}});
+ {error,_} ->
+ epp_reply(From, {error,{loc(Token),epp,{bad,Tag}}})
+ end
+ catch
+ _:_ ->
+ epp_reply(From, {error,{loc(Token),epp,{bad,Tag}}})
+ end,
+ wait_req_scan(St);
+scan_err_warn(_Toks, {atom,_,Tag}=Token, From, St) ->
+ epp_reply(From, {error,{loc(Token),epp,{bad,Tag}}}),
+ wait_req_scan(St).
+
%% scan_define(Tokens, DefineToken, From, EppState)
scan_define([{'(',_Lp},{Type,_Lm,_}=Mac|Toks], Def, From, St)
@@ -930,9 +967,15 @@ scan_include(_Toks, Inc, From, St) ->
%% normal search path, if not we assume that the first directory name
%% is a library name, find its true directory and try with that.
-find_lib_dir(NewName) ->
- [Lib | Rest] = filename:split(NewName),
- {code:lib_dir(list_to_atom(Lib)), Rest}.
+expand_lib_dir(Name) ->
+ try
+ [App|Path] = filename:split(Name),
+ LibDir = code:lib_dir(list_to_atom(App)),
+ {ok,fname_join([LibDir|Path])}
+ catch
+ _:_ ->
+ error
+ end.
scan_include_lib([{'(',_Llp},{string,_Lf,_NewName0},{')',_Lrp},{dot,_Ld}],
Inc, From, St)
@@ -947,12 +990,11 @@ scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
{ok,NewF,Pname} ->
wait_req_scan(enter_file2(NewF, Pname, From, St, Loc));
{error,_E1} ->
- case catch find_lib_dir(NewName) of
- {LibDir, Rest} when is_list(LibDir) ->
- LibName = fname_join([LibDir | Rest]),
- case file:open(LibName, [read]) of
+ case expand_lib_dir(NewName) of
+ {ok,Header} ->
+ case file:open(Header, [read]) of
{ok,NewF} ->
- wait_req_scan(enter_file2(NewF, LibName, From,
+ wait_req_scan(enter_file2(NewF, Header, From,
St, Loc));
{error,_E2} ->
epp_reply(From,
@@ -960,7 +1002,7 @@ scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
{include,lib,NewName}}}),
wait_req_scan(St)
end;
- _Error ->
+ error ->
epp_reply(From, {error,{loc(Inc),epp,
{include,lib,NewName}}}),
wait_req_scan(St)
diff --git a/lib/stdlib/src/erl_bits.erl b/lib/stdlib/src/erl_bits.erl
index ddcfcfdf02..5851401026 100644
--- a/lib/stdlib/src/erl_bits.erl
+++ b/lib/stdlib/src/erl_bits.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. 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.
diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl
index 5ca233cde7..ef54076ee3 100644
--- a/lib/stdlib/src/erl_compile.erl
+++ b/lib/stdlib/src/erl_compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. 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.
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index f7711d0ad7..c08328b4b7 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2016. 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.
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 4ca9a609a8..2508f96b91 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -1502,7 +1502,7 @@ pattern({op,_Line,'++',{string,_Li,_S},R}, Vt, Old, Bvt, St) ->
pattern({match,_Line,Pat1,Pat2}, Vt, Old, Bvt, St0) ->
{Lvt,Bvt1,St1} = pattern(Pat1, Vt, Old, Bvt, St0),
{Rvt,Bvt2,St2} = pattern(Pat2, Vt, Old, Bvt, St1),
- St3 = reject_bin_alias(Pat1, Pat2, St2),
+ St3 = reject_invalid_alias(Pat1, Pat2, Vt, St2),
{vtmerge_pat(Lvt, Rvt),vtmerge_pat(Bvt1,Bvt2),St3};
%% Catch legal constant expressions, including unary +,-.
pattern(Pat, _Vt, _Old, _Bvt, St) ->
@@ -1517,56 +1517,77 @@ pattern_list(Ps, Vt, Old, Bvt0, St) ->
{vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt,Bvt1),St1}
end, {[],[],St}, Ps).
-%% reject_bin_alias(Pat, Expr, St) -> St'
+
+
+%% reject_invalid_alias(Pat, Expr, Vt, St) -> St'
%% Reject aliases for binary patterns at the top level.
+%% Reject aliases for maps patterns at the top level.
+%% The variables table (Vt) are for maps checkking.
-reject_bin_alias_expr({bin,_,_}=P, {match,_,P0,E}, St0) ->
- St = reject_bin_alias(P, P0, St0),
- reject_bin_alias_expr(P, E, St);
-reject_bin_alias_expr({match,_,_,_}=P, {match,_,P0,E}, St0) ->
- St = reject_bin_alias(P, P0, St0),
- reject_bin_alias_expr(P, E, St);
-reject_bin_alias_expr(_, _, St) -> St.
+reject_invalid_alias_expr({bin,_,_}=P, {match,_,P0,E}, Vt, St0) ->
+ St = reject_invalid_alias(P, P0, Vt, St0),
+ reject_invalid_alias_expr(P, E, Vt, St);
+reject_invalid_alias_expr({map,_,_}=P, {match,_,P0,E}, Vt, St0) ->
+ St = reject_invalid_alias(P, P0, Vt, St0),
+ reject_invalid_alias_expr(P, E, Vt, St);
+reject_invalid_alias_expr({match,_,_,_}=P, {match,_,P0,E}, Vt, St0) ->
+ St = reject_invalid_alias(P, P0, Vt, St0),
+ reject_invalid_alias_expr(P, E, Vt, St);
+reject_invalid_alias_expr(_, _, _, St) -> St.
-%% reject_bin_alias(Pat1, Pat2, St) -> St'
+
+%% reject_invalid_alias(Pat1, Pat2, St) -> St'
%% Aliases of binary patterns, such as <<A:8>> = <<B:4,C:4>> or even
%% <<A:8>> = <<A:8>>, are not allowed. Traverse the patterns in parallel
%% and generate an error if any binary aliases are found.
%% We generate an error even if is obvious that the overall pattern can't
%% possibly match, for instance, {a,<<A:8>>,c}={x,<<A:8>>} WILL generate an
%% error.
+%% Maps should reject unbound variables here.
-reject_bin_alias({bin,Line,_}, {bin,_,_}, St) ->
+reject_invalid_alias({bin,Line,_}, {bin,_,_}, _, St) ->
add_error(Line, illegal_bin_pattern, St);
-reject_bin_alias({cons,_,H1,T1}, {cons,_,H2,T2}, St0) ->
- St = reject_bin_alias(H1, H2, St0),
- reject_bin_alias(T1, T2, St);
-reject_bin_alias({tuple,_,Es1}, {tuple,_,Es2}, St) ->
- reject_bin_alias_list(Es1, Es2, St);
-reject_bin_alias({record,_,Name1,Pfs1}, {record,_,Name2,Pfs2},
+reject_invalid_alias({map,_Line,Ps1}, {map,_,Ps2}, Vt, St0) ->
+ Fun = fun ({map_field_exact,L,{var,_,K},_V}, Sti) ->
+ case is_var_bound(K,Vt) of
+ true ->
+ Sti;
+ false ->
+ add_error(L, {unbound_var,K}, Sti)
+ end;
+ ({map_field_exact,_L,_K,_V}, Sti) ->
+ Sti
+ end,
+ foldl(Fun, foldl(Fun, St0, Ps1), Ps2);
+reject_invalid_alias({cons,_,H1,T1}, {cons,_,H2,T2}, Vt, St0) ->
+ St = reject_invalid_alias(H1, H2, Vt, St0),
+ reject_invalid_alias(T1, T2, Vt, St);
+reject_invalid_alias({tuple,_,Es1}, {tuple,_,Es2}, Vt, St) ->
+ reject_invalid_alias_list(Es1, Es2, Vt, St);
+reject_invalid_alias({record,_,Name1,Pfs1}, {record,_,Name2,Pfs2}, Vt,
#lint{records=Recs}=St) ->
case {dict:find(Name1, Recs),dict:find(Name2, Recs)} of
{{ok,{_Line1,Fields1}},{ok,{_Line2,Fields2}}} ->
- reject_bin_alias_rec(Pfs1, Pfs2, Fields1, Fields2, St);
+ reject_invalid_alias_rec(Pfs1, Pfs2, Fields1, Fields2, Vt, St);
{_,_} ->
%% One or more non-existing records. (An error messages has
%% already been generated, so we are done here.)
St
end;
-reject_bin_alias({match,_,P1,P2}, P, St0) ->
- St = reject_bin_alias(P1, P, St0),
- reject_bin_alias(P2, P, St);
-reject_bin_alias(P, {match,_,_,_}=M, St) ->
- reject_bin_alias(M, P, St);
-reject_bin_alias(_P1, _P2, St) -> St.
-
-reject_bin_alias_list([E1|Es1], [E2|Es2], St0) ->
- St = reject_bin_alias(E1, E2, St0),
- reject_bin_alias_list(Es1, Es2, St);
-reject_bin_alias_list(_, _, St) -> St.
-
-reject_bin_alias_rec(PfsA0, PfsB0, FieldsA0, FieldsB0, St) ->
+reject_invalid_alias({match,_,P1,P2}, P, Vt, St0) ->
+ St = reject_invalid_alias(P1, P, Vt, St0),
+ reject_invalid_alias(P2, P, Vt, St);
+reject_invalid_alias(P, {match,_,_,_}=M, Vt, St) ->
+ reject_invalid_alias(M, P, Vt, St);
+reject_invalid_alias(_P1, _P2, _Vt, St) -> St.
+
+reject_invalid_alias_list([E1|Es1], [E2|Es2], Vt, St0) ->
+ St = reject_invalid_alias(E1, E2, Vt, St0),
+ reject_invalid_alias_list(Es1, Es2, Vt, St);
+reject_invalid_alias_list(_, _, _, St) -> St.
+
+reject_invalid_alias_rec(PfsA0, PfsB0, FieldsA0, FieldsB0, Vt, St) ->
%% We treat records as if they have been converted to tuples.
PfsA1 = rbia_field_vars(PfsA0),
PfsB1 = rbia_field_vars(PfsB0),
@@ -1582,7 +1603,7 @@ reject_bin_alias_rec(PfsA0, PfsB0, FieldsA0, FieldsB0, St) ->
D = sofs:projection({external,fun({_,_,P1,_,P2}) -> {P1,P2} end}, C),
E = sofs:to_external(D),
{Ps1,Ps2} = lists:unzip(E),
- reject_bin_alias_list(Ps1, Ps2, St).
+ reject_invalid_alias_list(Ps1, Ps2, Vt, St).
rbia_field_vars(Fs) ->
[{Name,Pat} || {record_field,_,{atom,_,Name},Pat} <- Fs].
@@ -2284,7 +2305,7 @@ expr({'catch',Line,E}, Vt, St0) ->
expr({match,_Line,P,E}, Vt, St0) ->
{Evt,St1} = expr(E, Vt, St0),
{Pvt,Bvt,St2} = pattern(P, vtupdate(Evt, Vt), St1),
- St = reject_bin_alias_expr(P, E, St2),
+ St = reject_invalid_alias_expr(P, E, Vt, St2),
{vtupdate(Bvt, vtmerge(Evt, Pvt)),St};
%% No comparison or boolean operators yet.
expr({op,_Line,_Op,A}, Vt, St) ->
@@ -2381,7 +2402,7 @@ is_valid_call(Call) ->
_ -> true
end.
-%% is_valid_map_key(K,St) -> true | false
+%% is_valid_map_key(K) -> true | false
%% variables are allowed for patterns only at the top of the tree
is_valid_map_key({var,_,_}) -> true;
@@ -2653,6 +2674,8 @@ find_field(_F, []) -> error.
%% Attr :: 'type' | 'opaque'
%% Checks that a type definition is valid.
+-dialyzer({no_match, type_def/6}).
+
type_def(Attr, Line, TypeName, ProtoType, Args, St0) ->
TypeDefs = St0#lint.types,
Arity = length(Args),
@@ -2714,8 +2737,6 @@ check_type(Types, St) ->
check_type({ann_type, _L, [_Var, Type]}, SeenVars, St) ->
check_type(Type, SeenVars, St);
-check_type({paren_type, _L, [Type]}, SeenVars, St) ->
- check_type(Type, SeenVars, St);
check_type({remote_type, L, [{atom, _, Mod}, {atom, _, Name}, Args]},
SeenVars, St0) ->
St = deprecated_type(L, Mod, Name, Args, St0),
@@ -2755,10 +2776,8 @@ check_type({type, L, range, [From, To]}, SeenVars, St) ->
_ -> add_error(L, {type_syntax, range}, St)
end,
{SeenVars, St1};
-check_type({type, L, map, any}, SeenVars, St) ->
- %% To get usage right while map/0 is a newly_introduced_builtin_type.
- St1 = used_type({map, 0}, L, St),
- {SeenVars, St1};
+check_type({type, _L, map, any}, SeenVars, St) ->
+ {SeenVars, St};
check_type({type, _L, map, Pairs}, SeenVars, St) ->
lists:foldl(fun(Pair, {AccSeenVars, AccSt}) ->
check_type(Pair, AccSeenVars, AccSt)
@@ -2866,7 +2885,6 @@ used_type(TypePair, L, #lint{usage = Usage, file = File} = St) ->
is_default_type({Name, NumberOfTypeVariables}) ->
erl_internal:is_type(Name, NumberOfTypeVariables).
-is_newly_introduced_builtin_type({map, 0}) -> true;
is_newly_introduced_builtin_type({Name, _}) when is_atom(Name) -> false.
is_obsolete_builtin_type(TypePair) ->
@@ -3416,6 +3434,14 @@ warn_unused_vars(U, Vt, St0) ->
UVt = map(fun ({V,{State,_,Ls}}) -> {V,{State,used,Ls}} end, U),
{vtmerge(Vt, UVt), St1}.
+
+is_var_bound(V, Vt) ->
+ case orddict:find(V, Vt) of
+ {ok,{bound,_Usage,_}} -> true;
+ _ -> false
+ end.
+
+
%% vtupdate(UpdVarTable, VarTable) -> VarTable.
%% Add the variables in the updated vartable to VarTable. The variables
%% will be updated with their property in UpdVarTable. The state of
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index b1c574ea60..a896de4f1c 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -170,9 +170,16 @@ fun_type -> '(' top_types ')' '->' top_type
: {type, ?anno('$1'), 'fun',
[{type, ?anno('$1'), product, '$2'},'$5']}.
+map_pair_types -> '...' : [{type, ?anno('$1'), map_field_assoc,
+ [{type, ?anno('$1'), any, []},
+ {type, ?anno('$1'), any, []}]}].
map_pair_types -> map_pair_type : ['$1'].
map_pair_types -> map_pair_type ',' map_pair_types : ['$1'|'$3'].
-map_pair_type -> top_type '=>' top_type : {type, ?anno('$2'), map_field_assoc,['$1','$3']}.
+
+map_pair_type -> top_type '=>' top_type : {type, ?anno('$2'),
+ map_field_assoc,['$1','$3']}.
+map_pair_type -> top_type ':=' top_type : {type, ?anno('$2'),
+ map_field_exact,['$1','$3']}.
field_types -> field_type : ['$1'].
field_types -> field_type ',' field_types : ['$1'|'$3'].
@@ -311,7 +318,7 @@ bit_size_expr -> expr_max : '$1'.
list_comprehension -> '[' expr '||' lc_exprs ']' :
{lc,?anno('$1'),'$2','$4'}.
-binary_comprehension -> '<<' binary '||' lc_exprs '>>' :
+binary_comprehension -> '<<' expr_max '||' lc_exprs '>>' :
{bc,?anno('$1'),'$2','$4'}.
lc_exprs -> lc_expr : ['$1'].
lc_exprs -> lc_expr ',' lc_exprs : ['$1'|'$3'].
@@ -810,7 +817,8 @@ Erlang code.
| {'type', anno(), 'map', [af_map_pair_type()]}.
-type af_map_pair_type() ::
- {'type', anno(), 'map_field_assoc', [abstract_type()]}.
+ {'type', anno(), 'map_field_assoc', [abstract_type()]}
+ | {'type', anno(), 'map_field_exact', [abstract_type()]}.
-type af_predefined_type() ::
{'type', anno(), type_name(), [abstract_type()]}.
diff --git a/lib/stdlib/src/erl_posix_msg.erl b/lib/stdlib/src/erl_posix_msg.erl
index 5eac230631..bfafca1ff7 100644
--- a/lib/stdlib/src/erl_posix_msg.erl
+++ b/lib/stdlib/src/erl_posix_msg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. 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.
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index c5177aca90..ca764675fc 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -344,11 +344,31 @@ binary_type(I1, I2) ->
map_type(Fs) ->
{first,[$#],map_pair_types(Fs)}.
-map_pair_types(Fs) ->
+map_pair_types(Fs0) ->
+ Fs = replace_any_map(Fs0),
tuple_type(Fs, fun map_pair_type/2).
+replace_any_map([{type,Line,map_field_assoc,[KType,VType]}]=Fs) ->
+ IsAny = fun({type,_,any,[]}) -> true;
+ %% ({var,_,'_'}) -> true;
+ (_) -> false
+ end,
+ case IsAny(KType) andalso IsAny(VType) of
+ true ->
+ [{type,Line,map_field_assoc,any}];
+ false ->
+ Fs
+ end;
+replace_any_map([F|Fs]) ->
+ [F|replace_any_map(Fs)];
+replace_any_map([]) -> [].
+
+map_pair_type({type,_Line,map_field_assoc,any}, _Prec) ->
+ leaf("...");
map_pair_type({type,_Line,map_field_assoc,[KType,VType]}, Prec) ->
- {list,[{cstep,[ltype(KType, Prec),leaf(" =>")],ltype(VType, Prec)}]}.
+ {list,[{cstep,[ltype(KType, Prec),leaf(" =>")],ltype(VType, Prec)}]};
+map_pair_type({type,_Line,map_field_exact,[KType,VType]}, Prec) ->
+ {list,[{cstep,[ltype(KType, Prec),leaf(" :=")],ltype(VType, Prec)}]}.
record_type(Name, Fields) ->
{first,[record_name(Name)],field_types(Fields)}.
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index d0e7a827a8..a383a0fc67 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. 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.
diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl
index fea1656051..665685d3ee 100644
--- a/lib/stdlib/src/error_logger_file_h.erl
+++ b/lib/stdlib/src/error_logger_file_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl
index d2df6681e3..cb22a8c0b6 100644
--- a/lib/stdlib/src/error_logger_tty_h.erl
+++ b/lib/stdlib/src/error_logger_tty_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 1fca3624dc..3f74e01692 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl
index b3698fb3f5..80667023fb 100644
--- a/lib/stdlib/src/eval_bits.erl
+++ b/lib/stdlib/src/eval_bits.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. 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.
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index 51ffd1cff9..7029389e2f 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. 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.
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index 008beb8b67..c4586171ca 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. 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.
@@ -36,6 +36,7 @@
extension/1, join/1, join/2, pathtype/1,
rootname/1, rootname/2, split/1, nativename/1]).
-export([find_src/1, find_src/2, flatten/1]).
+-export([basedir/2, basedir/3]).
%% Undocumented and unsupported exports.
-export([append/2]).
@@ -139,6 +140,7 @@ absname_join(AbsBase, Name) ->
-spec basename(Filename) -> file:filename_all() when
Filename :: file:name_all().
+
basename(Name) when is_binary(Name) ->
case os:type() of
{win32,_} ->
@@ -954,3 +956,180 @@ filename_string_to_binary(List) ->
Bin
end.
+%% Application Base Directories
+%% basedir
+%% http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+
+-type basedir_type() :: 'user_cache' | 'user_config' | 'user_data'
+ | 'user_log'
+ | 'site_config' | 'site_data'.
+
+-spec basedir(Type,Application) -> file:filename_all() when
+ Type :: basedir_type(),
+ Application :: string() | binary().
+
+basedir(Type,Application) when is_atom(Type), is_list(Application) orelse
+ is_binary(Application) ->
+ basedir(Type, Application, #{}).
+
+-spec basedir(Type,Application,Opts) -> file:filename_all() when
+ Type :: basedir_type(),
+ Application :: string() | binary(),
+ Opts :: #{author => string() | binary(),
+ os => 'windows' | 'darwin' | 'linux',
+ version => string() | binary()}.
+
+basedir(Type,Application,Opts) when is_atom(Type), is_map(Opts),
+ is_list(Application) orelse
+ is_binary(Application) ->
+ Os = basedir_os_from_opts(Opts),
+ Name = basedir_name_from_opts(Os,Application,Opts),
+ Base = basedir_from_os(Type,Os),
+ case {Type,Os} of
+ {user_log,linux} ->
+ filename:join([Base,Name,"log"]);
+ {user_log,windows} ->
+ filename:join([Base,Name,"Logs"]);
+ {user_cache,windows} ->
+ filename:join([Base,Name,"Cache"]);
+ {Type,_} when Type =:= site_config orelse Type =:= site_data ->
+ [filename:join([B,Name]) || B <- Base];
+ _ ->
+ filename:join([Base,Name])
+ end.
+
+basedir_os_from_opts(#{os := linux}) -> linux;
+basedir_os_from_opts(#{os := windows}) -> windows;
+basedir_os_from_opts(#{os := darwin}) -> darwin;
+basedir_os_from_opts(#{}) -> basedir_os_type().
+
+basedir_name_from_opts(windows,App,#{author:=Author,version:=Vsn}) ->
+ filename:join([Author,App,Vsn]);
+basedir_name_from_opts(windows,App,#{author:=Author}) ->
+ filename:join([Author,App]);
+basedir_name_from_opts(_,App,#{version:=Vsn}) ->
+ filename:join([App,Vsn]);
+basedir_name_from_opts(_,App,_) ->
+ App.
+
+basedir_from_os(Type,Os) ->
+ case Os of
+ linux -> basedir_linux(Type);
+ darwin -> basedir_darwin(Type);
+ windows -> basedir_windows(Type)
+ end.
+
+-define(basedir_linux_user_data, ".local/share").
+-define(basedir_linux_user_config, ".config").
+-define(basedir_linux_user_cache, ".cache").
+-define(basedir_linux_user_log, ".cache"). %% .cache/App/log
+-define(basedir_linux_site_data, "/usr/local/share/:/usr/share/").
+-define(basedir_linux_site_config, "/etc/xdg").
+
+basedir_linux(Type) ->
+ case Type of
+ user_data -> getenv("XDG_DATA_HOME", ?basedir_linux_user_data, true);
+ user_config -> getenv("XDG_CONFIG_HOME",?basedir_linux_user_config,true);
+ user_cache -> getenv("XDG_CACHE_HOME", ?basedir_linux_user_cache, true);
+ user_log -> getenv("XDG_CACHE_HOME", ?basedir_linux_user_log, true);
+ site_data ->
+ Base = getenv("XDG_DATA_DIRS",?basedir_linux_site_data,false),
+ string:tokens(Base,":");
+ site_config ->
+ Base = getenv("XDG_CONFIG_DIRS",?basedir_linux_site_config,false),
+ string:tokens(Base,":")
+ end.
+
+-define(basedir_darwin_user_data, "Library/Application Support").
+-define(basedir_darwin_user_config, "Library/Application Support").
+-define(basedir_darwin_user_cache, "Library/Caches").
+-define(basedir_darwin_user_log, "Library/Logs").
+-define(basedir_darwin_site_data, "/Library/Application Support").
+-define(basedir_darwin_site_config, "/Library/Application Support").
+
+basedir_darwin(Type) ->
+ case Type of
+ user_data -> basedir_join_home(?basedir_darwin_user_data);
+ user_config -> basedir_join_home(?basedir_darwin_user_config);
+ user_cache -> basedir_join_home(?basedir_darwin_user_cache);
+ user_log -> basedir_join_home(?basedir_darwin_user_log);
+ site_data -> [?basedir_darwin_site_data];
+ site_config -> [?basedir_darwin_site_config]
+ end.
+
+%% On Windows:
+%% ex. C:\Users\egil\AppData\Local\Ericsson\Erlang
+%% %LOCALAPPDATA% is defined on Windows 7 and onwards
+%% %APPDATA% is used instead of %LOCALAPPDATA% if it's not defined.
+%% %APPDATA% is used for roaming, i.e. for user_config on Windows 7 and beyond.
+%%
+%% user_data %LOCALAPPDATA%[/$author]/$appname[/$version]
+%% user_config %APPDATA%[/$author]/$appname[/$version]
+%% user_cache %LOCALAPPDATA%[/$author]/$appname[/$version]/Cache
+%% user_log %LOCALAPPDATA%[/$author]/$appname[/$version]/Logs
+
+-define(basedir_windows_user_data, "Local").
+-define(basedir_windows_user_config, "Roaming").
+-define(basedir_windows_user_cache, "Local"). %% Cache is added later
+-define(basedir_windows_user_log, "Local"). %% Logs is added later
+
+basedir_windows(Type) ->
+ %% If LOCALAPPDATA is not defined we are likely on an
+ %% XP machine. Use APPDATA instead.
+ case basedir_windows_appdata() of
+ noappdata ->
+ %% No AppData is set
+ %% Probably running MSYS
+ case Type of
+ user_data -> basedir_join_home(?basedir_windows_user_data);
+ user_config -> basedir_join_home(?basedir_windows_user_config);
+ user_cache -> basedir_join_home(?basedir_windows_user_cache);
+ user_log -> basedir_join_home(?basedir_windows_user_log);
+ site_data -> [];
+ site_config -> []
+ end;
+ {ok, AppData} ->
+ case Type of
+ user_data -> getenv("LOCALAPPDATA", AppData);
+ user_config -> AppData;
+ user_cache -> getenv("LOCALAPPDATA", AppData);
+ user_log -> getenv("LOCALAPPDATA", AppData);
+ site_data -> [];
+ site_config -> []
+ end
+ end.
+
+basedir_windows_appdata() ->
+ case os:getenv("APPDATA") of
+ Invalid when Invalid =:= false orelse Invalid =:= [] ->
+ noappdata;
+ Val ->
+ {ok, Val}
+ end.
+
+%% basedir aux
+
+getenv(K,Def,false) -> getenv(K,Def);
+getenv(K,Def,true) -> getenv(K,basedir_join_home(Def)).
+
+getenv(K,Def) ->
+ case os:getenv(K) of
+ [] -> Def;
+ false -> Def;
+ Val -> Val
+ end.
+
+basedir_join_home(Dir) ->
+ case os:getenv("HOME") of
+ false ->
+ {ok,[[Home]]} = init:get_argument(home),
+ filename:join(Home,Dir);
+ Home -> filename:join(Home,Dir)
+ end.
+
+basedir_os_type() ->
+ case os:type() of
+ {unix,darwin} -> darwin;
+ {win32,_} -> windows;
+ _ -> linux
+ end.
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index a05c2ce6fd..597830cf9a 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -26,7 +26,8 @@
%%%
%%% The standard behaviour should export init_it/6.
%%%-----------------------------------------------------------------
--export([start/5, start/6, debug_options/1,
+-export([start/5, start/6, debug_options/2,
+ name/1, unregister_name/1, get_proc_name/1, get_parent/0,
call/3, call/4, reply/2, stop/1, stop/3]).
-export([init_it/6, init_it/7]).
@@ -124,7 +125,7 @@ init_it(GenMod, Starter, Parent, Mod, Args, Options) ->
init_it2(GenMod, Starter, Parent, self(), Mod, Args, Options).
init_it(GenMod, Starter, Parent, Name, Mod, Args, Options) ->
- case name_register(Name) of
+ case register_name(Name) of
true ->
init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options);
{false, Pid} ->
@@ -297,19 +298,19 @@ where({global, Name}) -> global:whereis_name(Name);
where({via, Module, Name}) -> Module:whereis_name(Name);
where({local, Name}) -> whereis(Name).
-name_register({local, Name} = LN) ->
+register_name({local, Name} = LN) ->
try register(Name, self()) of
true -> true
catch
error:_ ->
{false, where(LN)}
end;
-name_register({global, Name} = GN) ->
+register_name({global, Name} = GN) ->
case global:register_name(Name, self()) of
yes -> true;
no -> {false, where(GN)}
end;
-name_register({via, Module, Name} = GN) ->
+register_name({via, Module, Name} = GN) ->
case Module:register_name(Name, self()) of
yes ->
true;
@@ -317,34 +318,108 @@ name_register({via, Module, Name} = GN) ->
{false, where(GN)}
end.
+name({local,Name}) -> Name;
+name({global,Name}) -> Name;
+name({via,_, Name}) -> Name;
+name(Pid) when is_pid(Pid) -> Pid.
+
+unregister_name({local,Name}) ->
+ try unregister(Name) of
+ _ -> ok
+ catch
+ _:_ -> ok
+ end;
+unregister_name({global,Name}) ->
+ _ = global:unregister_name(Name),
+ ok;
+unregister_name({via, Mod, Name}) ->
+ _ = Mod:unregister_name(Name),
+ ok;
+unregister_name(Pid) when is_pid(Pid) ->
+ ok.
+
+get_proc_name(Pid) when is_pid(Pid) ->
+ Pid;
+get_proc_name({local, Name}) ->
+ case process_info(self(), registered_name) of
+ {registered_name, Name} ->
+ Name;
+ {registered_name, _Name} ->
+ exit(process_not_registered);
+ [] ->
+ exit(process_not_registered)
+ end;
+get_proc_name({global, Name}) ->
+ case global:whereis_name(Name) of
+ undefined ->
+ exit(process_not_registered_globally);
+ Pid when Pid =:= self() ->
+ Name;
+ _Pid ->
+ exit(process_not_registered_globally)
+ end;
+get_proc_name({via, Mod, Name}) ->
+ case Mod:whereis_name(Name) of
+ undefined ->
+ exit({process_not_registered_via, Mod});
+ Pid when Pid =:= self() ->
+ Name;
+ _Pid ->
+ exit({process_not_registered_via, Mod})
+ end.
+
+get_parent() ->
+ case get('$ancestors') of
+ [Parent | _] when is_pid(Parent) ->
+ Parent;
+ [Parent | _] when is_atom(Parent) ->
+ name_to_pid(Parent);
+ _ ->
+ exit(process_was_not_started_by_proc_lib)
+ end.
+
+name_to_pid(Name) ->
+ case whereis(Name) of
+ undefined ->
+ case global:whereis_name(Name) of
+ undefined ->
+ exit(could_not_find_registered_name);
+ Pid ->
+ Pid
+ end;
+ Pid ->
+ Pid
+ end.
+
timeout(Options) ->
- case opt(timeout, Options) of
- {ok, Time} ->
+ case lists:keyfind(timeout, 1, Options) of
+ {_,Time} ->
Time;
- _ ->
+ false ->
infinity
end.
spawn_opts(Options) ->
- case opt(spawn_opt, Options) of
- {ok, Opts} ->
+ case lists:keyfind(spawn_opt, 1, Options) of
+ {_,Opts} ->
Opts;
- _ ->
+ false ->
[]
end.
-opt(Op, [{Op, Value}|_]) ->
- {ok, Value};
-opt(Op, [_|Options]) ->
- opt(Op, Options);
-opt(_, []) ->
- false.
-
-debug_options(Opts) ->
- case opt(debug, Opts) of
- {ok, Options} -> sys:debug_options(Options);
- _ -> []
+debug_options(Name, Opts) ->
+ case lists:keyfind(debug, 1, Opts) of
+ {_,Options} ->
+ try sys:debug_options(Options)
+ catch _:_ ->
+ error_logger:format(
+ "~p: ignoring erroneous debug options - ~p~n",
+ [Name,Options]),
+ []
+ end;
+ false ->
+ []
end.
format_status_header(TagLine, Pid) when is_pid(Pid) ->
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 3d63c19de7..ccacf658e9 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -147,16 +147,11 @@ init_it(Starter, self, Name, Mod, Args, Options) ->
init_it(Starter, self(), Name, Mod, Args, Options);
init_it(Starter, Parent, Name0, _, _, Options) ->
process_flag(trap_exit, true),
- Debug = gen:debug_options(Options),
+ Name = gen:name(Name0),
+ Debug = gen:debug_options(Name, Options),
proc_lib:init_ack(Starter, {ok, self()}),
- Name = name(Name0),
loop(Parent, Name, [], Debug, false).
-name({local,Name}) -> Name;
-name({global,Name}) -> Name;
-name({via,_, Name}) -> Name;
-name(Pid) when is_pid(Pid) -> Pid.
-
-spec add_handler(emgr_ref(), handler(), term()) -> term().
add_handler(M, Handler, Args) -> rpc(M, {add_handler, Handler, Args}).
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index 7eabb95548..6e7528fd98 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -305,64 +305,11 @@ enter_loop(Mod, Options, StateName, StateData, Timeout) ->
enter_loop(Mod, Options, StateName, StateData, self(), Timeout).
enter_loop(Mod, Options, StateName, StateData, ServerName, Timeout) ->
- Name = get_proc_name(ServerName),
- Parent = get_parent(),
- Debug = gen:debug_options(Options),
+ Name = gen:get_proc_name(ServerName),
+ Parent = gen:get_parent(),
+ Debug = gen:debug_options(Name, Options),
loop(Parent, Name, StateName, StateData, Mod, Timeout, Debug).
-get_proc_name(Pid) when is_pid(Pid) ->
- Pid;
-get_proc_name({local, Name}) ->
- case process_info(self(), registered_name) of
- {registered_name, Name} ->
- Name;
- {registered_name, _Name} ->
- exit(process_not_registered);
- [] ->
- exit(process_not_registered)
- end;
-get_proc_name({global, Name}) ->
- case global:whereis_name(Name) of
- undefined ->
- exit(process_not_registered_globally);
- Pid when Pid =:= self() ->
- Name;
- _Pid ->
- exit(process_not_registered_globally)
- end;
-get_proc_name({via, Mod, Name}) ->
- case Mod:whereis_name(Name) of
- undefined ->
- exit({process_not_registered_via, Mod});
- Pid when Pid =:= self() ->
- Name;
- _Pid ->
- exit({process_not_registered_via, Mod})
- end.
-
-get_parent() ->
- case get('$ancestors') of
- [Parent | _] when is_pid(Parent) ->
- Parent;
- [Parent | _] when is_atom(Parent) ->
- name_to_pid(Parent);
- _ ->
- exit(process_was_not_started_by_proc_lib)
- end.
-
-name_to_pid(Name) ->
- case whereis(Name) of
- undefined ->
- case global:whereis_name(Name) of
- undefined ->
- exit(could_not_find_registered_name);
- Pid ->
- Pid
- end;
- Pid ->
- Pid
- end.
-
%%% ---------------------------------------------------
%%% Initiate the new process.
%%% Register the name using the Rfunc function
@@ -373,8 +320,8 @@ name_to_pid(Name) ->
init_it(Starter, self, Name, Mod, Args, Options) ->
init_it(Starter, self(), Name, Mod, Args, Options);
init_it(Starter, Parent, Name0, Mod, Args, Options) ->
- Name = name(Name0),
- Debug = gen:debug_options(Options),
+ Name = gen:name(Name0),
+ Debug = gen:debug_options(Name, Options),
case catch Mod:init(Args) of
{ok, StateName, StateData} ->
proc_lib:init_ack(Starter, {ok, self()}),
@@ -383,15 +330,15 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) ->
proc_lib:init_ack(Starter, {ok, self()}),
loop(Parent, Name, StateName, StateData, Mod, Timeout, Debug);
{stop, Reason} ->
- unregister_name(Name0),
+ gen:unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
ignore ->
- unregister_name(Name0),
+ gen:unregister_name(Name0),
proc_lib:init_ack(Starter, ignore),
exit(normal);
{'EXIT', Reason} ->
- unregister_name(Name0),
+ gen:unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
Else ->
@@ -400,20 +347,6 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) ->
exit(Error)
end.
-name({local,Name}) -> Name;
-name({global,Name}) -> Name;
-name({via,_, Name}) -> Name;
-name(Pid) when is_pid(Pid) -> Pid.
-
-unregister_name({local,Name}) ->
- _ = (catch unregister(Name));
-unregister_name({global,Name}) ->
- _ = global:unregister_name(Name);
-unregister_name({via, Mod, Name}) ->
- _ = Mod:unregister_name(Name);
-unregister_name(Pid) when is_pid(Pid) ->
- Pid.
-
%%-----------------------------------------------------------------
%% The MAIN loop
%%-----------------------------------------------------------------
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index c58b1de609..5800aca66f 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -304,9 +304,9 @@ enter_loop(Mod, Options, State, Timeout) ->
enter_loop(Mod, Options, State, self(), Timeout).
enter_loop(Mod, Options, State, ServerName, Timeout) ->
- Name = get_proc_name(ServerName),
- Parent = get_parent(),
- Debug = debug_options(Name, Options),
+ Name = gen:get_proc_name(ServerName),
+ Parent = gen:get_parent(),
+ Debug = gen:debug_options(Name, Options),
loop(Parent, Name, State, Mod, Timeout, Debug).
%%%========================================================================
@@ -323,8 +323,8 @@ enter_loop(Mod, Options, State, ServerName, Timeout) ->
init_it(Starter, self, Name, Mod, Args, Options) ->
init_it(Starter, self(), Name, Mod, Args, Options);
init_it(Starter, Parent, Name0, Mod, Args, Options) ->
- Name = name(Name0),
- Debug = debug_options(Name, Options),
+ Name = gen:name(Name0),
+ Debug = gen:debug_options(Name, Options),
case catch Mod:init(Args) of
{ok, State} ->
proc_lib:init_ack(Starter, {ok, self()}),
@@ -339,15 +339,15 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) ->
%% (Otherwise, the parent process could get
%% an 'already_started' error if it immediately
%% tried starting the process again.)
- unregister_name(Name0),
+ gen:unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
ignore ->
- unregister_name(Name0),
+ gen:unregister_name(Name0),
proc_lib:init_ack(Starter, ignore),
exit(normal);
{'EXIT', Reason} ->
- unregister_name(Name0),
+ gen:unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
Else ->
@@ -356,20 +356,6 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) ->
exit(Error)
end.
-name({local,Name}) -> Name;
-name({global,Name}) -> Name;
-name({via,_, Name}) -> Name;
-name(Pid) when is_pid(Pid) -> Pid.
-
-unregister_name({local,Name}) ->
- _ = (catch unregister(Name));
-unregister_name({global,Name}) ->
- _ = global:unregister_name(Name);
-unregister_name({via, Mod, Name}) ->
- _ = Mod:unregister_name(Name);
-unregister_name(Pid) when is_pid(Pid) ->
- Pid.
-
%%%========================================================================
%%% Internal functions
%%%========================================================================
@@ -858,86 +844,6 @@ error_info(Reason, Name, Msg, State, Debug) ->
sys:print_log(Debug),
ok.
-%%% ---------------------------------------------------
-%%% Misc. functions.
-%%% ---------------------------------------------------
-
-opt(Op, [{Op, Value}|_]) ->
- {ok, Value};
-opt(Op, [_|Options]) ->
- opt(Op, Options);
-opt(_, []) ->
- false.
-
-debug_options(Name, Opts) ->
- case opt(debug, Opts) of
- {ok, Options} -> dbg_opts(Name, Options);
- _ -> []
- end.
-
-dbg_opts(Name, Opts) ->
- case catch sys:debug_options(Opts) of
- {'EXIT',_} ->
- format("~p: ignoring erroneous debug options - ~p~n",
- [Name, Opts]),
- [];
- Dbg ->
- Dbg
- end.
-
-get_proc_name(Pid) when is_pid(Pid) ->
- Pid;
-get_proc_name({local, Name}) ->
- case process_info(self(), registered_name) of
- {registered_name, Name} ->
- Name;
- {registered_name, _Name} ->
- exit(process_not_registered);
- [] ->
- exit(process_not_registered)
- end;
-get_proc_name({global, Name}) ->
- case global:whereis_name(Name) of
- undefined ->
- exit(process_not_registered_globally);
- Pid when Pid =:= self() ->
- Name;
- _Pid ->
- exit(process_not_registered_globally)
- end;
-get_proc_name({via, Mod, Name}) ->
- case Mod:whereis_name(Name) of
- undefined ->
- exit({process_not_registered_via, Mod});
- Pid when Pid =:= self() ->
- Name;
- _Pid ->
- exit({process_not_registered_via, Mod})
- end.
-
-get_parent() ->
- case get('$ancestors') of
- [Parent | _] when is_pid(Parent)->
- Parent;
- [Parent | _] when is_atom(Parent)->
- name_to_pid(Parent);
- _ ->
- exit(process_was_not_started_by_proc_lib)
- end.
-
-name_to_pid(Name) ->
- case whereis(Name) of
- undefined ->
- case global:whereis_name(Name) of
- undefined ->
- exit(could_not_find_registered_name);
- Pid ->
- Pid
- end;
- Pid ->
- Pid
- end.
-
%%-----------------------------------------------------------------
%% Status information
%%-----------------------------------------------------------------
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
new file mode 100644
index 0000000000..23bddafeed
--- /dev/null
+++ b/lib/stdlib/src/gen_statem.erl
@@ -0,0 +1,1308 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2016. 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(gen_statem).
+
+%% API
+-export(
+ [start/3,start/4,start_link/3,start_link/4,
+ stop/1,stop/3,
+ cast/2,call/2,call/3,
+ enter_loop/5,enter_loop/6,enter_loop/7,
+ reply/1,reply/2]).
+
+%% gen callbacks
+-export(
+ [init_it/6]).
+
+%% sys callbacks
+-export(
+ [system_continue/3,
+ system_terminate/4,
+ system_code_change/4,
+ system_get_state/1,
+ system_replace_state/2,
+ format_status/2]).
+
+%% Internal callbacks
+-export(
+ [wakeup_from_hibernate/3]).
+
+%% Type exports for templates
+-export_type(
+ [event_type/0,
+ callback_mode/0,
+ state_function_result/0,
+ handle_event_result/0,
+ action/0]).
+
+%% Fix problem for doc build
+-export_type([transition_option/0]).
+
+%%%==========================================================================
+%%% Interface functions.
+%%%==========================================================================
+
+-type from() ::
+ {To :: pid(), Tag :: term()}. % Reply-to specifier for call
+
+-type state() ::
+ state_name() | % For state callback function StateName/5
+ term(). % For state callback function handle_event/5
+
+-type state_name() :: atom().
+
+-type data() :: term().
+
+-type event_type() ::
+ {'call',From :: from()} | 'cast' |
+ 'info' | 'timeout' | 'internal'.
+
+-type callback_mode() :: 'state_functions' | 'handle_event_function'.
+
+-type transition_option() ::
+ postpone() | hibernate() | event_timeout().
+-type postpone() ::
+ %% If 'true' postpone the current event
+ %% and retry it when the state changes (=/=)
+ boolean().
+-type hibernate() ::
+ %% If 'true' hibernate the server instead of going into receive
+ boolean().
+-type event_timeout() ::
+ %% Generate a ('timeout', EventContent, ...) event after Time
+ %% unless some other event is delivered
+ Time :: timeout().
+
+-type action() ::
+ %% During a state change:
+ %% * NextState and NewData are set.
+ %% * All action()s are executed in order of apperance.
+ %% * Postponing the current event is performed
+ %% iff 'postpone' is 'true'.
+ %% * A state timer is started iff 'timeout' is set.
+ %% * Pending events are handled or if there are
+ %% no pending events the server goes into receive
+ %% or hibernate (iff 'hibernate' is 'true')
+ %%
+ %% These action()s are executed in order of appearence
+ %% in the containing list. The ones that set options
+ %% will override any previous so the last of each kind wins.
+ %%
+ 'postpone' | % Set the postpone option
+ {'postpone', Postpone :: postpone()} |
+ %%
+ 'hibernate' | % Set the hibernate option
+ {'hibernate', Hibernate :: hibernate()} |
+ %%
+ (Timeout :: event_timeout()) | % {timeout,Timeout}
+ {'timeout', % Set the event timeout option
+ Time :: event_timeout(), EventContent :: term()} |
+ %%
+ reply_action() |
+ %%
+ %% All 'next_event' events are kept in a list and then
+ %% inserted at state changes so the first in the
+ %% action() list is the first to be delivered.
+ {'next_event', % Insert event as the next to handle
+ EventType :: event_type(),
+ EventContent :: term()}.
+-type reply_action() ::
+ {'reply', % Reply to a caller
+ From :: from(), Reply :: term()}.
+
+-type state_function_result() ::
+ {'next_state', % {next_state,NextStateName,NewData,[]}
+ NextStateName :: state_name(),
+ NewData :: data()} |
+ {'next_state', % State transition, maybe to the same state
+ NextStateName :: state_name(),
+ NewData :: data(),
+ Actions :: [action()] | action()} |
+ common_state_callback_result().
+-type handle_event_result() ::
+ {'next_state', % {next_state,NextState,NewData,[]}
+ NextState :: state(),
+ NewData :: data()} |
+ {'next_state', % State transition, maybe to the same state
+ NextState :: state(),
+ NewData :: data(),
+ Actions :: [action()] | action()} |
+ common_state_callback_result().
+-type common_state_callback_result() ::
+ 'stop' | % {stop,normal}
+ {'stop', % Stop the server
+ Reason :: term()} |
+ {'stop', % Stop the server
+ Reason :: term(),
+ NewData :: data()} |
+ {'stop_and_reply', % Reply then stop the server
+ Reason :: term(),
+ Replies :: [reply_action()] | reply_action()} |
+ {'stop_and_reply', % Reply then stop the server
+ Reason :: term(),
+ Replies :: [reply_action()] | reply_action(),
+ NewData :: data()} |
+ {'keep_state', % {keep_state,NewData,[]}
+ NewData :: data()} |
+ {'keep_state', % Keep state, change data
+ NewData :: data(),
+ Actions :: [action()] | action()} |
+ 'keep_state_and_data' | % {keep_state_and_data,[]}
+ {'keep_state_and_data', % Keep state and data -> only actions
+ Actions :: [action()] | action()}.
+
+
+%% The state machine init function. It is called only once and
+%% the server is not running until this function has returned
+%% an {ok, ...} tuple. Thereafter the state callbacks are called
+%% for all events to this server.
+-callback init(Args :: term()) ->
+ {callback_mode(), state(), data()} |
+ {callback_mode(), state(), data(), [action()] | action()} |
+ 'ignore' |
+ {'stop', Reason :: term()}.
+
+%% Example state callback for callback_mode() =:= state_functions
+%% state name 'state_name'.
+%%
+%% In this mode all states has to be type state_name() i.e atom().
+%%
+%% Note that state callbacks and only state callbacks have arity 5
+%% and that is intended.
+-callback state_name(
+ event_type(),
+ EventContent :: term(),
+ Data :: data()) ->
+ state_function_result().
+%%
+%% State callback for callback_mode() =:= handle_event_function.
+%%
+%% Note that state callbacks and only state callbacks have arity 5
+%% and that is intended.
+-callback handle_event(
+ event_type(),
+ EventContent :: term(),
+ State :: state(), % Current state
+ Data :: data()) ->
+ handle_event_result().
+
+%% Clean up before the server terminates.
+-callback terminate(
+ Reason :: 'normal' | 'shutdown' | {'shutdown', term()}
+ | term(),
+ State :: state(),
+ Data :: data()) ->
+ any().
+
+%% Note that the new code can expect to get an OldState from
+%% the old code version not only in code_change/4 but in the first
+%% state callback function called thereafter
+-callback code_change(
+ OldVsn :: term() | {'down', term()},
+ OldState :: state(),
+ OldData :: data(),
+ Extra :: term()) ->
+ {NewCallbackMode :: callback_mode(),
+ NewState :: state(),
+ NewData :: data()}.
+
+%% Format the callback module state in some sensible that is
+%% often condensed way. For StatusOption =:= 'normal' the perferred
+%% return term is [{data,[{"State",FormattedState}]}], and for
+%% StatusOption =:= 'terminate' it is just FormattedState.
+-callback format_status(
+ StatusOption,
+ [ [{Key :: term(), Value :: term()}] |
+ state() |
+ data()]) ->
+ Status :: term() when
+ StatusOption :: 'normal' | 'terminate'.
+
+-optional_callbacks(
+ [init/1, % One may use enter_loop/5,6,7 instead
+ format_status/2, % Has got a default implementation
+ %%
+ state_name/3, % Example for callback_mode =:= state_functions:
+ %% there has to be a StateName/5 callback function for every StateName.
+ %%
+ handle_event/4]). % For callback_mode =:= handle_event_function
+
+%% Type validation functions
+callback_mode(CallbackMode) ->
+ case CallbackMode of
+ state_functions ->
+ true;
+ handle_event_function ->
+ true;
+ _ ->
+ false
+ end.
+%%
+from({Pid,_}) when is_pid(Pid) ->
+ true;
+from(_) ->
+ false.
+%%
+event_type({call,From}) ->
+ from(From);
+event_type(Type) ->
+ case Type of
+ cast ->
+ true;
+ info ->
+ true;
+ timeout ->
+ true;
+ internal ->
+ true;
+ _ ->
+ false
+ end.
+
+
+
+-define(
+ STACKTRACE(),
+ try throw(ok) catch _ -> erlang:get_stacktrace() end).
+
+%%%==========================================================================
+%%% API
+
+-type server_name() ::
+ {'global', GlobalName :: term()}
+ | {'via', RegMod :: module(), Name :: term()}
+ | {'local', atom()}.
+-type server_ref() ::
+ pid()
+ | (LocalName :: atom())
+ | {Name :: atom(), Node :: atom()}
+ | {'global', GlobalName :: term()}
+ | {'via', RegMod :: module(), ViaName :: term()}.
+-type debug_opt() ::
+ {'debug',
+ Dbgs ::
+ ['trace' | 'log' | 'statistics' | 'debug'
+ | {'logfile', string()}]}.
+-type start_opt() ::
+ debug_opt()
+ | {'timeout', Time :: timeout()}
+ | {'spawn_opt', [proc_lib:spawn_option()]}.
+-type start_ret() :: {'ok', pid()} | 'ignore' | {'error', term()}.
+
+
+
+%% Start a state machine
+-spec start(
+ Module :: module(), Args :: term(), Opts :: [start_opt()]) ->
+ start_ret().
+start(Module, Args, Opts) ->
+ gen:start(?MODULE, nolink, Module, Args, Opts).
+%%
+-spec start(
+ ServerName :: server_name(),
+ Module :: module(), Args :: term(), Opts :: [start_opt()]) ->
+ start_ret().
+start(ServerName, Module, Args, Opts) ->
+ gen:start(?MODULE, nolink, ServerName, Module, Args, Opts).
+
+%% Start and link to a state machine
+-spec start_link(
+ Module :: module(), Args :: term(), Opts :: [start_opt()]) ->
+ start_ret().
+start_link(Module, Args, Opts) ->
+ gen:start(?MODULE, link, Module, Args, Opts).
+%%
+-spec start_link(
+ ServerName :: server_name(),
+ Module :: module(), Args :: term(), Opts :: [start_opt()]) ->
+ start_ret().
+start_link(ServerName, Module, Args, Opts) ->
+ gen:start(?MODULE, link, ServerName, Module, Args, Opts).
+
+%% Stop a state machine
+-spec stop(ServerRef :: server_ref()) -> ok.
+stop(ServerRef) ->
+ gen:stop(ServerRef).
+%%
+-spec stop(
+ ServerRef :: server_ref(),
+ Reason :: term(),
+ Timeout :: timeout()) -> ok.
+stop(ServerRef, Reason, Timeout) ->
+ gen:stop(ServerRef, Reason, Timeout).
+
+%% Send an event to a state machine that arrives with type 'event'
+-spec cast(ServerRef :: server_ref(), Msg :: term()) -> ok.
+cast({global,Name}, Msg) ->
+ try global:send(Name, wrap_cast(Msg)) of
+ _ -> ok
+ catch
+ _:_ -> ok
+ end;
+cast({via,RegMod,Name}, Msg) ->
+ try RegMod:send(Name, wrap_cast(Msg)) of
+ _ -> ok
+ catch
+ _:_ -> ok
+ end;
+cast({Name,Node} = ServerRef, Msg) when is_atom(Name), is_atom(Node) ->
+ send(ServerRef, wrap_cast(Msg));
+cast(ServerRef, Msg) when is_atom(ServerRef) ->
+ send(ServerRef, wrap_cast(Msg));
+cast(ServerRef, Msg) when is_pid(ServerRef) ->
+ send(ServerRef, wrap_cast(Msg)).
+
+%% Call a state machine (synchronous; a reply is expected) that
+%% arrives with type {call,From}
+-spec call(ServerRef :: server_ref(), Request :: term()) -> Reply :: term().
+call(ServerRef, Request) ->
+ call(ServerRef, Request, infinity).
+%%
+-spec call(
+ ServerRef :: server_ref(),
+ Request :: term(),
+ Timeout :: timeout()) ->
+ Reply :: term().
+call(ServerRef, Request, infinity) ->
+ try gen:call(ServerRef, '$gen_call', Request, infinity) of
+ {ok,Reply} ->
+ Reply
+ catch
+ Class:Reason ->
+ erlang:raise(
+ Class,
+ {Reason,{?MODULE,call,[ServerRef,Request,infinity]}},
+ erlang:get_stacktrace())
+ end;
+call(ServerRef, Request, Timeout) ->
+ %% Call server through proxy process to dodge any late reply
+ Ref = make_ref(),
+ Self = self(),
+ Pid = spawn(
+ fun () ->
+ Self !
+ try gen:call(
+ ServerRef, '$gen_call', Request, Timeout) of
+ Result ->
+ {Ref,Result}
+ catch Class:Reason ->
+ {Ref,Class,Reason,erlang:get_stacktrace()}
+ end
+ end),
+ Mref = monitor(process, Pid),
+ receive
+ {Ref,Result} ->
+ demonitor(Mref, [flush]),
+ case Result of
+ {ok,Reply} ->
+ Reply
+ end;
+ {Ref,Class,Reason,Stacktrace} ->
+ demonitor(Mref, [flush]),
+ erlang:raise(
+ Class,
+ {Reason,{?MODULE,call,[ServerRef,Request,Timeout]}},
+ Stacktrace);
+ {'DOWN',Mref,_,_,Reason} ->
+ %% There is a theoretical possibility that the
+ %% proxy process gets killed between try--of and !
+ %% so this clause is in case of that
+ exit(Reason)
+ end.
+
+%% Reply from a state machine callback to whom awaits in call/2
+-spec reply([reply_action()] | reply_action()) -> ok.
+reply({reply,From,Reply}) ->
+ reply(From, Reply);
+reply(Replies) when is_list(Replies) ->
+ replies(Replies).
+%%
+-spec reply(From :: from(), Reply :: term()) -> ok.
+reply({To,Tag}, Reply) when is_pid(To) ->
+ Msg = {Tag,Reply},
+ try To ! Msg of
+ _ ->
+ ok
+ catch
+ _:_ -> ok
+ end.
+
+%% Instead of starting the state machine through start/3,4
+%% or start_link/3,4 turn the current process presumably
+%% started by proc_lib into a state machine using
+%% the same arguments as you would have returned from init/1
+-spec enter_loop(
+ Module :: module(), Opts :: [debug_opt()],
+ CallbackMode :: callback_mode(),
+ State :: state(), Data :: data()) ->
+ no_return().
+enter_loop(Module, Opts, CallbackMode, State, Data) ->
+ enter_loop(Module, Opts, CallbackMode, State, Data, self()).
+%%
+-spec enter_loop(
+ Module :: module(), Opts :: [debug_opt()],
+ CallbackMode :: callback_mode(),
+ State :: state(), Data :: data(),
+ Server_or_Actions ::
+ server_name() | pid() | [action()]) ->
+ no_return().
+enter_loop(Module, Opts, CallbackMode, State, Data, Server_or_Actions) ->
+ if
+ is_list(Server_or_Actions) ->
+ enter_loop(
+ Module, Opts, CallbackMode, State, Data,
+ self(), Server_or_Actions);
+ true ->
+ enter_loop(
+ Module, Opts, CallbackMode, State, Data,
+ Server_or_Actions, [])
+ end.
+%%
+-spec enter_loop(
+ Module :: module(), Opts :: [debug_opt()],
+ CallbackMode :: callback_mode(),
+ State :: state(), Data :: data(),
+ Server :: server_name() | pid(),
+ Actions :: [action()] | action()) ->
+ no_return().
+enter_loop(Module, Opts, CallbackMode, State, Data, Server, Actions) ->
+ is_atom(Module) orelse error({atom,Module}),
+ callback_mode(CallbackMode) orelse error({callback_mode,CallbackMode}),
+ Parent = gen:get_parent(),
+ enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent).
+
+%%---------------------------------------------------------------------------
+%% API helpers
+
+wrap_cast(Event) ->
+ {'$gen_cast',Event}.
+
+replies([{reply,From,Reply}|Replies]) ->
+ reply(From, Reply),
+ replies(Replies);
+replies([]) ->
+ ok.
+
+%% Might actually not send the message in case of caught exception
+send(Proc, Msg) ->
+ try erlang:send(Proc, Msg, [noconnect]) of
+ noconnect ->
+ _ = spawn(erlang, send, [Proc,Msg]),
+ ok;
+ ok ->
+ ok
+ catch
+ _:_ ->
+ ok
+ end.
+
+%% Here the init_it/6 and enter_loop/5,6,7 functions converge
+enter(Module, Opts, CallbackMode, State, Data, Server, Actions, Parent) ->
+ %% The values should already have been type checked
+ Name = gen:get_proc_name(Server),
+ Debug = gen:debug_options(Name, Opts),
+ P = Events = [],
+ Event = {internal,initial_state},
+ %% We enforce {postpone,false} to ensure that
+ %% our fake Event gets discarded, thought it might get logged
+ NewActions =
+ if
+ is_list(Actions) ->
+ Actions ++ [{postpone,false}];
+ true ->
+ [Actions,{postpone,false}]
+ end,
+ S = #{
+ callback_mode => CallbackMode,
+ module => Module,
+ name => Name,
+ %% All fields below will be replaced according to the arguments to
+ %% loop_event_actions/10 when it finally loops back to loop/3
+ state => State,
+ data => Data,
+ postponed => P,
+ hibernate => false,
+ timer => undefined},
+ NewDebug = sys_debug(Debug, S, State, {enter,Event,State}),
+ loop_event_actions(
+ Parent, NewDebug, S, Events,
+ State, Data, P, Event, State, NewActions).
+
+%%%==========================================================================
+%%% gen callbacks
+
+init_it(Starter, self, ServerRef, Module, Args, Opts) ->
+ init_it(Starter, self(), ServerRef, Module, Args, Opts);
+init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
+ try Module:init(Args) of
+ Result ->
+ init_result(Starter, Parent, ServerRef, Module, Result, Opts)
+ catch
+ Result ->
+ init_result(Starter, Parent, ServerRef, Module, Result, Opts);
+ Class:Reason ->
+ gen:unregister_name(ServerRef),
+ proc_lib:init_ack(Starter, {error,Reason}),
+ erlang:raise(Class, Reason, erlang:get_stacktrace())
+ end.
+
+%%---------------------------------------------------------------------------
+%% gen callbacks helpers
+
+init_result(Starter, Parent, ServerRef, Module, Result, Opts) ->
+ case Result of
+ {CallbackMode,State,Data} ->
+ case callback_mode(CallbackMode) of
+ true ->
+ proc_lib:init_ack(Starter, {ok,self()}),
+ enter(
+ Module, Opts, CallbackMode, State, Data,
+ ServerRef, [], Parent);
+ false ->
+ Error = {callback_mode,CallbackMode},
+ proc_lib:init_ack(Starter, {error,Error}),
+ exit(Error)
+ end;
+ {CallbackMode,State,Data,Actions} ->
+ case callback_mode(CallbackMode) of
+ true ->
+ proc_lib:init_ack(Starter, {ok,self()}),
+ enter(
+ Module, Opts, CallbackMode, State, Data,
+ ServerRef, Actions, Parent);
+ false ->
+ Error = {callback_mode,CallbackMode},
+ proc_lib:init_ack(Starter, {error,Error}),
+ exit(Error)
+ end;
+ {stop,Reason} ->
+ gen:unregister_name(ServerRef),
+ proc_lib:init_ack(Starter, {error,Reason}),
+ exit(Reason);
+ ignore ->
+ gen:unregister_name(ServerRef),
+ proc_lib:init_ack(Starter, ignore),
+ exit(normal);
+ _ ->
+ Error = {bad_return_value,Result},
+ proc_lib:init_ack(Starter, {error,Error}),
+ exit(Error)
+ end.
+
+%%%==========================================================================
+%%% sys callbacks
+
+system_continue(Parent, Debug, S) ->
+ loop(Parent, Debug, S).
+
+system_terminate(
+ Reason, _Parent, Debug,
+ #{state := State, data := Data, postponed := P} = S) ->
+ terminate(
+ exit, Reason, ?STACKTRACE(),
+ Debug, S, [], State, Data, P).
+
+system_code_change(
+ #{module := Module,
+ state := State,
+ data := Data} = S,
+ _Mod, OldVsn, Extra) ->
+ case
+ try Module:code_change(OldVsn, State, Data, Extra)
+ catch
+ Result -> Result
+ end
+ of
+ {NewCallbackMode,NewState,NewData} ->
+ callback_mode(NewCallbackMode) orelse
+ error({callback_mode,NewCallbackMode}),
+ {ok,
+ S#{callback_mode := NewCallbackMode,
+ state := NewState,
+ data := NewData}};
+ {ok,_} = Error ->
+ error({case_clause,Error});
+ Error ->
+ Error
+ end.
+
+system_get_state(#{state := State, data := Data}) ->
+ {ok,{State,Data}}.
+
+system_replace_state(
+ StateFun,
+ #{state := State,
+ data := Data} = S) ->
+ {NewState,NewData} = Result = StateFun({State,Data}),
+ {ok,Result,S#{state := NewState, data := NewData}}.
+
+format_status(
+ Opt,
+ [PDict,SysState,Parent,Debug,
+ #{name := Name, postponed := P, state := State, data := Data} = S]) ->
+ Header = gen:format_status_header("Status for state machine", Name),
+ Log = sys:get_debug(log, Debug, []),
+ [{header,Header},
+ {data,
+ [{"Status",SysState},
+ {"Parent",Parent},
+ {"Logged Events",Log},
+ {"Postponed",P}]} |
+ case format_status(Opt, PDict, S, State, Data) of
+ L when is_list(L) -> L;
+ T -> [T]
+ end].
+
+%%---------------------------------------------------------------------------
+%% Format debug messages. Print them as the call-back module sees
+%% them, not as the real erlang messages. Use trace for that.
+%%---------------------------------------------------------------------------
+
+print_event(Dev, {in,Event}, {Name,_}) ->
+ io:format(
+ Dev, "*DBG* ~p received ~s~n",
+ [Name,event_string(Event)]);
+print_event(Dev, {out,Reply,{To,_Tag}}, {Name,_}) ->
+ io:format(
+ Dev, "*DBG* ~p sent ~p to ~p~n",
+ [Name,Reply,To]);
+print_event(Dev, {Tag,Event,NextState}, {Name,State}) ->
+ StateString =
+ case NextState of
+ State ->
+ io_lib:format("~p", [State]);
+ _ ->
+ io_lib:format("~p => ~p", [State,NextState])
+ end,
+ io:format(
+ Dev, "*DBG* ~p ~w ~s in state ~s~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]);
+ {EventType,EventContent} ->
+ io_lib:format("~w ~p", [EventType,EventContent])
+ end.
+
+sys_debug(Debug, #{name := Name}, State, Entry) ->
+ case Debug of
+ [] ->
+ Debug;
+ _ ->
+ sys:handle_debug(
+ Debug, fun print_event/3, {Name,State}, Entry)
+ end.
+
+%%%==========================================================================
+%%% Internal callbacks
+
+wakeup_from_hibernate(Parent, Debug, S) ->
+ %% It is a new message that woke us up so we have to receive it now
+ loop_receive(Parent, Debug, S).
+
+%%%==========================================================================
+%%% State Machine engine implementation of proc_lib/gen server
+
+%% Server loop, consists of all loop* functions
+%% and detours through sys:handle_system_message/7 and proc_lib:hibernate/3
+
+%% Entry point for system_continue/3
+loop(Parent, Debug, #{hibernate := Hibernate} = S) ->
+ case Hibernate of
+ true ->
+ %% Does not return but restarts process at
+ %% wakeup_from_hibernate/3 that jumps to loop_receive/3
+ proc_lib:hibernate(
+ ?MODULE, wakeup_from_hibernate, [Parent,Debug,S]),
+ error(
+ {should_not_have_arrived_here_but_instead_in,
+ {wakeup_from_hibernate,3}});
+ false ->
+ loop_receive(Parent, Debug, S)
+ end.
+
+%% Entry point for wakeup_from_hibernate/3
+loop_receive(Parent, Debug, #{timer := Timer} = S) ->
+ receive
+ Msg ->
+ case Msg of
+ {system,Pid,Req} ->
+ #{hibernate := Hibernate} = S,
+ %% Does not return but tail recursively calls
+ %% system_continue/3 that jumps to loop/3
+ sys:handle_system_msg(
+ Req, Pid, Parent, ?MODULE, Debug, S, Hibernate);
+ {'EXIT',Parent,Reason} = EXIT ->
+ #{state := State, data := Data, postponed := P} = S,
+ %% EXIT is not a 2-tuple and therefore
+ %% not an event and has no event_type(),
+ %% but this will stand out in the crash report...
+ terminate(
+ exit, Reason, ?STACKTRACE(),
+ Debug, S, [EXIT], State, Data, P);
+ {timeout,Timer,Content} when Timer =/= undefined ->
+ loop_receive_result(
+ Parent, Debug, S, {timeout,Content});
+ _ ->
+ %% Cancel Timer if running
+ case Timer of
+ undefined ->
+ ok;
+ _ ->
+ case erlang:cancel_timer(Timer) of
+ TimeLeft when is_integer(TimeLeft) ->
+ ok;
+ false ->
+ receive
+ {timeout,Timer,_} ->
+ ok
+ after 0 ->
+ ok
+ end
+ end
+ end,
+ Event =
+ case Msg of
+ {'$gen_call',From,Request} ->
+ {{call,From},Request};
+ {'$gen_cast',E} ->
+ {cast,E};
+ _ ->
+ {info,Msg}
+ end,
+ loop_receive_result(Parent, Debug, S, Event)
+ end
+ end.
+
+loop_receive_result(
+ Parent, Debug,
+ #{state := State,
+ data := Data,
+ postponed := P} = S,
+ Event) ->
+ %% The engine state map S is now dismantled
+ %% and will not be restored until we return to loop/3.
+ %%
+ %% The fields 'callback_mode', 'module', and 'name' are still valid.
+ %% The fields 'state', 'data', and 'postponed' are held in arguments.
+ %% The fields 'timer' and 'hibernate' will be recalculated.
+ %%
+ NewDebug = sys_debug(Debug, S, State, {in,Event}),
+ %% Here the queue of not yet handled events is created
+ Events = [],
+ Hibernate = false,
+ loop_event(
+ Parent, NewDebug, S, Events, State, Data, P, Event, Hibernate).
+
+%% Process the event queue, or if it is empty
+%% loop back to loop/3 to receive a new event
+loop_events(
+ Parent, Debug, S, [Event|Events],
+ State, Data, P, Hibernate, _Timeout) ->
+ %%
+ %% If there was a state timer requested we just ignore that
+ %% since we have events to handle which cancels the timer
+ loop_event(
+ Parent, Debug, S, Events, State, Data, P, Event, Hibernate);
+loop_events(
+ Parent, Debug, S, [],
+ State, Data, P, Hibernate, Timeout) ->
+ case Timeout of
+ {timeout,0,EventContent} ->
+ %% Immediate timeout - simulate it
+ %% so we do not get the timeout message
+ %% after any received event
+ loop_event(
+ Parent, Debug, S, [],
+ State, Data, P, {timeout,EventContent}, Hibernate);
+ {timeout,Time,EventContent} ->
+ %% Actually start a timer
+ Timer = erlang:start_timer(Time, self(), EventContent),
+ loop_events_done(
+ Parent, Debug, S, Timer, State, Data, P, Hibernate);
+ undefined ->
+ %% No state timeout has been requested
+ Timer = undefined,
+ loop_events_done(
+ Parent, Debug, S, Timer, State, Data, P, Hibernate)
+ end.
+%%
+loop_events_done(Parent, Debug, S, Timer, State, Data, P, Hibernate) ->
+ NewS =
+ S#{
+ state := State,
+ data := Data,
+ postponed := P,
+ hibernate := Hibernate,
+ timer := Timer},
+ loop(Parent, Debug, NewS).
+
+loop_event(
+ Parent, Debug,
+ #{callback_mode := CallbackMode,
+ module := Module} = S,
+ Events,
+ State, Data, P, {Type,Content} = Event, Hibernate) ->
+ %%
+ %% If Hibernate is true here it can only be
+ %% because it was set from an event action
+ %% and we did not go into hibernation since there
+ %% were events in queue, so we do what the user
+ %% might depend on i.e collect garbage which
+ %% would have happened if we actually hibernated
+ %% and immediately was awakened
+ Hibernate andalso garbage_collect(),
+ %%
+ try
+ case CallbackMode of
+ state_functions ->
+ Module:State(Type, Content, Data);
+ handle_event_function ->
+ Module:handle_event(Type, Content, State, Data)
+ end of
+ Result ->
+ loop_event_result(
+ Parent, Debug, S, Events, State, Data, P, Event, Result)
+ catch
+ Result ->
+ loop_event_result(
+ Parent, Debug, S, Events, State, Data, P, Event, Result);
+ error:badarg when CallbackMode =:= state_functions ->
+ case erlang:get_stacktrace() of
+ [{erlang,apply,[Module,State,_],_}|Stacktrace] ->
+ Args = [Type,Content,Data],
+ terminate(
+ error,
+ {undef_state_function,{Module,State,Args}},
+ Stacktrace,
+ Debug, S, [Event|Events], State, Data, P);
+ Stacktrace ->
+ terminate(
+ error, badarg, Stacktrace,
+ Debug, S, [Event|Events], State, Data, P)
+ end;
+ error:undef ->
+ %% Process an undef to check for the simple mistake
+ %% of calling a nonexistent state function
+ case erlang:get_stacktrace() of
+ [{Module,State,
+ [Type,Content,Data]=Args,
+ _}
+ |Stacktrace]
+ when CallbackMode =:= state_functions ->
+ terminate(
+ error,
+ {undef_state_function,{Module,State,Args}},
+ Stacktrace,
+ Debug, S, [Event|Events], State, Data, P);
+ [{Module,handle_event,
+ [Type,Content,State,Data]=Args,
+ _}
+ |Stacktrace]
+ when CallbackMode =:= handle_event_function ->
+ terminate(
+ error,
+ {undef_state_function,{Module,handle_event,Args}},
+ Stacktrace,
+ Debug, S, [Event|Events], State, Data, P);
+ Stacktrace ->
+ terminate(
+ error, undef, Stacktrace,
+ Debug, S, [Event|Events], State, Data, P)
+ end;
+ Class:Reason ->
+ Stacktrace = erlang:get_stacktrace(),
+ terminate(
+ Class, Reason, Stacktrace,
+ Debug, S, [Event|Events], State, Data, P)
+ end.
+
+%% Interpret all callback return variants
+loop_event_result(
+ Parent, Debug, S, Events, State, Data, P, Event, Result) ->
+ case Result of
+ stop ->
+ terminate(
+ exit, normal, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, Data, P);
+ {stop,Reason} ->
+ terminate(
+ exit, Reason, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, Data, P);
+ {stop,Reason,NewData} ->
+ terminate(
+ exit, Reason, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, NewData, P);
+ {stop_and_reply,Reason,Replies} ->
+ Q = [Event|Events],
+ reply_then_terminate(
+ exit, Reason, ?STACKTRACE(),
+ Debug, S, Q, State, Data, P, Replies);
+ {stop_and_reply,Reason,Replies,NewData} ->
+ Q = [Event|Events],
+ reply_then_terminate(
+ exit, Reason, ?STACKTRACE(),
+ Debug, S, Q, State, NewData, P, Replies);
+ {next_state,NextState,NewData} ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, []);
+ {next_state,NextState,NewData,Actions} ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions);
+ {keep_state,NewData} ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, State, []);
+ {keep_state,NewData,Actions} ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, State, Actions);
+ keep_state_and_data ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, Data, P, Event, State, []);
+ {keep_state_and_data,Actions} ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, Data, P, Event, State, Actions);
+ _ ->
+ terminate(
+ error, {bad_return_value,Result}, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, Data, P)
+ end.
+
+loop_event_actions(
+ Parent, Debug, S, Events, State, NewData, P, Event, NextState, Actions) ->
+ Postpone = false, % Shall we postpone this event; boolean()
+ Hibernate = false,
+ Timeout = undefined,
+ NextEvents = [],
+ loop_event_actions(
+ Parent, Debug, S, Events, State, NewData, P, Event, NextState,
+ if
+ is_list(Actions) ->
+ Actions;
+ true ->
+ [Actions]
+ end,
+ Postpone, Hibernate, Timeout, NextEvents).
+%%
+%% Process all actions
+loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, [Action|Actions],
+ Postpone, Hibernate, Timeout, NextEvents) ->
+ case Action of
+ %% Actual actions
+ {reply,From,Reply} ->
+ case from(From) of
+ true ->
+ NewDebug = do_reply(Debug, S, State, From, Reply),
+ loop_event_actions(
+ Parent, NewDebug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ Postpone, Hibernate, Timeout, NextEvents);
+ false ->
+ terminate(
+ error, {bad_action,Action}, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, NewData, P)
+ end;
+ {next_event,Type,Content} ->
+ case event_type(Type) of
+ true ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ Postpone, Hibernate, Timeout,
+ [{Type,Content}|NextEvents]);
+ false ->
+ terminate(
+ error, {bad_action,Action}, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, NewData, P)
+ end;
+ %% Actions that set options
+ {postpone,NewPostpone} when is_boolean(NewPostpone) ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ NewPostpone, Hibernate, Timeout, NextEvents);
+ {postpone,_} ->
+ terminate(
+ error, {bad_action,Action}, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, NewData, P);
+ postpone ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ true, Hibernate, Timeout, NextEvents);
+ {hibernate,NewHibernate} when is_boolean(NewHibernate) ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ Postpone, NewHibernate, Timeout, NextEvents);
+ {hibernate,_} ->
+ terminate(
+ error, {bad_action,Action}, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, NewData, P);
+ hibernate ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ Postpone, true, Timeout, NextEvents);
+ {timeout,infinity,_} -> % Clear timer - it will never trigger
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ Postpone, Hibernate, undefined, NextEvents);
+ {timeout,Time,_} = NewTimeout when is_integer(Time), Time >= 0 ->
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ Postpone, Hibernate, NewTimeout, NextEvents);
+ {timeout,_,_} ->
+ terminate(
+ error, {bad_action,Action}, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, NewData, P);
+ infinity -> % Clear timer - it will never trigger
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ Postpone, Hibernate, undefined, NextEvents);
+ Time when is_integer(Time), Time >= 0 ->
+ NewTimeout = {timeout,Time,Time},
+ loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P, Event, NextState, Actions,
+ Postpone, Hibernate, NewTimeout, NextEvents);
+ _ ->
+ terminate(
+ error, {bad_action,Action}, ?STACKTRACE(),
+ Debug, S, [Event|Events], State, NewData, P)
+ end;
+%%
+%% End of actions list
+loop_event_actions(
+ Parent, Debug, S, Events,
+ State, NewData, P0, Event, NextState, [],
+ Postpone, Hibernate, Timeout, NextEvents) ->
+ %%
+ %% All options have been collected and next_events are buffered.
+ %% Do the actual state transition.
+ %%
+ P1 = % Move current event to postponed if Postpone
+ case Postpone of
+ true ->
+ [Event|P0];
+ false ->
+ P0
+ end,
+ {Q2,P} = % Move all postponed events to queue if state change
+ if
+ NextState =:= State ->
+ {Events,P1};
+ true ->
+ {lists:reverse(P1, Events),[]}
+ end,
+ %% Place next events first in queue
+ Q = lists:reverse(NextEvents, Q2),
+ %%
+ NewDebug =
+ sys_debug(
+ Debug, S, State,
+ case Postpone of
+ true ->
+ {postpone,Event,NextState};
+ false ->
+ {consume,Event,NextState}
+ end),
+ loop_events(
+ Parent, NewDebug, S, Q, NextState, NewData, P, Hibernate, Timeout).
+
+%%---------------------------------------------------------------------------
+%% Server helpers
+
+reply_then_terminate(
+ Class, Reason, Stacktrace,
+ Debug, S, Q, State, Data, P, Replies) ->
+ if
+ is_list(Replies) ->
+ do_reply_then_terminate(
+ Class, Reason, Stacktrace,
+ Debug, S, Q, State, Data, P, Replies);
+ true ->
+ do_reply_then_terminate(
+ Class, Reason, Stacktrace,
+ Debug, S, Q, State, Data, P, [Replies])
+ end.
+%%
+do_reply_then_terminate(
+ Class, Reason, Stacktrace, Debug, S, Q, State, Data, P, []) ->
+ terminate(Class, Reason, Stacktrace, Debug, S, Q, State, Data, P);
+do_reply_then_terminate(
+ Class, Reason, Stacktrace, Debug, S, Q, State, Data, P, [R|Rs]) ->
+ case R of
+ {reply,{_To,_Tag}=From,Reply} ->
+ NewDebug = do_reply(Debug, S, State, From, Reply),
+ do_reply_then_terminate(
+ Class, Reason, Stacktrace,
+ NewDebug, S, Q, State, Data, P, Rs);
+ _ ->
+ terminate(
+ error, {bad_action,R}, ?STACKTRACE(),
+ Debug, S, Q, State, Data, P)
+ end.
+
+do_reply(Debug, S, State, From, Reply) ->
+ reply(From, Reply),
+ sys_debug(Debug, S, State, {out,Reply,From}).
+
+
+terminate(
+ Class, Reason, Stacktrace,
+ Debug, #{module := Module} = S, Q, State, Data, P) ->
+ try Module:terminate(Reason, State, Data) of
+ _ -> ok
+ catch
+ _ -> ok;
+ C:R ->
+ ST = erlang:get_stacktrace(),
+ error_info(
+ C, R, ST, Debug, S, Q, P,
+ format_status(terminate, get(), S, State, Data)),
+ erlang:raise(C, R, ST)
+ end,
+ case Reason of
+ normal -> ok;
+ shutdown -> ok;
+ {shutdown,_} -> ok;
+ _ ->
+ error_info(
+ Class, Reason, Stacktrace, Debug, S, Q, P,
+ format_status(terminate, get(), S, State, Data))
+ end,
+ case Stacktrace of
+ [] ->
+ erlang:Class(Reason);
+ _ ->
+ erlang:raise(Class, Reason, Stacktrace)
+ end.
+
+error_info(
+ Class, Reason, Stacktrace, Debug,
+ #{name := Name, callback_mode := CallbackMode},
+ Q, P, FmtData) ->
+ {FixedReason,FixedStacktrace} =
+ case Stacktrace of
+ [{M,F,Args,_}|ST]
+ when Class =:= error, Reason =:= undef ->
+ case code:is_loaded(M) of
+ false ->
+ {{'module could not be loaded',M},ST};
+ _ ->
+ Arity =
+ if
+ is_list(Args) ->
+ length(Args);
+ is_integer(Args) ->
+ Args
+ end,
+ case erlang:function_exported(M, F, Arity) of
+ true ->
+ {Reason,Stacktrace};
+ false ->
+ {{'function not exported',{M,F,Arity}},
+ ST}
+ end
+ end;
+ _ -> {Reason,Stacktrace}
+ end,
+ error_logger:format(
+ "** State machine ~p terminating~n" ++
+ case Q of
+ [] -> "";
+ _ -> "** Last event = ~p~n"
+ end ++
+ "** When server state = ~p~n" ++
+ "** Reason for termination = ~w:~p~n" ++
+ "** Callback mode = ~p~n" ++
+ case Q of
+ [_,_|_] -> "** Queued = ~p~n";
+ _ -> ""
+ end ++
+ case P of
+ [] -> "";
+ _ -> "** Postponed = ~p~n"
+ end ++
+ case FixedStacktrace of
+ [] -> "";
+ _ -> "** Stacktrace =~n** ~p~n"
+ end,
+ [Name |
+ case Q of
+ [] -> [];
+ [Event|_] -> [Event]
+ end] ++
+ [FmtData,Class,FixedReason,
+ CallbackMode] ++
+ case Q of
+ [_|[_|_] = Events] -> [Events];
+ _ -> []
+ end ++
+ case P of
+ [] -> [];
+ _ -> [P]
+ end ++
+ case FixedStacktrace of
+ [] -> [];
+ _ -> [FixedStacktrace]
+ end),
+ sys:print_log(Debug),
+ ok.
+
+
+%% Call Module:format_status/2 or return a default value
+format_status(Opt, PDict, #{module := Module}, State, Data) ->
+ case erlang:function_exported(Module, format_status, 2) of
+ true ->
+ try Module:format_status(Opt, [PDict,State,Data])
+ catch
+ Result -> Result;
+ _:_ ->
+ format_status_default(
+ Opt, State,
+ "Module:format_status/2 crashed")
+ end;
+ false ->
+ format_status_default(Opt, State, Data)
+ end.
+
+%% The default Module:format_status/2
+format_status_default(Opt, State, Data) ->
+ SSD = {State,Data},
+ case Opt of
+ terminate ->
+ SSD;
+ _ ->
+ [{data,[{"State",SSD}]}]
+ end.
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index ef30f16f18..ad98bc0420 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -112,14 +112,14 @@
-type format_spec() ::
#{
- control_char => char(),
- args => [any()],
- width => 'none' | integer(),
- adjust => 'left' | 'right',
- precision => 'none' | integer(),
- pad_char => char(),
- encoding => 'unicode' | 'latin1',
- strings => boolean()
+ control_char := char(),
+ args := [any()],
+ width := 'none' | integer(),
+ adjust := 'left' | 'right',
+ precision := 'none' | integer(),
+ pad_char := char(),
+ encoding := 'unicode' | 'latin1',
+ strings := boolean()
}.
%%----------------------------------------------------------------------
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index 282005da7d..1da866dc88 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/io_lib_fread.erl b/lib/stdlib/src/io_lib_fread.erl
index 25555c6f52..6a8f8f728e 100644
--- a/lib/stdlib/src/io_lib_fread.erl
+++ b/lib/stdlib/src/io_lib_fread.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 6309addf57..16ca2f41dc 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
index eb24516c50..6fba63a895 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index 2b4472cdf7..af9d63ddd6 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -39,7 +39,8 @@
-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,
partition/2,zf/2,filtermap/2,
mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2,
- split/2]).
+ split/2,
+ join/2]).
%%% BIFs
-export([keyfind/3, keymember/3, keysearch/3, member/2, reverse/2]).
@@ -1439,6 +1440,18 @@ split(N, [H|T], R) ->
split(_, [], _) ->
badarg.
+-spec join(Sep, List1) -> List2 when
+ Sep :: T,
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
+
+join(_Sep, []) -> [];
+join(Sep, [H|T]) -> [H|join_prepend(Sep, T)].
+
+join_prepend(_Sep, []) -> [];
+join_prepend(Sep, [H|T]) -> [Sep,H|join_prepend(Sep,T)].
+
%%% =================================================================
%%% Here follows the implementation of the sort functions.
%%%
diff --git a/lib/stdlib/src/log_mf_h.erl b/lib/stdlib/src/log_mf_h.erl
index 35723bbc9e..393da9ab27 100644
--- a/lib/stdlib/src/log_mf_h.erl
+++ b/lib/stdlib/src/log_mf_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index 43d10f4800..5dafdb282a 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2016. 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.
@@ -20,17 +20,18 @@
-module(maps).
--export([get/3,filter/2,fold/3, map/2,
- size/1,
+-export([get/3, filter/2,fold/3,
+ map/2, size/1,
+ update_with/3, update_with/4,
without/2, with/2]).
-
-%%% BIFs
+%% BIFs
-export([get/2, find/2, from_list/1,
is_key/2, keys/1, merge/2,
- new/0, put/3, remove/2,
+ new/0, put/3, remove/2, take/2,
to_list/1, update/3, values/1]).
+%% Shadowed by erl_bif_types: maps:get/2
-spec get(Key,Map) -> Value when
Key :: term(),
Map :: map(),
@@ -46,7 +47,7 @@ get(_,_) -> erlang:nif_error(undef).
find(_,_) -> erlang:nif_error(undef).
-
+%% Shadowed by erl_bif_types: maps:from_list/1
-spec from_list(List) -> Map when
List :: [{Key,Value}],
Key :: term(),
@@ -56,6 +57,7 @@ find(_,_) -> erlang:nif_error(undef).
from_list(_) -> erlang:nif_error(undef).
+%% Shadowed by erl_bif_types: maps:is_key/2
-spec is_key(Key,Map) -> boolean() when
Key :: term(),
Map :: map().
@@ -71,6 +73,7 @@ is_key(_,_) -> erlang:nif_error(undef).
keys(_) -> erlang:nif_error(undef).
+%% Shadowed by erl_bif_types: maps:merge/2
-spec merge(Map1,Map2) -> Map3 when
Map1 :: map(),
Map2 :: map(),
@@ -86,6 +89,7 @@ merge(_,_) -> erlang:nif_error(undef).
new() -> erlang:nif_error(undef).
+%% Shadowed by erl_bif_types: maps:put/3
-spec put(Key,Value,Map1) -> Map2 when
Key :: term(),
Value :: term(),
@@ -102,7 +106,15 @@ put(_,_,_) -> erlang:nif_error(undef).
remove(_,_) -> erlang:nif_error(undef).
+-spec take(Key,Map1) -> {Value,Map2} | error when
+ Key :: term(),
+ Map1 :: map(),
+ Value :: term(),
+ Map2 :: map().
+
+take(_,_) -> erlang:nif_error(undef).
+%% Shadowed by erl_bif_types: maps:to_list/1
-spec to_list(Map) -> [{Key,Value}] when
Map :: map(),
Key :: term(),
@@ -111,6 +123,7 @@ remove(_,_) -> erlang:nif_error(undef).
to_list(_) -> erlang:nif_error(undef).
+%% Shadowed by erl_bif_types: maps:update/3
-spec update(Key,Value,Map1) -> Map2 when
Key :: term(),
Value :: term(),
@@ -127,8 +140,40 @@ update(_,_,_) -> erlang:nif_error(undef).
values(_) -> erlang:nif_error(undef).
+%% End of BIFs
+
+-spec update_with(Key,Fun,Map1) -> Map2 when
+ Key :: term(),
+ Map1 :: map(),
+ Map2 :: map(),
+ Fun :: fun((Value1 :: term()) -> Value2 :: term()).
+
+update_with(Key,Fun,Map) when is_function(Fun,1), is_map(Map) ->
+ try maps:get(Key,Map) of
+ Val -> maps:update(Key,Fun(Val),Map)
+ catch
+ error:{badkey,_} ->
+ erlang:error({badkey,Key},[Key,Fun,Map])
+ end;
+update_with(Key,Fun,Map) ->
+ erlang:error(error_type(Map),[Key,Fun,Map]).
+
+
+-spec update_with(Key,Fun,Init,Map1) -> Map2 when
+ Key :: term(),
+ Map1 :: Map1,
+ Map2 :: Map2,
+ Fun :: fun((Value1 :: term()) -> Value2 :: term()),
+ Init :: term().
+
+update_with(Key,Fun,Init,Map) when is_function(Fun,1), is_map(Map) ->
+ case maps:find(Key,Map) of
+ {ok,Val} -> maps:update(Key,Fun(Val),Map);
+ error -> maps:put(Key,Init,Map)
+ end;
+update_with(Key,Fun,Init,Map) ->
+ erlang:error(error_type(Map),[Key,Fun,Init,Map]).
-%%% End of BIFs
-spec get(Key, Map, Default) -> Value | Default when
Key :: term(),
diff --git a/lib/stdlib/src/math.erl b/lib/stdlib/src/math.erl
index 06dfc01bbb..97c965e27a 100644
--- a/lib/stdlib/src/math.erl
+++ b/lib/stdlib/src/math.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/ordsets.erl b/lib/stdlib/src/ordsets.erl
index 6010b41006..569407f5ef 100644
--- a/lib/stdlib/src/ordsets.erl
+++ b/lib/stdlib/src/ordsets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 6f546da7b8..c3ad261daa 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -35,7 +35,7 @@
obsolete(Module, Name, Arity) ->
case obsolete_1(Module, Name, Arity) of
{deprecated=Tag,{_,_,_}=Replacement} ->
- {Tag,Replacement,"in a future release"};
+ {Tag,Replacement,"a future release"};
{_,String}=Ret when is_list(String) ->
Ret;
{_,_,_}=Ret ->
@@ -47,18 +47,6 @@ obsolete(Module, Name, Arity) ->
obsolete_1(net, _, _) ->
{deprecated, "module 'net' obsolete; use 'net_adm'"};
-obsolete_1(erl_internal, builtins, 0) ->
- {deprecated, {erl_internal, bif, 2}};
-
-obsolete_1(erl_eval, seq, 2) ->
- {deprecated, {erl_eval, exprs, 2}};
-obsolete_1(erl_eval, seq, 3) ->
- {deprecated, {erl_eval, exprs, 3}};
-obsolete_1(erl_eval, arg_list, 2) ->
- {deprecated, {erl_eval, expr_list, 2}};
-obsolete_1(erl_eval, arg_list, 3) ->
- {deprecated, {erl_eval, expr_list, 3}};
-
obsolete_1(erlang, hash, 2) ->
{deprecated, {erlang, phash2, 2}};
@@ -70,11 +58,12 @@ obsolete_1(erlang, now, 0) ->
obsolete_1(calendar, local_time_to_universal_time, 1) ->
{deprecated, {calendar, local_time_to_universal_time_dst, 1}};
-obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
- {deprecated, {rpc, multi_server_call, A}};
+%% *** CRYPTO added in OTP 19 ***
+obsolete_1(crypto, rand_bytes, 1) ->
+ {deprecated, {crypto, strong_rand_bytes, 1}};
-%% *** CRYPTO add in R16B01 ***
+%% *** CRYPTO added in R16B01 ***
obsolete_1(crypto, md4, 1) ->
{deprecated, {crypto, hash, 2}};
@@ -391,106 +380,10 @@ obsolete_1(http, cookie_header, 2) -> {removed,{httpc,cookie_header,2},"R15B"
obsolete_1(http, stream_next, 1) -> {removed,{httpc,stream_next,1},"R15B"};
obsolete_1(http, default_profile, 0) -> {removed,{httpc,default_profile,0},"R15B"};
-obsolete_1(httpd, start, 0) -> {removed,{inets,start,[2,3]},"R14B"};
-obsolete_1(httpd, start, 1) -> {removed,{inets,start,[2,3]},"R14B"};
-obsolete_1(httpd, start_link, 0) -> {removed,{inets,start,[2,3]},"R14B"};
-obsolete_1(httpd, start_link, 1) -> {removed,{inets,start,[2,3]},"R14B"};
-obsolete_1(httpd, start_child, 0) -> {removed,{inets,start,[2,3]},"R14B"};
-obsolete_1(httpd, start_child, 1) -> {removed,{inets,start,[2,3]},"R14B"};
-obsolete_1(httpd, stop, 0) -> {removed,{inets,stop,2},"R14B"};
-obsolete_1(httpd, stop, 1) -> {removed,{inets,stop,2},"R14B"};
-obsolete_1(httpd, stop, 2) -> {removed,{inets,stop,2},"R14B"};
-obsolete_1(httpd, stop_child, 0) -> {removed,{inets,stop,2},"R14B"};
-obsolete_1(httpd, stop_child, 1) -> {removed,{inets,stop,2},"R14B"};
-obsolete_1(httpd, stop_child, 2) -> {removed,{inets,stop,2},"R14B"};
-obsolete_1(httpd, restart, 0) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, restart, 1) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, restart, 2) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, block, 0) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, block, 1) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, block, 2) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, block, 3) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, block, 4) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, unblock, 0) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, unblock, 1) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd, unblock, 2) -> {removed,{httpd,reload_config,2},"R14B"};
-obsolete_1(httpd_util, key1search, 2) -> {removed,{proplists,get_value,2},"R13B"};
-obsolete_1(httpd_util, key1search, 3) -> {removed,{proplists,get_value,3},"R13B"};
-obsolete_1(ftp, open, 3) -> {removed,{inets,start,[2,3]},"R14B"};
-obsolete_1(ftp, force_active, 1) -> {removed,{inets,start,[2,3]},"R14B"};
-
-%% Added in R12B-4.
-obsolete_1(ssh_cm, connect, A) when 1 =< A, A =< 3 ->
- {removed,{ssh,connect,A},"R14B"};
-obsolete_1(ssh_cm, listen, A) when 2 =< A, A =< 4 ->
- {removed,{ssh,daemon,A},"R14B"};
-obsolete_1(ssh_cm, stop_listener, 1) ->
- {removed,{ssh,stop_listener,[1,2]},"R14B"};
-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},"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},"R14B"};
-obsolete_1(ssh_cm, setenv, 5) ->
- {removed,{ssh_connection,setenv,5},"R14B"};
-obsolete_1(ssh_cm, shell, 2) ->
- {removed,{ssh_connection,shell,2},"R14B"};
-obsolete_1(ssh_cm, exec, 4) ->
- {removed,{ssh_connection,exec,4},"R14B"};
-obsolete_1(ssh_cm, subsystem, 4) ->
- {removed,{ssh_connection,subsystem,4},"R14B"};
-obsolete_1(ssh_cm, winch, A) when A =:= 4; A =:= 6 ->
- {removed,{ssh_connection,window_change,A},"R14B"};
-obsolete_1(ssh_cm, signal, 3) ->
- {removed,{ssh_connection,signal,3},"R14B"};
-obsolete_1(ssh_cm, attach, A) when A =:= 2; A =:= 3 ->
- {removed,"no longer useful; removed in R14B"};
-obsolete_1(ssh_cm, detach, 2) ->
- {removed,"no longer useful; removed in R14B"};
-obsolete_1(ssh_cm, set_user_ack, 4) ->
- {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) ->
- {removed,{ssh_connection,close,2},"R14B"};
-obsolete_1(ssh_cm, stop, 1) ->
- {removed,{ssh,close,1},"R14B"};
-obsolete_1(ssh_cm, send_eof, 2) ->
- {removed,{ssh_connection,send_eof,2},"R14B"};
-obsolete_1(ssh_cm, send, A) when A =:= 3; A =:= 4 ->
- {removed,{ssh_connection,send,A},"R14B"};
-obsolete_1(ssh_cm, send_ack, A) when 3 =< A, A =< 5 ->
- {removed,{ssh_connection,send,[3,4]},"R14B"};
-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]},"R14B"};
-obsolete_1(ssh_sshd, stop, 1) ->
- {removed,{ssh,stop_listener,1},"R14B"};
-
%% Added in R13A.
obsolete_1(regexp, _, _) ->
{removed, "removed in R15; use the re module instead"};
-obsolete_1(lists, flat_length, 1) ->
- {removed,{lists,flatlength,1},"R14"};
-
-obsolete_1(ssh_sftp, connect, A) when 1 =< A, A =< 3 ->
- {removed,{ssh_sftp,start_channel,A},"R14B"};
-obsolete_1(ssh_sftp, stop, 1) ->
- {removed,{ssh_sftp,stop_channel,1},"R14B"};
-
-%% Added in R13B01.
-obsolete_1(ssl_pkix, decode_cert_file, A) when A =:= 1; A =:= 2 ->
- {removed,"removed in R14A; use public_key:pem_to_der/1 and public_key:pkix_decode_cert/2 instead"};
-obsolete_1(ssl_pkix, decode_cert, A) when A =:= 1; A =:= 2 ->
- {removed,{public_key,pkix_decode_cert,2},"R14A"};
-
%% Added in R13B04.
obsolete_1(erlang, concat_binary, 1) ->
{removed,{erlang,list_to_binary,1},"R15B"};
@@ -649,8 +542,12 @@ obsolete_1(random, _, _) ->
obsolete_1(code, rehash, 0) ->
{deprecated, "deprecated because the code path cache feature has been removed"};
+%% Removed in OTP 19.
+
obsolete_1(overload, _, _) ->
{removed, "removed in OTP 19"};
+obsolete_1(rpc, safe_multi_server_call, A) when A =:= 2; A =:= 3 ->
+ {removed, {rpc, multi_server_call, A}};
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/pool.erl b/lib/stdlib/src/pool.erl
index 2112337f65..05950a1d7c 100644
--- a/lib/stdlib/src/pool.erl
+++ b/lib/stdlib/src/pool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 10c476a6f5..4a19603ec2 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -43,12 +43,19 @@
%%-----------------------------------------------------------------------------
-type priority_level() :: 'high' | 'low' | 'max' | 'normal'.
+-type max_heap_size() :: non_neg_integer() |
+ #{ size => non_neg_integer(),
+ kill => true,
+ error_logger => true}.
-type spawn_option() :: 'link'
| 'monitor'
| {'priority', priority_level()}
+ | {'max_heap_size', max_heap_size()}
| {'min_heap_size', non_neg_integer()}
| {'min_bin_vheap_size', non_neg_integer()}
- | {'fullsweep_after', non_neg_integer()}.
+ | {'fullsweep_after', non_neg_integer()}
+ | {'message_queue_data',
+ 'off_heap' | 'on_heap' | 'mixed' }.
-type dict_or_pid() :: pid()
| (ProcInfo :: [_])
@@ -472,13 +479,15 @@ trans_init(gen,init_it,[gen_server,_,_,supervisor_bridge,[Module|_],_]) ->
{supervisor_bridge,Module,1};
trans_init(gen,init_it,[gen_server,_,_,_,supervisor_bridge,[Module|_],_]) ->
{supervisor_bridge,Module,1};
-trans_init(gen,init_it,[gen_server,_,_,Module,_,_]) ->
+trans_init(gen,init_it,[GenMod,_,_,Module,_,_])
+ when GenMod =:= gen_server;
+ GenMod =:= gen_statem;
+ GenMod =:= gen_fsm ->
{Module,init,1};
-trans_init(gen,init_it,[gen_server,_,_,_,Module|_]) ->
- {Module,init,1};
-trans_init(gen,init_it,[gen_fsm,_,_,Module,_,_]) ->
- {Module,init,1};
-trans_init(gen,init_it,[gen_fsm,_,_,_,Module|_]) ->
+trans_init(gen,init_it,[GenMod,_,_,_,Module|_])
+ when GenMod =:= gen_server;
+ GenMod =:= gen_statem;
+ GenMod =:= gen_fsm ->
{Module,init,1};
trans_init(gen,init_it,[gen_event|_]) ->
{gen_event,init_it,6};
diff --git a/lib/stdlib/src/proplists.erl b/lib/stdlib/src/proplists.erl
index 1840fa5cc0..8e99ec0ed9 100644
--- a/lib/stdlib/src/proplists.erl
+++ b/lib/stdlib/src/proplists.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. 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.
diff --git a/lib/stdlib/src/queue.erl b/lib/stdlib/src/queue.erl
index 2e65759d2a..d4d1904886 100644
--- a/lib/stdlib/src/queue.erl
+++ b/lib/stdlib/src/queue.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl
index d455abf7b0..93409d95df 100644
--- a/lib/stdlib/src/rand.erl
+++ b/lib/stdlib/src/rand.erl
@@ -44,11 +44,11 @@
%% This depends on the algorithm handler function
-type alg_seed() :: exs64_state() | exsplus_state() | exs1024_state().
%% This is the algorithm handler function within this module
--type alg_handler() :: #{type => alg(),
- max => integer(),
- next => fun(),
- uniform => fun(),
- uniform_n => fun()}.
+-type alg_handler() :: #{type := alg(),
+ max := integer(),
+ next := fun(),
+ uniform := fun(),
+ uniform_n := fun()}.
%% Internal state
-opaque state() :: {alg_handler(), alg_seed()}.
diff --git a/lib/stdlib/src/random.erl b/lib/stdlib/src/random.erl
index 8b639dd0a7..46dabb4323 100644
--- a/lib/stdlib/src/random.erl
+++ b/lib/stdlib/src/random.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl
index 80bfe38970..52d3c35608 100644
--- a/lib/stdlib/src/re.erl
+++ b/lib/stdlib/src/re.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2016. 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.
diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index cd435ff49c..3e70450320 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2016. 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.
diff --git a/lib/stdlib/src/shell_default.erl b/lib/stdlib/src/shell_default.erl
index 4ef5e14db1..6947cf181b 100644
--- a/lib/stdlib/src/shell_default.erl
+++ b/lib/stdlib/src/shell_default.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl
index 4e629a5e56..5b5c328c0c 100644
--- a/lib/stdlib/src/slave.erl
+++ b/lib/stdlib/src/slave.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/sofs.erl b/lib/stdlib/src/sofs.erl
index bcd1fc11e2..b18df2ad09 100644
--- a/lib/stdlib/src/sofs.erl
+++ b/lib/stdlib/src/sofs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2016. 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.
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index b8a7973cf2..32bcdc4f2a 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -65,6 +65,7 @@
gen_event,
gen_fsm,
gen_server,
+ gen_statem,
io,
io_lib,
io_lib_format,
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 04cdf31ada..9877662743 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. 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.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
{"%VSN%",
%% Up from - max one major revision back
- [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.*
- {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}], % 17.0-17.5
+ [{<<"3\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
+ {<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-18.*
%% Down to - max one major revision back
- [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.*
- {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}] % 17.0-17.5
+ [{<<"3\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-19.*
+ {<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-18.*
}.
diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl
index 07659ed812..c659db78bd 100644
--- a/lib/stdlib/src/string.erl
+++ b/lib/stdlib/src/string.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 9d783af82a..a594c66fa7 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -57,8 +57,8 @@
| {'global', Name :: atom()}
| {'via', Module :: module(), Name :: any()}
| pid().
--type child_spec() :: #{id => child_id(), % mandatory
- start => mfargs(), % mandatory
+-type child_spec() :: #{id := child_id(), % mandatory
+ start := mfargs(), % mandatory
restart => restart(), % optional
shutdown => shutdown(), % optional
type => worker(), % optional
diff --git a/lib/stdlib/src/supervisor_bridge.erl b/lib/stdlib/src/supervisor_bridge.erl
index 18218b71ad..af1e046d30 100644
--- a/lib/stdlib/src/supervisor_bridge.erl
+++ b/lib/stdlib/src/supervisor_bridge.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index a7debb00f5..a6ecf03716 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/timer.erl b/lib/stdlib/src/timer.erl
index f7530447bb..ca868627a9 100644
--- a/lib/stdlib/src/timer.erl
+++ b/lib/stdlib/src/timer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
diff --git a/lib/stdlib/src/win32reg.erl b/lib/stdlib/src/win32reg.erl
index 8074b2efda..8e82a79cbf 100644
--- a/lib/stdlib/src/win32reg.erl
+++ b/lib/stdlib/src/win32reg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. 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.