summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yaml4
-rw-r--r--Makefile.in2
-rwxr-xr-xconfigure10
-rw-r--r--configure.src10
-rw-r--r--erts/emulator/beam/beam_common.c6
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c7
-rw-r--r--erts/emulator/beam/jit/x86/instr_call.cpp8
-rw-r--r--erts/emulator/valgrind/suppress.standard32
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml8
-rw-r--r--lib/common_test/src/ct_groups.erl9
-rw-r--r--lib/common_test/src/ct_run.erl19
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE.erl238
-rw-r--r--lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl50
-rw-r--r--lib/crypto/c_src/Makefile.in3
-rw-r--r--lib/crypto/c_src/aead.c42
-rw-r--r--lib/crypto/c_src/api_ng.c255
-rw-r--r--lib/crypto/c_src/atoms.c4
-rw-r--r--lib/crypto/c_src/atoms.h2
-rw-r--r--lib/crypto/c_src/cipher.c9
-rw-r--r--lib/crypto/c_src/common.c53
-rw-r--r--lib/crypto/c_src/common.h19
-rw-r--r--lib/crypto/c_src/crypto.c7
-rw-r--r--lib/crypto/c_src/mac.c66
-rw-r--r--lib/crypto/c_src/otp_test_engine.c3
-rw-r--r--lib/crypto/src/crypto.erl214
-rw-r--r--lib/crypto/test/crypto_SUITE.erl16
-rw-r--r--lib/crypto/test/engine_SUITE.erl2
-rw-r--r--lib/dialyzer/src/dialyzer.erl4
-rw-r--r--lib/dialyzer/test/dialyzer_common.erl2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/unicode2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/unicode/exposer.erl5
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/unicode/problematic.erl9
-rw-r--r--lib/erl_docgen/priv/css/otp_doc.css489
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/Makefile2
-rw-r--r--lib/erl_docgen/priv/js/topbar.js16
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl519
-rw-r--r--lib/kernel/doc/src/logger.xml12
-rw-r--r--lib/kernel/src/logger.erl30
-rw-r--r--lib/kernel/test/logger_SUITE.erl59
-rw-r--r--lib/mnesia/doc/src/mnesia.xml12
-rw-r--r--lib/mnesia/src/mnesia_loader.erl2
-rw-r--r--lib/snmp/src/app/snmp_app.erl4
-rw-r--r--lib/ssl/doc/src/standards_compliance.xml6
-rw-r--r--lib/ssl/doc/src/using_ssl.xml6
-rw-r--r--lib/ssl/test/tls_api_SUITE.erl1
-rw-r--r--lib/stdlib/src/shell_docs.erl43
-rw-r--r--lib/stdlib/test/shell_docs_SUITE.erl21
-rw-r--r--make/otp_release_targets.mk8
-rw-r--r--make/otp_version_tickets9
-rw-r--r--make/otp_version_tickets_in_merge8
-rwxr-xr-xscripts/otp_html_check2
-rw-r--r--system/doc/top/Makefile8
-rw-r--r--system/doc/top/templates/index.html.src54
53 files changed, 1604 insertions, 827 deletions
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index 0f09ab3d4d..1d1f2b44bc 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -111,6 +111,8 @@ jobs:
tar -xzf ./otp_src.tar.gz
cd otp
export ERL_TOP=`pwd`
+ export MAKEFLAGS=-j4
+ export ERLC_USE_SERVER=true
eval `./otp_build env_win32 x64`
./otp_build configure
if cat erts/CONF_INFO || cat lib/*/CONF_INFO || cat lib/*/SKIP || cat lib/SKIP-APPLICATIONS; then exit 1; fi
@@ -232,8 +234,10 @@ jobs:
TAG=${GITHUB_REF#refs/tags/}
IS_RELEASE=`$(echo $TAG | grep -E '^OTP-[0-9]+\.[0-9]+$' > /dev/null) \
&& echo "true" || echo "false"`
+ VSN=${TAG#OTP-}
echo "::set-output name=tag::${TAG}"
echo "::set-output name=release::${IS_RELEASE}"
+ echo "::set-output name=vsn::${VSN}"
- uses: actions/checkout@v2
diff --git a/Makefile.in b/Makefile.in
index ab2fc77b06..bf867f66ce 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -451,7 +451,7 @@ endif
$(DOCGEN)/priv/bin/validate_links.escript $(ERL_TOP) make/$(TARGET)/mod2app.xml \
lib/*/doc/xml/*.xml erts/doc/xml/*.xml system/doc/xml/*/*.xml
-mod2app: $(ERL_TOP)/make/$(TARGET)/mod2app.xml
+mod2app: doc_bootstrap_build doc_bootstrap_copy $(ERL_TOP)/make/$(TARGET)/mod2app.xml
$(ERL_TOP)/make/$(TARGET)/mod2app.xml: erts/doc/src/Makefile lib/*/doc/src/Makefile
PATH=$(BOOT_PREFIX)"$${PATH}" escript $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_docgen/priv/bin/xref_mod_app.escript -topdir $(ERL_TOP) -outfile $(ERL_TOP)/make/$(TARGET)/mod2app.xml
diff --git a/configure b/configure
index de7045e377..19b4b01ec8 100755
--- a/configure
+++ b/configure
@@ -55,7 +55,7 @@ skip_applications=
while test $# != 0; do
case $1 in
-srcdir=* | --srcdir=*)
- user_srcdir=`expr -- "$1" : '[^=]*=\(.*\)'`
+ user_srcdir=`echo "$1" | sed 's/^[^=]*=//'`
if test "$ERL_TOP" != ""; then
echo "WARNING: Overriding ERL_TOP with $user_srcdir" 1>&2
echo "" 1>&2
@@ -95,7 +95,7 @@ while test $# != 0; do
echo "" 1>&2
;;
-cache-file=* | --cache-file=* )
- static_cache=`expr -- "$1" : '[^=]*=\(.*\)'`
+ static_cache=`echo "$1" | sed 's/^[^=]*=//'`
if test "$static_cache" != "/dev/null"; then
echo "WARNING: Only using config cache file '$static_cache' as static cache" 1>&2
echo "" 1>&2
@@ -140,8 +140,8 @@ while test $# != 0; do
pie_ldflags="-no-pie"
;;
CFLAGS=* | LDFLAGS=*)
- flgs_var=`expr -- "$1" : '\([^=]*\)=.*'`
- flgs_val=`expr -- "$1" : '[^=]*=\(.*\)'`
+ flgs_var=`echo "$1" | sed 's/=.*$//'`
+ flgs_val=`echo "$1" | sed 's/^[^=]*=//'`
eval $flgs_var=\$flgs_val
;;
--help=r* | -help=r*)
@@ -151,7 +151,7 @@ while test $# != 0; do
*)
case $1 in
--without-*)
- skip_app=`expr -- "$1" : '--without-\(.*\)'`
+ skip_app=`echo "$1" | sed 's/^--without-//'`
if [ "$skip_app" = "stdlib" ] ||
[ "$skip_app" = "kernel" ] ||
[ "$skip_app" = "sasl" ] ||
diff --git a/configure.src b/configure.src
index 03bc4b3947..f0afd5c6ee 100644
--- a/configure.src
+++ b/configure.src
@@ -55,7 +55,7 @@ skip_applications=
while test $# != 0; do
case $1 in
-srcdir=* | --srcdir=*)
- user_srcdir=`expr -- "$1" : '[^=]*=\(.*\)'`
+ user_srcdir=`echo "$1" | sed 's/^[^=]*=//'`
if test "$ERL_TOP" != ""; then
echo "WARNING: Overriding ERL_TOP with $user_srcdir" 1>&2
echo "" 1>&2
@@ -95,7 +95,7 @@ while test $# != 0; do
echo "" 1>&2
;;
-cache-file=* | --cache-file=* )
- static_cache=`expr -- "$1" : '[^=]*=\(.*\)'`
+ static_cache=`echo "$1" | sed 's/^[^=]*=//'`
if test "$static_cache" != "/dev/null"; then
echo "WARNING: Only using config cache file '$static_cache' as static cache" 1>&2
echo "" 1>&2
@@ -140,8 +140,8 @@ while test $# != 0; do
pie_ldflags="-no-pie"
;;
CFLAGS=* | LDFLAGS=*)
- flgs_var=`expr -- "$1" : '\([^=]*\)=.*'`
- flgs_val=`expr -- "$1" : '[^=]*=\(.*\)'`
+ flgs_var=`echo "$1" | sed 's/=.*$//'`
+ flgs_val=`echo "$1" | sed 's/^[^=]*=//'`
eval $flgs_var=\$flgs_val
;;
--help=r* | -help=r*)
@@ -151,7 +151,7 @@ while test $# != 0; do
*)
case $1 in
--without-*)
- skip_app=`expr -- "$1" : '--without-\(.*\)'`
+ skip_app=`echo "$1" | sed 's/^--without-//'`
if [ "$skip_app" = "stdlib" ] ||
[ "$skip_app" = "kernel" ] ||
[ "$skip_app" = "sasl" ] ||
diff --git a/erts/emulator/beam/beam_common.c b/erts/emulator/beam/beam_common.c
index 5eeb9a9807..1a1326450f 100644
--- a/erts/emulator/beam/beam_common.c
+++ b/erts/emulator/beam/beam_common.c
@@ -1300,11 +1300,7 @@ apply_setup_error_handler(Process* p, Eterm module, Eterm function, Uint arity,
* properly adjusted).
*/
- if (HeapWordsLeft(p) < sz) {
- erts_garbage_collect(p, sz, reg, arity);
- }
- hp = HEAP_TOP(p);
- HEAP_TOP(p) += sz;
+ hp = HAlloc(p, sz);
for (i = arity-1; i >= 0; i--) {
args = CONS(hp, reg[i], args);
hp += 2;
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index e638e499c9..be4ee9772d 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -3285,11 +3285,10 @@ recv_marker_insert(Process *c_p, ErtsRecvMarker *markp, int setting)
if (!setting && *c_p->sig_qs.save == (ErtsMessage *) &markp->sig) {
/*
- * This should most likely never happen (which is why the assert
- * is here), but if it does, leave the message queue in a valid
- * state...
+ * This can happen when a recv marker recently entered the message
+ * queue via erts_proc_sig_handle_incoming() through the midddle
+ * signal queue...
*/
- ASSERT(0);
markp->pass++;
c_p->sig_qs.save = c_p->sig_qs.last;
}
diff --git a/erts/emulator/beam/jit/x86/instr_call.cpp b/erts/emulator/beam/jit/x86/instr_call.cpp
index b79ef5567c..e0ee3543bd 100644
--- a/erts/emulator/beam/jit/x86/instr_call.cpp
+++ b/erts/emulator/beam/jit/x86/instr_call.cpp
@@ -136,7 +136,7 @@ x86::Mem BeamModuleAssembler::emit_variable_apply(bool includeI) {
align_erlang_cp();
a.bind(entry);
- emit_enter_runtime<Update::eStack | Update::eHeap>();
+ emit_enter_runtime<Update::eReductions | Update::eStack | Update::eHeap>();
a.mov(ARG1, c_p);
load_x_reg_array(ARG2);
@@ -151,7 +151,7 @@ x86::Mem BeamModuleAssembler::emit_variable_apply(bool includeI) {
runtime_call<4>(apply);
- emit_leave_runtime<Update::eStack | Update::eHeap>();
+ emit_leave_runtime<Update::eReductions | Update::eStack | Update::eHeap>();
a.test(RET, RET);
a.short_().jne(dispatch);
@@ -185,7 +185,7 @@ x86::Mem BeamModuleAssembler::emit_fixed_apply(const ArgVal &Arity,
mov_arg(ARG3, Arity);
- emit_enter_runtime<Update::eStack | Update::eHeap>();
+ emit_enter_runtime<Update::eReductions | Update::eStack | Update::eHeap>();
a.mov(ARG1, c_p);
load_x_reg_array(ARG2);
@@ -200,7 +200,7 @@ x86::Mem BeamModuleAssembler::emit_fixed_apply(const ArgVal &Arity,
runtime_call<5>(fixed_apply);
- emit_leave_runtime<Update::eStack | Update::eHeap>();
+ emit_leave_runtime<Update::eReductions | Update::eStack | Update::eHeap>();
a.test(RET, RET);
a.short_().jne(dispatch);
diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard
index 85548e0869..51cb44e5ef 100644
--- a/erts/emulator/valgrind/suppress.standard
+++ b/erts/emulator/valgrind/suppress.standard
@@ -293,6 +293,38 @@ fun:process_main
fun:sched_thread_func
}
{
+Loading problem again. Now after PR
+Memcheck:Leak
+fun:malloc
+...
+fun:valid_curve
+fun:init_curves
+fun:get_curve_cnt
+fun:init_curve_types
+fun:init_algorithms_types
+fun:initialize
+fun:load
+fun:erts_load_nif
+fun:process_main
+}
+{
+Compiler before PR
+Memcheck:Leak
+fun:malloc
+fun:erts_sys_alloc
+fun:erts_alloc_fnf
+fun:erl_drv_mutex_create
+fun:enif_mutex_create
+fun:init_algorithms_types
+fun:initialize
+fun:load
+fun:erts_load_nif
+fun:process_main
+fun:sched_thread_func
+fun:thr_wrapper
+fun:start_thread
+}
+{
Crypto internal.. loading pecularities revisited
Memcheck:Leak
fun:malloc
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index 0b8657ced3..731e550364 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -955,9 +955,9 @@
Dir = string()
Suites = atom() | [atom()] | all
Suite = atom()
- Groups = GroupPath | [GroupPath] | GroupSpec | [GroupSpec] | all
- GroupPath = [GroupName]
- GroupSpec = GroupName | {GroupName,Properties} | {GroupName,Properties,GroupSpec}
+ Groups = GroupPath | GroupSpec | [GroupSpec] | all
+ GroupPath = [[GroupSpec]]
+ GroupSpec = GroupName | {GroupName,Properties} | {GroupName,Properties,[GroupSpec]}
GroupName = atom()
GroupNames = GroupName | [GroupName]
Cases = atom() | [atom()] | all
@@ -1608,5 +1608,3 @@ div.error pre { color:white }</pre>
</section>
</chapter>
-
-
diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl
index b296939bd6..273a1acb12 100644
--- a/lib/common_test/src/ct_groups.erl
+++ b/lib/common_test/src/ct_groups.erl
@@ -550,11 +550,11 @@ search_and_override([Conf = {conf,Props,Init,Tests,End}], ORSpec, Mod) ->
Suite = ?val(suite, Props),
case lists:keysearch(Name, 1, ORSpec) of
{value,{Name,default}} ->
- [Conf];
+ [{conf, Props, Init, search_and_override(Tests, ORSpec, Mod),End}];
{value,{Name,ORProps}} ->
- [{conf,InsProps(Name,Suite,ORProps),Init,Tests,End}];
+ [{conf,InsProps(Name,Suite,ORProps),Init, search_and_override(Tests, ORSpec, Mod),End}];
{value,{Name,default,[]}} ->
- [Conf];
+ [{conf, Props, Init, search_and_override(Tests, ORSpec, Mod),End}];
{value,{Name,default,SubORSpec}} ->
override_props([Conf], SubORSpec, Name,Mod);
{value,{Name,ORProps,SubORSpec}} ->
@@ -562,7 +562,8 @@ search_and_override([Conf = {conf,Props,Init,Tests,End}], ORSpec, Mod) ->
Init,Tests,End}], SubORSpec, Name,Mod);
_ ->
[{conf,Props,Init,search_and_override(Tests,ORSpec,Mod),End}]
- end.
+ end;
+search_and_override(Tests, _, _) -> Tests.
%% Modify the Tests element according to the override specification
override_props([{conf,Props,Init,Tests,End} | Confs], SubORSpec, Name,Mod) ->
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index a69267f5ea..27d0418029 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -2050,8 +2050,23 @@ final_tests1([{TestDir,Suite,GrsOrCs}|Tests], Final, Skip, Bad) when
[ct_groups:make_conf(TestDir, Suite,
GroupName, Props, TCs)];
({GroupOrGroups,TCs}) ->
- [ct_groups:make_conf(TestDir, Suite,
- GroupOrGroups, [], TCs)];
+ case GroupOrGroups of
+ [GroupList] when is_list(GroupList) ->
+ {GrpNames, Props} = lists:foldl(
+ fun({GrpName,_} = GrSpec, {GrpNames, Props}) ->
+ {lists:append(GrpNames, [GrpName]), [GrSpec | Props]};
+ ({GrpName,_,_} = GrSpec, {GrpNames, Props}) ->
+ {lists:append(GrpNames, [GrpName]), [GrSpec | Props]};
+ (GrpName, {GrpNames, Props}) ->
+ {lists:append(GrpNames, [GrpName]), Props}
+ end,
+ {[], []}, GroupList),
+ [ct_groups:make_conf(TestDir, Suite,
+ [GrpNames], [{override, Props}], TCs)];
+ _ ->
+ [ct_groups:make_conf(TestDir, Suite,
+ GroupOrGroups, [], TCs)]
+ end;
(TC) ->
[TC]
end, GrsOrCs),
diff --git a/lib/common_test/test/ct_testspec_1_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE.erl
index 2d2c42999f..41027dff36 100644
--- a/lib/common_test/test/ct_testspec_1_SUITE.erl
+++ b/lib/common_test/test/ct_testspec_1_SUITE.erl
@@ -63,6 +63,9 @@ all() ->
[all_suites, skip_all_suites, suite, skip_suite,
all_testcases, skip_all_testcases, testcase,
skip_testcase, all_groups, skip_all_groups, group,
+ group_path, group_config,
+ group_spec, multi_group, multi_group_config,
+ groupspec_path, groupspec_path_2,
skip_group, group_all_testcases,
skip_group_all_testcases, group_testcase,
skip_group_testcase, topgroup, subgroup, skip_subgroup,
@@ -207,12 +210,53 @@ skip_all_groups(Config) when is_list(Config) ->
group(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
-
TestDir = filename:join(DataDir, "groups_1"),
TestSpec = [{groups,TestDir,groups_11_SUITE,test_group_1a}],
-
setup_and_execute(group, TestSpec, Config).
+group_path(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,[[test_group_2, test_group_3]]}],
+ setup_and_execute(group_path, TestSpec, Config).
+
+group_config(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE, {test_group_1c, [parallel]}}],
+ setup_and_execute(group_config, TestSpec, Config).
+
+group_spec(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE, {test_group_2, [parallel], [{test_group_3, [sequence]}]}}],
+ setup_and_execute(group_spec, TestSpec, Config).
+
+multi_group(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE, [test_group_1a, test_group_3]}],
+ setup_and_execute(multi_group, TestSpec, Config).
+
+multi_group_config(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE, [{test_group_2, [parallel], [{test_group_3, [sequence]}]},
+ {test_group_9, [sequence], [{test_group_8, [parallel]}]}]}],
+ setup_and_execute(multi_group_config, TestSpec, Config).
+
+groupspec_path(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,[[{test_group_2, []}, {test_group_3,[]}]]}],
+ setup_and_execute(groupspec_path, TestSpec, Config).
+
+groupspec_path_2(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir, Config),
+ TestDir = filename:join(DataDir, "groups_1"),
+ TestSpec = [{groups,TestDir,groups_11_SUITE,[[{test_group_2, [parallel]}, {test_group_3,[sequence]}]]}],
+ setup_and_execute(groupspec_path_2, TestSpec, Config).
+
skip_group(Config) when is_list(Config) ->
DataDir = ?config(data_dir, Config),
@@ -224,7 +268,6 @@ skip_group(Config) when is_list(Config) ->
setup_and_execute(skip_group, TestSpec, Config).
-
%%%-----------------------------------------------------------------
%%%
@@ -753,7 +796,7 @@ test_events(all_groups) ->
[
{?eh,start_logging,'_'},
{?eh,tc_start,{groups_11_SUITE,init_per_suite}},
- {?eh,test_stats,{12,0,{0,0}}},
+ {?eh,test_stats,{16,0,{0,0}}},
{?eh,tc_done,{groups_11_SUITE,end_per_suite,'_'}},
{negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
];
@@ -761,7 +804,7 @@ test_events(all_groups) ->
test_events(skip_all_groups) ->
[
{?eh,start_logging,'_'},
- {?eh,start_info,{1,1,12}},
+ {?eh,start_info,{1,1,16}},
{?eh,tc_start,{groups_11_SUITE,init_per_suite}},
{?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_1a},"SKIPPED!"}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_1a,test_group_1a},"SKIPPED!"}},
@@ -775,26 +818,38 @@ test_events(skip_all_groups) ->
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_1b,test_group_1b},"SKIPPED!"}},
{?eh,test_stats,{0,0,{4,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_1b},"SKIPPED!"}},
+ {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_1c},"SKIPPED!"}},
+ {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1a,test_group_1c},"SKIPPED!"}},
+ {?eh,test_stats,{0,0,{5,0}}},
+ {?eh,tc_user_skip,{groups_11_SUITE,{testcase_1b,test_group_1c},"SKIPPED!"}},
+ {?eh,test_stats,{0,0,{6,0}}},
+ {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_1c},"SKIPPED!"}},
{?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_2},"SKIPPED!"}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_2a,test_group_2},"SKIPPED!"}},
- {?eh,test_stats,{0,0,{5,0}}},
+ {?eh,test_stats,{0,0,{7,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_3a,test_group_3},"SKIPPED!"}},
- {?eh,test_stats,{0,0,{6,0}}},
+ {?eh,test_stats,{0,0,{8,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_3b,test_group_3},"SKIPPED!"}},
- {?eh,test_stats,{0,0,{7,0}}},
+ {?eh,test_stats,{0,0,{9,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_2b,test_group_2},"SKIPPED!"}},
- {?eh,test_stats,{0,0,{8,0}}},
+ {?eh,test_stats,{0,0,{10,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_2},"SKIPPED!"}},
{?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_4},"SKIPPED!"}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_5a,test_group_5},"SKIPPED!"}},
- {?eh,test_stats,{0,0,{9,0}}},
+ {?eh,test_stats,{0,0,{11,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_7a,test_group_7},"SKIPPED!"}},
- {?eh,test_stats,{0,0,{10,0}}},
+ {?eh,test_stats,{0,0,{12,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_7b,test_group_7},"SKIPPED!"}},
- {?eh,test_stats,{0,0,{11,0}}},
+ {?eh,test_stats,{0,0,{13,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{testcase_5b,test_group_5},"SKIPPED!"}},
- {?eh,test_stats,{0,0,{12,0}}},
+ {?eh,test_stats,{0,0,{14,0}}},
{?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_4},"SKIPPED!"}},
+ {?eh,tc_user_skip,{groups_11_SUITE,{init_per_group,test_group_9},"SKIPPED!"}},
+ {?eh,tc_user_skip,{groups_11_SUITE,{testcase_9,test_group_9},"SKIPPED!"}},
+ {?eh,test_stats,{0,0,{15,0}}},
+ {?eh,tc_user_skip,{groups_11_SUITE,{testcase_8,test_group_8},"SKIPPED!"}},
+ {?eh,test_stats,{0,0,{16,0}}},
+ {?eh,tc_user_skip,{groups_11_SUITE,{end_per_group,test_group_9},"SKIPPED!"}},
{?eh,tc_start,{groups_11_SUITE,end_per_suite}},
{?eh,tc_done,{groups_11_SUITE,end_per_suite,ok}},
{negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
@@ -813,6 +868,65 @@ test_events(group) ->
{negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
];
+test_events(group_path) ->
+ [
+ {?eh,start_logging,'_'},
+ {?eh,tc_start,{groups_11_SUITE,init_per_suite}},
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_2,[sequence]}}},
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_3,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_3,[parallel]},'_'}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_2,[sequence]},'_'}},
+ {?eh,tc_done,{groups_11_SUITE,end_per_suite,'_'}},
+ {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
+ ];
+
+test_events(group_config) ->
+ [
+ {?eh,start_logging,'_'},
+ {?eh,tc_start,{groups_11_SUITE,init_per_suite}},
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_1c,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_1c,[parallel]},'_'}},
+ {?eh,tc_done,{groups_11_SUITE,end_per_suite,'_'}},
+ {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
+ ];
+
+
+test_events(groupspec_path) ->
+ [
+ {?eh,start_logging,'_'},
+ {?eh,tc_start,{groups_11_SUITE,init_per_suite}},
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_2,[]}}},
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_3,[]}}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3a}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3b}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_3,[]},'_'}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_2,[]},'_'}},
+ {?eh,tc_done,{groups_11_SUITE,end_per_suite,'_'}},
+ {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
+ ];
+
+test_events(groupspec_path_2) ->
+ [
+ {?eh,start_logging,'_'},
+ {?eh,tc_start,{groups_11_SUITE,init_per_suite}},
+ {parallel, [
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_2,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{init_per_group,test_group_2,[parallel]},ok}},
+ [
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_3,[sequence]}}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3a}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3b}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_3,[sequence]},'_'}}
+ ],
+ {?eh,tc_start,{groups_11_SUITE,{end_per_group,test_group_2,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_2,[parallel]},ok}}
+ ]},
+ {?eh,tc_done,{groups_11_SUITE,end_per_suite,'_'}},
+ {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
+ ];
+
test_events(skip_group) ->
[
{?eh,start_logging,'_'},
@@ -858,6 +972,104 @@ test_events(group_all_testcases) ->
{negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
];
+test_events(group_spec) ->
+ [
+ {?eh,start_logging,'_'},
+ {?eh,tc_start,{groups_11_SUITE,init_per_suite}},
+ {parallel, [
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_2,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{init_per_group,test_group_2,[parallel]},ok}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_2a}},
+ {?eh,tc_done,{groups_11_SUITE,testcase_2a,ok}},
+ [
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_3,[sequence]}}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3a}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3b}},
+ {?eh,test_stats,{3,0,{0,0}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_3,[sequence]},'_'}}
+ ],
+ {?eh,tc_start,{groups_11_SUITE,testcase_2b}},
+ {?eh,tc_done,{groups_11_SUITE,testcase_2b,ok}},
+ {?eh,test_stats,{4,0,{0,0}}},
+ {?eh,tc_start,{groups_11_SUITE,{end_per_group,test_group_2,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_2,[parallel]},ok}}
+ ]},
+ {?eh,tc_done,{groups_11_SUITE,end_per_suite,'_'}},
+ {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
+ ];
+
+test_events(multi_group) ->
+ [
+ {?eh,start_logging,'_'},
+ {?eh,tc_start,{groups_11_SUITE,init_per_suite}},
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_1a,[]}}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_1a}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_1b}},
+ {?eh,test_stats,{2,0,{0,0}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_1a,[]},'_'}},
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_2,[sequence]}}},
+ {parallel, [
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_3,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{init_per_group,test_group_3,[parallel]}, ok}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3a}},
+ {?eh,tc_done,{groups_11_SUITE,testcase_3a,ok}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3b}},
+ {?eh,tc_done,{groups_11_SUITE,testcase_3b,ok}},
+ {?eh,test_stats,{4,0,{0,0}}},
+ {?eh,tc_start,{groups_11_SUITE,{end_per_group,test_group_3,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_3,[parallel]}, ok}}
+ ]},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_2,[sequence]},'_'}},
+ {?eh,tc_done,{groups_11_SUITE,end_per_suite,'_'}},
+ {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
+ ];
+
+test_events(multi_group_config) ->
+ [
+ {?eh,start_logging,'_'},
+ {?eh,tc_start,{groups_11_SUITE,init_per_suite}},
+ {parallel, [
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_2,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{init_per_group,test_group_2,[parallel]},ok}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_2a}},
+ {?eh,tc_done,{groups_11_SUITE,testcase_2a,ok}},
+ [
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_3,[sequence]}}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3a}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_3b}},
+ {?eh,test_stats,{3,0,{0,0}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_3,[sequence]},'_'}}
+ ],
+ {?eh,tc_start,{groups_11_SUITE,testcase_2b}},
+ {?eh,tc_done,{groups_11_SUITE,testcase_2b,ok}},
+ {?eh,test_stats,{4,0,{0,0}}},
+ {?eh,tc_start,{groups_11_SUITE,{end_per_group,test_group_2,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_2,[parallel]},ok}}
+ ]},
+ [
+ {?eh,tc_start,{groups_11_SUITE,{init_per_group,test_group_9,[sequence]}}},
+ {?eh,tc_done,{groups_11_SUITE,{init_per_group,test_group_9,[sequence]},ok}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_9}},
+ {?eh,tc_done,{groups_11_SUITE,testcase_9,ok}},
+ {?eh,test_stats,{5,0,{0,0}}},
+ {parallel,[
+ {?eh,tc_start,
+ {groups_11_SUITE,{init_per_group,test_group_8,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{init_per_group,test_group_8,[parallel]},ok}},
+ {?eh,tc_start,{groups_11_SUITE,testcase_8}},
+ {?eh,tc_done,{groups_11_SUITE,testcase_8,ok}},
+ {?eh,test_stats,{6,0,{0,0}}},
+ {?eh,tc_start,{groups_11_SUITE,{end_per_group,test_group_8,[parallel]}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_8,[parallel]},ok}}
+ ]},
+ {?eh,tc_start,{groups_11_SUITE,{end_per_group,test_group_9,[sequence]}}},
+ {?eh,tc_done,{groups_11_SUITE,{end_per_group,test_group_9,[sequence]},ok}}
+ ],
+ {?eh,tc_done,{groups_11_SUITE,end_per_suite,'_'}},
+ {negative,{?eh,tc_start,'_'},{?eh,stop_logging,'_'}}
+ ];
+
+
test_events(skip_group_all_testcases) ->
[
{?eh,start_logging,'_'},
diff --git a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl
index 4d481fe3b8..56c97d9782 100644
--- a/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl
+++ b/lib/common_test/test/ct_testspec_1_SUITE_data/groups_1/groups_11_SUITE.erl
@@ -36,9 +36,11 @@ groups() ->
{test_group_1b, [], [testcase_1a,testcase_1b]},
- {test_group_2, [], [testcase_2a,
+ {test_group_1c, [sequence], [testcase_1a,testcase_1b]},
- {test_group_3, [], [testcase_3a,
+ {test_group_2, [sequence], [testcase_2a,
+
+ {test_group_3, [parallel], [testcase_3a,
testcase_3b]},
testcase_2b]},
@@ -49,7 +51,12 @@ groups() ->
testcase_5b]}]},
{test_group_6, [{group, test_group_7}]},
- {test_group_7, [testcase_7a,testcase_7b]}
+ {test_group_7, [testcase_7a,testcase_7b]},
+
+ {test_group_8, [sequence], [testcase_8]},
+
+ {test_group_9, [parallel], [testcase_9, {group, test_group_8}]}
+
].
all() ->
@@ -64,10 +71,11 @@ all() ->
%% this func only for internal test purposes
grs_and_tcs() ->
{[
- test_group_1a, test_group_1b,
+ test_group_1a, test_group_1b, test_group_1c,
test_group_2, test_group_3,
test_group_4, test_group_5,
- test_group_6, test_group_7
+ test_group_6, test_group_7,
+ test_group_8, test_group_9
],
[
testcase_1,
@@ -77,7 +85,9 @@ grs_and_tcs() ->
testcase_3a, testcase_3b,
testcase_3,
testcase_5a, testcase_5b,
- testcase_7a, testcase_7b
+ testcase_7a, testcase_7b,
+ testcase_8,
+ testcase_9
]}.
%%--------------------------------------------------------------------
@@ -95,7 +105,10 @@ end_per_suite(Config) ->
%%--------------------------------------------------------------------
init_per_group(Group, Config) ->
- [{name,Group}] = ?config(tc_group_properties,Config),
+ Group = case ?config(tc_group_properties,Config) of
+ [{name, Group0}] -> Group0;
+ [{name, Group0}, _Props] -> Group0
+ end,
{Grs,_} = grs_and_tcs(),
case lists:member(Group, Grs) of
true ->
@@ -164,8 +177,11 @@ testcase_1a(Config) ->
_ ->
case ?config(test_group_1b,Config) of
test_group_1b -> ok;
+ _ -> case ?config(test_group_1c,Config) of
+ test_group_1c -> ok;
_ -> ct:fail(no_group_data)
end
+ end
end,
testcase_1a = ?config(testcase_1a,Config),
ok.
@@ -178,8 +194,11 @@ testcase_1b(Config) ->
_ ->
case ?config(test_group_1b,Config) of
test_group_1b -> ok;
+ _ -> case ?config(test_group_1c,Config) of
+ test_group_1c -> ok;
_ -> ct:fail(no_group_data)
end
+ end
end,
undefined = ?config(testcase_1a,Config),
testcase_1b = ?config(testcase_1b,Config),
@@ -191,6 +210,7 @@ testcase_2(Config) ->
init = ?config(suite,Config),
undefined = ?config(test_group_1a,Config),
undefined = ?config(test_group_1b,Config),
+ undefined = ?config(test_group_1c, Config),
testcase_2 = ?config(testcase_2,Config),
ok.
@@ -280,3 +300,19 @@ testcase_7b(Config) ->
undefined = ?config(testcase_7a,Config),
testcase_7b = ?config(testcase_7b,Config),
ok.
+testcase_8() ->
+ [].
+testcase_8(Config) ->
+ init = ?config(suite,Config),
+ test_group_9 = ?config(test_group_9,Config),
+ test_group_8 = ?config(test_group_8,Config),
+ testcase_8 = ?config(testcase_8,Config),
+ ok.
+testcase_9() ->
+ [].
+testcase_9(Config) ->
+ init = ?config(suite,Config),
+ test_group_9 = ?config(test_group_9,Config),
+ undefined = ?config(test_group_8,Config),
+ testcase_9 = ?config(testcase_9,Config),
+ ok.
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index d360d9b6cb..92918b5d9f 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -93,6 +93,7 @@ CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o \
$(OBJDIR)/bn$(TYPEMARKER).o \
$(OBJDIR)/cipher$(TYPEMARKER).o \
$(OBJDIR)/cmac$(TYPEMARKER).o \
+ $(OBJDIR)/common$(TYPEMARKER).o \
$(OBJDIR)/dh$(TYPEMARKER).o \
$(OBJDIR)/digest$(TYPEMARKER).o \
$(OBJDIR)/dss$(TYPEMARKER).o \
@@ -181,7 +182,7 @@ static_lib: $(NIF_ARCHIVE)
$(OBJDIR)/otp_test_engine$(TYPEMARKER).o: otp_test_engine.c
$(V_at)$(INSTALL_DIR) $(OBJDIR)
- $(V_CC) -c -o $@ $(ALL_CFLAGS) $<
+ $(V_CC) -c -o $@ $(filter-out -Wmissing-prototypes,$(ALL_CFLAGS)) $<
$(LIBDIR)/otp_test_engine$(TYPEMARKER).so: $(TEST_ENGINE_OBJS)
$(V_at)$(INSTALL_DIR) $(LIBDIR)
diff --git a/lib/crypto/c_src/aead.c b/lib/crypto/c_src/aead.c
index 42c3d35928..8bbeb5bec4 100644
--- a/lib/crypto/c_src/aead.c
+++ b/lib/crypto/c_src/aead.c
@@ -51,30 +51,30 @@ ERL_NIF_TERM aead_cipher_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
encflg = -1;
else
{
- ret = EXCP_BADARG(env, "Bad enc flag");
+ ret = EXCP_BADARG_N(env, 6, "Bad enc flag");
goto done;
}
type = argv[0];
if (!enif_is_atom(env, type))
- {ret = EXCP_BADARG(env, "non-atom cipher type"); goto done;}
+ {ret = EXCP_BADARG_N(env, 0, "non-atom cipher type"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
- {ret = EXCP_BADARG(env, "non-binary key"); goto done;}
+ {ret = EXCP_BADARG_N(env, 1, "non-binary key"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[2], &iv))
- {ret = EXCP_BADARG(env, "non-binary iv"); goto done;}
+ {ret = EXCP_BADARG_N(env, 2, "non-binary iv"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[3], &in))
- {ret = EXCP_BADARG(env, "non-binary text"); goto done;}
+ {ret = EXCP_BADARG_N(env, 3, "non-binary text"); goto done;}
if (!enif_inspect_iolist_as_binary(env, argv[4], &aad))
- {ret = EXCP_BADARG(env, "non-binary AAD"); goto done;}
+ {ret = EXCP_BADARG_N(env, 4, "non-binary AAD"); goto done;}
if (encflg) {
if (!enif_get_uint(env, argv[5], &tag_len))
- {ret = EXCP_BADARG(env, "Bad Tag length"); goto done;}
+ {ret = EXCP_BADARG_N(env, 5, "Bad Tag length"); goto done;}
tag_data = NULL;
} else {
if (!enif_inspect_iolist_as_binary(env, argv[5], &tag))
- {ret = EXCP_BADARG(env, "non-binary Tag"); goto done;}
+ {ret = EXCP_BADARG_N(env, 5, "non-binary Tag"); goto done;}
tag_len = tag.size;
tag_data = tag.data;
}
@@ -84,16 +84,16 @@ ERL_NIF_TERM aead_cipher_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
|| iv.size > INT_MAX
|| in.size > INT_MAX
|| aad.size > INT_MAX)
- {ret = EXCP_BADARG(env, "binary too long"); goto done;}
+ {ret = EXCP_BADARG_N(env, 5, "binary too long"); goto done;}
if ((cipherp = get_cipher_type(type, key.size)) == NULL)
- {ret = EXCP_BADARG(env, "Unknown cipher"); goto done;}
+ {ret = EXCP_BADARG_N(env, 0, "Unknown cipher or invalid key size"); goto done;}
if (cipherp->flags & NON_EVP_CIPHER)
- {ret = EXCP_BADARG(env, "Bad cipher"); goto done;}
+ {ret = EXCP_BADARG_N(env, 0, "Bad cipher"); goto done;}
if (! (cipherp->flags & AEAD_CIPHER) )
- {ret = EXCP_BADARG(env, "Not aead cipher"); goto done;}
+ {ret = EXCP_BADARG_N(env, 0, "Not aead cipher"); goto done;}
if ((cipher = cipherp->cipher.p) == NULL)
- {ret = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version"); goto done;}
+ {ret = EXCP_NOTSUP_N(env, 0, "The cipher is not supported in this libcrypto version"); goto done;}
#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
if ( !encflg && (cipherp->flags & GCM_MODE))
@@ -106,27 +106,27 @@ ERL_NIF_TERM aead_cipher_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encflg) != 1)
{ret = EXCP_ERROR(env, "CipherInit failed"); goto done;}
if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_ivlen, (int)iv.size, NULL) != 1)
- {ret = EXCP_BADARG(env, "Bad IV length"); goto done;}
+ {ret = EXCP_BADARG_N(env, 2, "Bad IV length"); goto done;}
#if defined(HAVE_CCM)
if (cipherp->flags & CCM_MODE) {
if (EVP_CIPHER_CTX_ctrl(ctx, cipherp->extra.aead.ctx_ctrl_set_tag, (int)tag_len, tag_data) != 1)
- {ret = EXCP_BADARG(env, "Can't set tag"); goto done;}
+ {ret = EXCP_BADARG_N(env, 5, "Can't set tag"); goto done;}
if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
- {ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
+ {ret = EXCP_ERROR(env, "Can't set key or iv"); goto done;}
if (EVP_CipherUpdate(ctx, NULL, &len, NULL, (int)in.size) != 1)
- {ret = EXCP_BADARG(env, "Can't set text size"); goto done;}
+ {ret = EXCP_ERROR(env, "Can't set text size"); goto done;}
} else
#endif
{ /* GCM_MODE or CHACHA20_POLY1305 */
/* Set key and iv */
if (EVP_CipherInit_ex(ctx, NULL, NULL, key.data, iv.data, -1) != 1)
- {ret = EXCP_BADARG(env, "Can't set key or iv"); goto done;}
+ {ret = EXCP_ERROR(env, "Can't set key and iv"); goto done;}
}
/* Set the AAD */
if (EVP_CipherUpdate(ctx, NULL, &len, aad.data, (int)aad.size) != 1)
- {ret = EXCP_BADARG(env, "Can't set AAD"); goto done;}
+ {ret = EXCP_BADARG_N(env, 4, "Can't set AAD"); goto done;}
/* Set the plain text and get the crypto text (or vice versa :) ) */
if ((outp = enif_make_new_binary(env, in.size, &out)) == NULL)
@@ -134,7 +134,7 @@ ERL_NIF_TERM aead_cipher_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
if (EVP_CipherUpdate(ctx, outp, &len, in.data, (int)in.size) != 1)
{
if (encflg)
- ret = EXCP_BADARG(env, "Can't set in-text");
+ ret = EXCP_BADARG_N(env, 3, "Can't set in-text");
else
/* Decrypt error */
ret = atom_error;
@@ -182,7 +182,7 @@ done:
return ret;
#else
- return EXCP_NOTSUP(env, "Unsupported Cipher");
+ return EXCP_NOTSUP_N(env, 0, "Unsupported Cipher");
#endif
}
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
index c2ae10f2ac..35404ba1e0 100644
--- a/lib/crypto/c_src/api_ng.c
+++ b/lib/crypto/c_src/api_ng.c
@@ -85,13 +85,117 @@ int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in)
/* Get the arguments for the initialization of the EVP_CIPHER_CTX. Check */
/* them and initialize that context. */
/*************************************************************************/
+
+static ERL_NIF_TERM get_opts(ErlNifEnv* env, const ERL_NIF_TERM opts, int opts_arg_num, int *encflgp, ERL_NIF_TERM *padflgp)
+{ /* boolean() | [{Tag,Val}] Tag = encrypt | padding */
+ unsigned list_len;
+ ERL_NIF_TERM p, hd, tl;
+
+ *padflgp = atom_false; /* Not valid as padding value */
+ /* First check if the opts is an atom: */
+ if (opts == atom_true)
+ {
+ *encflgp = 1;
+ *padflgp = atom_undefined;
+ return atom_ok;
+ }
+
+ if (opts == atom_false)
+ {
+ *encflgp = 0;
+ *padflgp = atom_undefined;
+ return atom_ok;
+ }
+
+ if (opts == atom_undefined)
+ /* For compat funcs in crypto.erl. TODO: check and remove */
+ {
+ *encflgp = -1;
+ *padflgp = atom_undefined;
+ return atom_ok;
+ }
+
+ if (!enif_is_list(env, opts) || !enif_get_list_length(env, opts, &list_len))
+ /* Not a boolean() and not a list, definitly an error */
+ return EXCP_BADARG_N(env, opts_arg_num, "Options are not a boolean or a proper list");
+
+ /* A list, might be a property list, as it should */
+ *encflgp = -14; /* why not? */
+ p = opts;
+ while (enif_get_list_cell(env, p, &hd, &tl))
+ /* Loop through the list [{Tag,Value},...]
+ - check that
+ + the list is proper
+ + each list element is a 2-tuple
+ + the Tag is known
+ + the Value is of right type
+ - assign Values of known Tags to their respective flags
+ */
+ {
+ int arity;
+ const ERL_NIF_TERM* elements;
+
+ if (!(enif_get_tuple(env, hd, &arity, &elements) && (arity == 2)) )
+ return EXCP_BADARG_N(env, opts_arg_num, "Options must be a property list!");
+
+ if (elements[0] == atom_encrypt)
+ {
+ if (*encflgp != -14)
+ return EXCP_BADARG_N(env, opts_arg_num, "'encrypt' option is present more than once!");
+ else if (elements[1] == atom_true)
+ *encflgp = 1;
+ else if (elements[1] == atom_false)
+ *encflgp = 0;
+ else if (elements[1] == atom_undefined)
+ *encflgp = -1; /* For compat funcs in crypto.erl. TODO: check and remove */
+ else
+ return EXCP_BADARG_N(env, opts_arg_num, "The 'encrypt' option must be a boolean!");
+ }
+ else if (elements[0] == atom_padding)
+ {
+ if (*padflgp != atom_false)
+ return EXCP_BADARG_N(env, opts_arg_num, "The 'padding' option is present more than once!");
+
+ else if ((elements[1] == atom_undefined) ||
+ (elements[1] == atom_none) ||
+ (elements[1] == atom_zero) ||
+ (elements[1] == atom_random) ||
+ (elements[1] == atom_pkcs_padding)
+ )
+ *padflgp = elements[1];
+
+ else
+ return EXCP_BADARG_N(env, opts_arg_num, "Bad 'padding' option value");
+ }
+ else
+ {
+ char msg[64];
+ if (enif_snprintf(msg, 64, "Bad tag in option: %T", elements[0]))
+ return EXCP_BADARG_N(env, opts_arg_num, msg);
+ else
+ return EXCP_BADARG_N(env, opts_arg_num, "Bad tag in option!");
+ }
+
+ p = tl; /* prepare for handling next list element or to exit the loop */
+ }
+
+ if (*encflgp == -14)
+ *encflgp = 1; /* {encrypt,true} is the default */
+
+ if (*padflgp == atom_false)
+ *padflgp = atom_undefined; /* {padding,undefined} is the default */
+
+ return atom_ok;
+}
+
+
static int get_init_args(ErlNifEnv* env,
struct evp_cipher_ctx *ctx_res,
- const ERL_NIF_TERM cipher_arg,
- const ERL_NIF_TERM key_arg,
- const ERL_NIF_TERM ivec_arg,
- const ERL_NIF_TERM encflg_arg,
- const ERL_NIF_TERM padding_arg,
+ const ERL_NIF_TERM argv[],
+ int cipher_arg_num,
+ int key_arg_num,
+ int ivec_arg_num,
+ int opts_arg_num,
const struct cipher_type_t **cipherp,
ERL_NIF_TERM *return_term)
{
@@ -103,57 +207,48 @@ static int get_init_args(ErlNifEnv* env,
#if !defined(HAVE_EVP_AES_CTR)
ctx_res->env = NULL; /* For testing if *env should be freed after errors */
#endif
- ctx_res->padding = atom_undefined;
ctx_res->padded_size = -1;
ctx_res->size = 0;
-
- /* Fetch the flag telling if we are going to encrypt (=true) or decrypt (=false) */
- if (encflg_arg == atom_true)
- ctx_res->encflag = 1;
- else if (encflg_arg == atom_false)
- ctx_res->encflag = 0;
- else if (encflg_arg == atom_undefined)
- /* For compat funcs in crypto.erl */
- ctx_res->encflag = -1;
- else
- {
- *return_term = EXCP_BADARG(env, "Bad enc flag");
- goto err;
- }
+
+ /* Fetch the options */
+ if ((*return_term =
+ get_opts(env, argv[opts_arg_num], opts_arg_num, &(ctx_res->encflag), &(ctx_res->padding))
+ ) != atom_ok)
+ goto err;
/* Fetch the key */
- if (!enif_inspect_iolist_as_binary(env, key_arg, &key_bin))
+ if (!enif_inspect_iolist_as_binary(env, argv[key_arg_num], &key_bin))
{
- *return_term = EXCP_BADARG(env, "Bad key");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "Bad key");
goto err;
}
/* Fetch cipher type */
- if (!enif_is_atom(env, cipher_arg))
+ if (!enif_is_atom(env, argv[cipher_arg_num]))
{
- *return_term = EXCP_BADARG(env, "Cipher id is not an atom");
+ *return_term = EXCP_BADARG_N(env, cipher_arg_num, "Cipher id is not an atom");
goto err;
}
- if (!(*cipherp = get_cipher_type(cipher_arg, key_bin.size)))
+ if (!(*cipherp = get_cipher_type(argv[cipher_arg_num], key_bin.size)))
{
- if (!get_cipher_type_no_key(cipher_arg))
- *return_term = EXCP_BADARG(env, "Unknown cipher");
+ if (!get_cipher_type_no_key(argv[cipher_arg_num]))
+ *return_term = EXCP_BADARG_N(env, cipher_arg_num, "Unknown cipher");
else
- *return_term = EXCP_BADARG(env, "Bad key size");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "Bad key size");
goto err;
}
if ((*cipherp)->flags & AEAD_CIPHER)
{
- *return_term = EXCP_BADARG(env, "Missing arguments for this cipher");
+ *return_term = EXCP_BADARG_N(env, cipher_arg_num, "Missing arguments for this cipher");
goto err;
}
if (CIPHER_FORBIDDEN_IN_FIPS(*cipherp))
{
- *return_term = EXCP_NOTSUP(env, "Forbidden in FIPS");
+ *return_term = EXCP_NOTSUP_N(env, cipher_arg_num, "Forbidden in FIPS");
goto err;
}
@@ -171,32 +266,34 @@ static int get_init_args(ErlNifEnv* env,
ivec_len = 16;
else {
/* Unsupported crypto */
- *return_term = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version");
+ *return_term =
+ EXCP_NOTSUP_N(env, cipher_arg_num, "Cipher not supported in this libcrypto version");
goto err;
}
}
#else
/* Normal code */
if (!((*cipherp)->cipher.p)) {
- *return_term = EXCP_NOTSUP(env, "Cipher not supported in this libcrypto version");
+ *return_term =
+ EXCP_NOTSUP_N(env, cipher_arg_num, "Cipher not supported in this libcrypto version");
goto err;
}
ivec_len = GET_IV_LEN(*cipherp);
#endif
- /* (*cipherp)->cipher.p != NULL and ivec_len has a value */
+ /* Here: (*cipherp)->cipher.p != NULL and ivec_len has a value */
/* Fetch IV */
- if (ivec_len && (ivec_arg != atom_undefined)) {
- if (!enif_inspect_iolist_as_binary(env, ivec_arg, &ivec_bin))
+ if (ivec_len && (argv[ivec_arg_num] != atom_undefined)) {
+ if (!enif_inspect_iolist_as_binary(env, argv[ivec_arg_num], &ivec_bin))
{
- *return_term = EXCP_BADARG(env, "Bad iv type");
+ *return_term = EXCP_BADARG_N(env, ivec_arg_num, "Bad iv type");
goto err;
}
if (ivec_len != ivec_bin.size)
{
- *return_term = EXCP_BADARG(env, "Bad iv size");
+ *return_term = EXCP_BADARG_N(env, ivec_arg_num, "Bad iv size");
goto err;
}
}
@@ -211,7 +308,7 @@ static int get_init_args(ErlNifEnv* env,
ERL_NIF_TERM ecount_bin;
unsigned char *outp;
if ((outp = enif_make_new_binary(env, AES_BLOCK_SIZE, &ecount_bin)) == NULL) {
- *return_term = EXCP_ERROR(env, "Can't allocate ecount_bin");
+ *return_term = EXCP_ERROR(env, "Can't allocate output data binary");
goto err;
}
memset(outp, 0, AES_BLOCK_SIZE);
@@ -223,7 +320,7 @@ static int get_init_args(ErlNifEnv* env,
}
ctx_res->state =
enif_make_copy(ctx_res->env,
- enif_make_tuple4(env, key_arg, ivec_arg, ecount_bin, enif_make_int(env, 0)));
+ enif_make_tuple4(env, argv[key_arg_num], argv[ivec_arg_num], ecount_bin, enif_make_int(env, 0)));
goto success;
} else {
/* Flag for subsequent calls that no aes_ctr compatibility code should be called */
@@ -249,27 +346,27 @@ static int get_init_args(ErlNifEnv* env,
if (!EVP_CIPHER_CTX_set_key_length(ctx_res->ctx, (int)key_bin.size))
{
- *return_term = EXCP_ERROR(env, "Can't initialize context, key_length");
+ *return_term = EXCP_ERROR_N(env, key_arg_num, "Can't initialize context, key_length");
goto err;
}
#ifdef HAVE_RC2
if (EVP_CIPHER_type((*cipherp)->cipher.p) == NID_rc2_cbc) {
if (key_bin.size > INT_MAX / 8) {
- *return_term = EXCP_BADARG(env, "To large rc2_cbc key");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "To large rc2_cbc key");
goto err;
}
if (!EVP_CIPHER_CTX_ctrl(ctx_res->ctx, EVP_CTRL_SET_RC2_KEY_BITS, (int)key_bin.size * 8, NULL)) {
- *return_term = EXCP_ERROR(env, "ctrl rc2_cbc key");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "ctrl rc2_cbc key");
goto err;
}
}
#endif
- if (ivec_arg == atom_undefined || ivec_len == 0)
+ if (argv[ivec_arg_num] == atom_undefined || ivec_len == 0)
{
if (!EVP_CipherInit_ex(ctx_res->ctx, NULL, NULL, key_bin.data, NULL, -1)) {
- *return_term = EXCP_ERROR(env, "Can't initialize key");
+ *return_term = EXCP_BADARG_N(env, key_arg_num, "Can't initialize key");
goto err;
}
}
@@ -281,20 +378,9 @@ static int get_init_args(ErlNifEnv* env,
}
/* Set padding */
- if ((padding_arg == atom_undefined) ||
- (padding_arg == atom_none) ||
- (padding_arg == atom_zero) ||
- (padding_arg == atom_random) )
+ if (ctx_res->padding != atom_pkcs_padding) /* pkcs_padding is default */
EVP_CIPHER_CTX_set_padding(ctx_res->ctx, 0);
- else if (padding_arg != atom_pkcs_padding) /* pkcs_padding is default */
- {
- *return_term = EXCP_BADARG(env, "Bad padding flag");
- goto err;
- }
-
- ctx_res->padding = padding_arg;
-
*return_term = atom_ok;
#if !defined(HAVE_EVP_AES_CTR)
@@ -309,18 +395,18 @@ static int get_init_args(ErlNifEnv* env,
/*************************************************************************/
/* Get the arguments for the EVP_CipherUpdate function, and call it. */
/*************************************************************************/
-
static int get_update_args(ErlNifEnv* env,
struct evp_cipher_ctx *ctx_res,
- const ERL_NIF_TERM indata_arg,
+ const ERL_NIF_TERM argv[],
+ int indata_arg_num,
ERL_NIF_TERM *return_term)
{
ErlNifBinary in_data_bin, out_data_bin;
int out_len, block_size;
- if (!enif_inspect_binary(env, indata_arg, &in_data_bin) )
+ if (!enif_inspect_iolist_as_binary(env, argv[indata_arg_num], &in_data_bin) )
{
- *return_term = EXCP_BADARG(env, "Bad 2:nd arg");
+ *return_term = EXCP_BADARG_N(env, indata_arg_num, "Expected binary");
goto err0;
}
@@ -340,7 +426,7 @@ static int get_update_args(ErlNifEnv* env,
if (enif_get_tuple(env, state0, &tuple_argc, &tuple_argv) && (tuple_argc == 4)) {
/* A compatibility state term */
/* encrypt and decrypt is performed by calling the same function */
- newstate_and_outdata = aes_ctr_stream_encrypt_compat(env, state0, indata_arg);
+ newstate_and_outdata = aes_ctr_stream_encrypt_compat(env, state0, argv[indata_arg_num]);
if (enif_get_tuple(env, newstate_and_outdata, &tuple_argc, &tuple_argv) && (tuple_argc == 2)) {
/* newstate_and_outdata = {NewState, OutData} */
@@ -488,7 +574,11 @@ static int get_final_args(ErlNifEnv* env,
else
{
- *return_term = EXCP_ERROR(env, "Bad padding flg");
+ char msg[64];
+ if (enif_snprintf(msg, 64, "Bad padding flag: %T", ctx_res->padding))
+ *return_term = EXCP_ERROR(env, msg);
+ else
+ *return_term = EXCP_ERROR(env, "Bad padding flg");
goto err;
}
@@ -567,7 +657,7 @@ static int get_final_args(ErlNifEnv* env,
/*************************************************************************/
ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Cipher, Key, IVec, Encrypt, Padding) % if no IV for the Cipher, set IVec = <<>>
+{/* (Cipher, Key, IVec, OptionsMap) % if no IV for the Cipher, set IVec = <<>>
*/
struct evp_cipher_ctx *ctx_res = NULL;
const struct cipher_type_t *cipherp;
@@ -577,8 +667,7 @@ ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
if ((ctx_res = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx))) == NULL)
return EXCP_ERROR(env, "Can't allocate resource");
- if (get_init_args(env, ctx_res, argv[0], argv[1], argv[2], argv[3], argv[4],
- &cipherp, &ret))
+ if (get_init_args(env, ctx_res, argv, 0, 1, 2, 3, &cipherp, &ret))
ret = enif_make_resource(env, ctx_res);
/* else error msg in ret */
@@ -591,7 +680,7 @@ ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
else if (argv[3] == atom_false)
ctx_res->encflag = 0;
else {
- ret = EXCP_BADARG(env, "Bad enc flag");
+ ret = EXCP_BADARG_N(env, 3, "Expected true or false");
goto ret;
}
if (ctx_res->ctx) {
@@ -603,7 +692,7 @@ ERL_NIF_TERM ng_crypto_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
}
ret = argv[0];
} else {
- ret = EXCP_BADARG(env, "Bad 1:st arg");
+ ret = EXCP_BADARG_N(env, 0, "Expected cipher name atom");
goto ret;
}
@@ -625,7 +714,7 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
ctx_res_copy.ctx = NULL;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
- return EXCP_BADARG(env, "Bad 1:st arg");
+ return EXCP_BADARG_N(env, 0, "Bad State");
if (argc == 3) {
/* We have an IV in this call. Make a copy of the context */
@@ -647,13 +736,13 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
if (!enif_inspect_iolist_as_binary(env, argv[2], &ivec_bin))
{
- ret = EXCP_BADARG(env, "Bad iv type");
+ ret = EXCP_BADARG_N(env, 2, "Bad iv type");
goto err;
}
if (ctx_res_copy.iv_len != ivec_bin.size)
{
- ret = EXCP_BADARG(env, "Bad iv size");
+ ret = EXCP_BADARG_N(env, 2, "Bad iv size");
goto err;
}
@@ -676,11 +765,11 @@ ERL_NIF_TERM ng_crypto_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
goto err;
}
- get_update_args(env, &ctx_res_copy, argv[1], &ret);
+ get_update_args(env, &ctx_res_copy, argv, 1, &ret);
ctx_res->size = ctx_res_copy.size;
} else
/* argc != 3, that is, argc = 2 (we don't have an IV in this call) */
- get_update_args(env, ctx_res, argv[1], &ret);
+ get_update_args(env, ctx_res, argv, 1, &ret);
err:
if (ctx_res_copy.ctx)
@@ -694,11 +783,11 @@ ERL_NIF_TERM ng_crypto_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
{/* (Context, Data [, IV]) */
ErlNifBinary data_bin;
- if (!enif_inspect_binary(env, argv[1], &data_bin))
- return EXCP_BADARG(env, "expected binary as data");
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &data_bin))
+ return EXCP_BADARG_N(env, 1, "expected binary");
if (data_bin.size > INT_MAX)
- return EXCP_BADARG(env, "to long data");
+ return EXCP_BADARG_N(env, 1, "too long data");
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (data_bin.size > MAX_BYTES_TO_NIF) {
@@ -721,7 +810,7 @@ ERL_NIF_TERM ng_crypto_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
ERL_NIF_TERM ret;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
- return EXCP_BADARG(env, "Bad arg");
+ return EXCP_BADARG_N(env, 0, "Bad State");
get_final_args(env, ctx_res, &ret);
@@ -733,7 +822,7 @@ ERL_NIF_TERM ng_crypto_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
/*************************************************************************/
ERL_NIF_TERM ng_crypto_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Cipher, Key, IVec, Data, Encrypt, PaddingType) */
+{/* (Cipher, Key, IVec, Data, OptionsMap) */
struct evp_cipher_ctx ctx_res;
const struct cipher_type_t *cipherp;
ERL_NIF_TERM ret;
@@ -746,11 +835,11 @@ ERL_NIF_TERM ng_crypto_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
#endif
/* EVP_CipherInit */
- if (!get_init_args(env, &ctx_res, argv[0], argv[1], argv[2], argv[4], argv[5], &cipherp, &ret))
+ if (!get_init_args(env, &ctx_res, argv, 0, 1, 2, 4, &cipherp, &ret))
goto out;
/* out_data = EVP_CipherUpdate */
- if (!get_update_args(env, &ctx_res, argv[3], &ret))
+ if (!get_update_args(env, &ctx_res, argv, 3, &ret))
/* Got an exception as result in &ret */
goto out;
@@ -800,11 +889,11 @@ ERL_NIF_TERM ng_crypto_one_time_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
*/
ErlNifBinary data_bin;
- if (!enif_inspect_binary(env, argv[3], &data_bin))
- return EXCP_BADARG(env, "expected binary as data");
+ if (!enif_inspect_iolist_as_binary(env, argv[3], &data_bin))
+ return EXCP_BADARG_N(env, 3, "expected binary as data");
if (data_bin.size > INT_MAX)
- return EXCP_BADARG(env, "to long data");
+ return EXCP_BADARG_N(env, 3, "too long data");
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (data_bin.size > MAX_BYTES_TO_NIF) {
@@ -827,7 +916,7 @@ ERL_NIF_TERM ng_crypto_get_data_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ERL_NIF_TERM ret;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)evp_cipher_ctx_rtype, (void**)&ctx_res))
- return EXCP_BADARG(env, "Bad arg");
+ return EXCP_BADARG_N(env, 0, "Bad State");
ret = enif_make_new_map(env);
diff --git a/lib/crypto/c_src/atoms.c b/lib/crypto/c_src/atoms.c
index 5671e6d801..cae3c5287d 100644
--- a/lib/crypto/c_src/atoms.c
+++ b/lib/crypto/c_src/atoms.c
@@ -24,6 +24,8 @@ ERL_NIF_TERM atom_true;
ERL_NIF_TERM atom_false;
ERL_NIF_TERM atom_sha;
ERL_NIF_TERM atom_error;
+ERL_NIF_TERM atom_encrypt;
+ERL_NIF_TERM atom_padding;
ERL_NIF_TERM atom_pkcs_padding;
ERL_NIF_TERM atom_zero;
ERL_NIF_TERM atom_random;
@@ -165,6 +167,8 @@ int init_atoms(ErlNifEnv *env, const ERL_NIF_TERM fips_mode, const ERL_NIF_TERM
atom_sha = enif_make_atom(env,"sha");
atom_error = enif_make_atom(env,"error");
+ atom_encrypt = enif_make_atom(env,"encrypt");
+ atom_padding = enif_make_atom(env,"padding");
atom_pkcs_padding = enif_make_atom(env,"pkcs_padding");
atom_zero = enif_make_atom(env,"zero");
atom_random = enif_make_atom(env,"random");
diff --git a/lib/crypto/c_src/atoms.h b/lib/crypto/c_src/atoms.h
index 414e3045ea..d6bdc43a52 100644
--- a/lib/crypto/c_src/atoms.h
+++ b/lib/crypto/c_src/atoms.h
@@ -28,6 +28,8 @@ extern ERL_NIF_TERM atom_true;
extern ERL_NIF_TERM atom_false;
extern ERL_NIF_TERM atom_sha;
extern ERL_NIF_TERM atom_error;
+extern ERL_NIF_TERM atom_encrypt;
+extern ERL_NIF_TERM atom_padding;
extern ERL_NIF_TERM atom_pkcs_padding;
extern ERL_NIF_TERM atom_zero;
extern ERL_NIF_TERM atom_random;
diff --git a/lib/crypto/c_src/cipher.c b/lib/crypto/c_src/cipher.c
index 5e7fc88d72..284ea0ba81 100644
--- a/lib/crypto/c_src/cipher.c
+++ b/lib/crypto/c_src/cipher.c
@@ -317,10 +317,13 @@ const struct cipher_type_t* get_cipher_type_no_key(ERL_NIF_TERM type)
int cmp_cipher_types_no_key(const void *keyp, const void *elemp) {
const struct cipher_type_t *key = keyp;
const struct cipher_type_t *elem = elemp;
+ int ret;
- if (key->type.atom < elem->type.atom) return -1;
- else if (key->type.atom > elem->type.atom) return 1;
- else /* key->type.atom == elem->type.atom */ return 0;
+ if (key->type.atom < elem->type.atom) ret = -1;
+ else if (key->type.atom > elem->type.atom) ret = 1;
+ else /* key->type.atom == elem->type.atom */ ret = 0;
+
+ return ret;
}
diff --git a/lib/crypto/c_src/common.c b/lib/crypto/c_src/common.c
new file mode 100644
index 0000000000..e5160548c4
--- /dev/null
+++ b/lib/crypto/c_src/common.c
@@ -0,0 +1,53 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2010-2021. 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%
+ */
+
+#include "common.h"
+
+ERL_NIF_TERM raise_exception(ErlNifEnv* env, ERL_NIF_TERM id, int arg_num, char* explanation, char* file, int line)
+/* Ex: raise_exception(atom_badarg, 1, "Unknown cipher", "api_ng.c", 17)
+ * -> {badarg, {"api_ng.c",17}, 1, "Unknown cipher"}
+ * id = atom_error | atom_notsup | atom_badarg
+ * arg_num is the (zero-based) position in argv[]. -1 is to signal that it is undefined.
+ */
+{
+ ERL_NIF_TERM file_info, exception;
+
+ file_info = enif_make_new_map(env);
+ enif_make_map_put(env, file_info,
+ enif_make_atom(env,"c_file_name"),
+ enif_make_string(env, file, (ERL_NIF_LATIN1)),
+ &file_info);
+ enif_make_map_put(env, file_info,
+ enif_make_atom(env,"c_file_line_num"),
+ enif_make_int(env, line),
+ &file_info);
+ enif_make_map_put(env, file_info,
+ enif_make_atom(env,"c_function_arg_num"),
+ enif_make_int(env, arg_num),
+ &file_info);
+ exception =
+ enif_make_tuple3(env,
+ id,
+ file_info,
+ enif_make_string(env, explanation, (ERL_NIF_LATIN1))
+ );
+
+ return enif_raise_exception(env, exception);
+}
diff --git a/lib/crypto/c_src/common.h b/lib/crypto/c_src/common.h
index 22aa38d806..8406cd0b7c 100644
--- a/lib/crypto/c_src/common.h
+++ b/lib/crypto/c_src/common.h
@@ -37,16 +37,13 @@
/* All nif functions return a valid value or throws an exception */
-#define EXCP(Env, Id, Str) enif_raise_exception((Env), \
- enif_make_tuple3((Env), \
- (Id), \
- enif_make_tuple2((Env), \
- enif_make_string((Env),__FILE__,(ERL_NIF_LATIN1)), \
- enif_make_int((Env), __LINE__)), \
- enif_make_string((Env),(Str),(ERL_NIF_LATIN1)) ))
-
-#define EXCP_NOTSUP(Env, Str) EXCP((Env), atom_notsup, (Str))
-#define EXCP_BADARG(Env, Str) EXCP((Env), atom_badarg, (Str))
-#define EXCP_ERROR(Env, Str) EXCP((Env), atom_error, (Str))
+ERL_NIF_TERM raise_exception(ErlNifEnv* env, ERL_NIF_TERM id, int arg_num, char* explanation, char* file, int Line);
+
+
+#define EXCP_ERROR(Env, Str) raise_exception((Env), atom_error, -1, (Str), __FILE__, __LINE__)
+#define EXCP_NOTSUP(Env, Str) raise_exception((Env), atom_notsup, -1, (Str), __FILE__, __LINE__)
+#define EXCP_ERROR_N(Env, ArgNum, Str) raise_exception((Env), atom_error, (ArgNum), (Str), __FILE__, __LINE__)
+#define EXCP_NOTSUP_N(Env, ArgNum, Str) raise_exception((Env), atom_notsup, (ArgNum), (Str), __FILE__, __LINE__)
+#define EXCP_BADARG_N(Env, ArgNum, Str) raise_exception((Env), atom_badarg, (ArgNum), (Str), __FILE__, __LINE__)
#endif /* E_COMMON_H__ */
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 66239462be..65804bf6fb 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -79,12 +79,12 @@ static ErlNifFunc nif_funcs[] = {
{"mac_update_nif", 2, mac_update_nif, 0},
{"mac_final_nif", 1, mac_final_nif, 0},
{"cipher_info_nif", 1, cipher_info_nif, 0},
- {"ng_crypto_init_nif", 5, ng_crypto_init_nif, 0},
+ {"ng_crypto_init_nif", 4, ng_crypto_init_nif, 0},
{"ng_crypto_update_nif", 2, ng_crypto_update_nif, 0},
{"ng_crypto_update_nif", 3, ng_crypto_update_nif, 0},
{"ng_crypto_final_nif", 1, ng_crypto_final_nif, 0},
{"ng_crypto_get_data_nif", 1, ng_crypto_get_data_nif, 0},
- {"ng_crypto_one_time_nif", 6, ng_crypto_one_time_nif, 0},
+ {"ng_crypto_one_time_nif", 5, ng_crypto_one_time_nif, 0},
{"strong_rand_bytes_nif", 1, strong_rand_bytes_nif, 0},
{"strong_rand_range_nif", 1, strong_rand_range_nif, 0},
{"rand_uniform_nif", 2, rand_uniform_nif, 0},
@@ -131,7 +131,8 @@ ERL_NIF_INIT(crypto,nif_funcs,load,NULL,upgrade,unload)
static int verify_lib_version(void)
{
-#if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
+#if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION_PLAIN(1,1,0) \
+ || defined(HAS_LIBRESSL)
const unsigned long libv = SSLeay();
#else
const unsigned long libv = OpenSSL_version_num();
diff --git a/lib/crypto/c_src/mac.c b/lib/crypto/c_src/mac.c
index 8735158a01..13bd2815b1 100644
--- a/lib/crypto/c_src/mac.c
+++ b/lib/crypto/c_src/mac.c
@@ -176,10 +176,10 @@ ERL_NIF_TERM mac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifBinary text;
if (!enif_inspect_iolist_as_binary(env, argv[3], &text))
- return EXCP_BADARG(env, "Bad text");
+ return EXCP_BADARG_N(env, 3, "Bad text");
if (text.size > INT_MAX)
- return EXCP_BADARG(env, "Too long text");
+ return EXCP_BADARG_N(env, 3, "Too long text");
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (text.size > MAX_BYTES_TO_NIF) {
@@ -213,28 +213,28 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
*/
if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin))
{
- return_term = EXCP_BADARG(env, "Bad key");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key");
goto err;
}
if (!enif_inspect_iolist_as_binary(env, argv[3], &text))
{
- return_term = EXCP_BADARG(env, "Bad text");
+ return_term = EXCP_BADARG_N(env, 3, "Bad text");
goto err;
}
if (!(macp = get_mac_type(argv[0], key_bin.size)))
{
if (!get_mac_type_no_key(argv[0]))
- return_term = EXCP_BADARG(env, "Unknown mac algorithm");
+ return_term = EXCP_BADARG_N(env, 0, "Unknown mac algorithm");
else
- return_term = EXCP_BADARG(env, "Bad key length");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key length");
goto err;
}
if (MAC_FORBIDDEN_IN_FIPS(macp))
{
- return_term = EXCP_NOTSUP(env, "MAC algorithm forbidden in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 0, "MAC algorithm forbidden in FIPS");
goto err;
}
@@ -256,17 +256,17 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if ((digp = get_digest_type(argv[1])) == NULL)
{
- return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC");
+ return_term = EXCP_BADARG_N(env, 1, "Bad digest algorithm for HMAC");
goto err;
}
if (digp->md.p == NULL)
{
- return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported digest algorithm");
goto err;
}
if (DIGEST_FORBIDDEN_IN_FIPS(digp))
{
- return_term = EXCP_NOTSUP(env, "Digest algorithm for HMAC forbidden in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 1, "Digest algorithm for HMAC forbidden in FIPS");
goto err;
}
md = digp->md.p;
@@ -300,22 +300,22 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if (!(cipherp = get_cipher_type(argv[1], key_bin.size)))
{ /* Something went wrong. Find out what by retrying in another way. */
if (!get_cipher_type_no_key(argv[1]))
- return_term = EXCP_BADARG(env, "Unknown cipher");
+ return_term = EXCP_BADARG_N(env, 1, "Unknown cipher");
else
/* Cipher exists, so it must be the key size that is wrong */
- return_term = EXCP_BADARG(env, "Bad key size");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key size");
goto err;
}
if (CIPHER_FORBIDDEN_IN_FIPS(cipherp))
{
- return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 1, "Cipher algorithm not supported in FIPS");
goto err;
}
if (cipherp->cipher.p == NULL)
{
- return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported cipher algorithm");
goto err;
}
@@ -349,7 +349,7 @@ ERL_NIF_TERM mac_one_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
case NO_mac:
default:
/* We know that this mac is supported with some version(s) of cryptolib */
- return_term = EXCP_NOTSUP(env, "Unsupported mac algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported mac algorithm");
goto err;
}
@@ -506,22 +506,22 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
*/
if (!enif_inspect_iolist_as_binary(env, argv[2], &key_bin))
{
- return_term = EXCP_BADARG(env, "Bad key");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key");
goto err;
}
if (!(macp = get_mac_type(argv[0], key_bin.size)))
{
if (!get_mac_type_no_key(argv[0]))
- return_term = EXCP_BADARG(env, "Unknown mac algorithm");
+ return_term = EXCP_BADARG_N(env, 0, "Unknown mac algorithm");
else
- return_term = EXCP_BADARG(env, "Bad key length");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key length");
goto err;
}
if (MAC_FORBIDDEN_IN_FIPS(macp))
{
- return_term = EXCP_NOTSUP(env, "MAC algorithm forbidden in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 0, "MAC algorithm forbidden in FIPS");
goto err;
}
@@ -543,17 +543,17 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if ((digp = get_digest_type(argv[1])) == NULL)
{
- return_term = EXCP_BADARG(env, "Bad digest algorithm for HMAC");
+ return_term = EXCP_BADARG_N(env, 1, "Bad digest algorithm for HMAC");
goto err;
}
if (digp->md.p == NULL)
{
- return_term = EXCP_NOTSUP(env, "Unsupported digest algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported digest algorithm");
goto err;
}
if (DIGEST_FORBIDDEN_IN_FIPS(digp))
{
- return_term = EXCP_NOTSUP(env, "Digest algorithm for HMAC forbidden in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 1, "Digest algorithm for HMAC forbidden in FIPS");
goto err;
}
md = digp->md.p;
@@ -579,22 +579,22 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
if (!(cipherp = get_cipher_type(argv[1], key_bin.size)))
{ /* Something went wrong. Find out what by retrying in another way. */
if (!get_cipher_type_no_key(argv[1]))
- return_term = EXCP_BADARG(env, "Unknown cipher");
+ return_term = EXCP_BADARG_N(env, 1, "Unknown cipher");
else
/* Cipher exists, so it must be the key size that is wrong */
- return_term = EXCP_BADARG(env, "Bad key size");
+ return_term = EXCP_BADARG_N(env, 2, "Bad key size");
goto err;
}
if (CIPHER_FORBIDDEN_IN_FIPS(cipherp))
{
- return_term = EXCP_NOTSUP(env, "Cipher algorithm not supported in FIPS");
+ return_term = EXCP_NOTSUP_N(env, 1, "Cipher algorithm not supported in FIPS");
goto err;
}
if (cipherp->cipher.p == NULL)
{
- return_term = EXCP_NOTSUP(env, "Unsupported cipher algorithm");
+ return_term = EXCP_NOTSUP_N(env, 1, "Unsupported cipher algorithm");
goto err;
}
@@ -621,7 +621,7 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
case NO_mac:
default:
/* We know that this mac is supported with some version(s) of cryptolib */
- return_term = EXCP_NOTSUP(env, "Unsupported mac algorithm");
+ return_term = EXCP_NOTSUP_N(env, 0, "Unsupported mac algorithm");
goto err;
}
@@ -666,7 +666,7 @@ ERL_NIF_TERM mac_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
#else
if (argv[0] != atom_hmac)
- return EXCP_NOTSUP(env, "Unsupported mac algorithm");
+ return EXCP_NOTSUP_N(env, 0, "Unsupported mac algorithm");
return hmac_init_nif(env, argc, argv);
#endif
@@ -679,10 +679,10 @@ ERL_NIF_TERM mac_update_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifBinary text;
if (!enif_inspect_iolist_as_binary(env, argv[1], &text))
- return EXCP_BADARG(env, "Bad text");
+ return EXCP_BADARG_N(env, 1, "Bad text");
if (text.size > INT_MAX)
- return EXCP_BADARG(env, "Too long text");
+ return EXCP_BADARG_N(env, 1, "Too long text");
/* Run long jobs on a dirty scheduler to not block the current emulator thread */
if (text.size > MAX_BYTES_TO_NIF) {
@@ -702,10 +702,10 @@ ERL_NIF_TERM mac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifBinary text;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj))
- return EXCP_BADARG(env, "Bad ref");
+ return EXCP_BADARG_N(env, 0, "Bad ref");
if (!enif_inspect_iolist_as_binary(env, argv[1], &text))
- return EXCP_BADARG(env, "Bad text");
+ return EXCP_BADARG_N(env, 1, "Bad text");
if (EVP_DigestSignUpdate(obj->ctx, text.data, text.size) != 1)
return EXCP_ERROR(env, "EVP_DigestSignUpdate");
@@ -728,7 +728,7 @@ ERL_NIF_TERM mac_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifBinary ret_bin;
if (!enif_get_resource(env, argv[0], (ErlNifResourceType*)mac_context_rtype, (void**)&obj))
- return EXCP_BADARG(env, "Bad ref");
+ return EXCP_BADARG_N(env, 0, "Bad ref");
if (EVP_DigestSignFinal(obj->ctx, NULL, &size) != 1)
return EXCP_ERROR(env, "Can't get sign size");
diff --git a/lib/crypto/c_src/otp_test_engine.c b/lib/crypto/c_src/otp_test_engine.c
index f5fff85b14..cee251a280 100644
--- a/lib/crypto/c_src/otp_test_engine.c
+++ b/lib/crypto/c_src/otp_test_engine.c
@@ -59,6 +59,7 @@
/* If OPENSSL_NO_EC is set, there will be an error in ec.h included from engine.h
So if EC is disabled, you can't use Engine either....
*/
+
#include <openssl/engine.h>
#include <openssl/pem.h>
@@ -192,7 +193,9 @@ static EVP_MD test_engine_md5_method= {
EVP_PKEY_NULL_method, /* IGNORED: pkey methods */
MD5_CBLOCK, /* Internal blocksize, see rfc1321/md5.h */
sizeof(EVP_MD *) + sizeof(MD5_CTX),
+# if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
NULL, /* IGNORED: control function */
+# endif
};
#endif
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 5d72114055..473be885c9 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -42,7 +42,7 @@
-export([privkey_to_pubkey/2]).
-export([ec_curve/1, ec_curves/0]).
-export([rand_seed/1]).
-
+-export([format_error/2]).
%%%----------------------------------------------------------------
%% Removed functions.
%%
@@ -403,23 +403,47 @@
%%--------------------------------------------------------------------
-%%
-%% Make the new descriptive_error() look like the old run_time_error()
-%%
--define(COMPAT(CALL),
- try begin CALL end
- catch
- error:{error, {_File,_Line}, _Reason} ->
- error(badarg);
- error:{E, {_File,_Line}, _Reason} when E==notsup ; E==badarg ->
- error(E)
- end).
-
+%% Compilation and loading
%%--------------------------------------------------------------------
-compile(no_native).
-on_load(on_load/0).
-define(CRYPTO_NIF_VSN,302).
+%%--------------------------------------------------------------------
+%% When generating documentation from crypto.erl, the macro ?CRYPTO_VSN is not defined.
+%% That causes the doc generation to stop...
+-ifndef(CRYPTO_VSN).
+-define(CRYPTO_VSN, "??").
+-endif.
+
+%%--------------------------------------------------------------------
+%% Call a nif and handle an error exceptions to fit into the error handling
+%% in the Erlang shell.
+%% If not called from a shell, an error exception will be propagated.
+
+-define(nif_call(Call), ?nif_call(Call, undefined, {})).
+
+-define(nif_call(Call, ArgMap), ?nif_call(Call, undefined, ArgMap)).
+
+-define(nif_call(Call, Args0, ArgMap),
+ try Call
+ catch
+ error
+ : {Id, #{c_file_name := C_file,
+ c_file_line_num := C_line,
+ c_function_arg_num := ArgNum}, Msg}
+ : Stack when is_list(C_file),
+ is_integer(C_line),
+ is_integer(ArgNum) ->
+ error({Id, {C_file,C_line}, Msg},
+ err_find_args(Args0, Stack),
+ [{error_info, #{erl_function_arg_num => err_remap_C_argnum(ArgNum, ArgMap)}}]
+ )
+ end).
+
+%%--------------------------------------------------------------------
+%% Error if the crypto nifs not are loaded
+
-define(nif_stub,nif_stub_error(?LINE)).
nif_stub_error(Line) ->
erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}).
@@ -427,16 +451,24 @@ nif_stub_error(Line) ->
%%--------------------------------------------------------------------
%%% API
%%--------------------------------------------------------------------
-%% Crypto app version history:
-%% (no version): Driver implementation
-%% 2.0 : NIF implementation, requires OTP R14
+version() ->
+ ?CRYPTO_VSN.
+
+format_error({Ex, {C_file,C_line}, Msg}, [{_M,_F,_Args,Opts} | _CallStack]) when Ex == badarg ;
+ Ex == notsup ->
+ case proplists:get_value(error_info, Opts) of
+ #{erl_function_arg_num := ErlArgNum} ->
+ FileMsg =
+ io_lib:format("(Found in the internal file ~s at line ~p)", [C_file, C_line]),
+ case ErlArgNum of
+ undefined ->
+ #{general => [Msg," ",FileMsg]};
+ N ->#{N => Msg,
+ general => FileMsg
+ }
+ end
+ end.
-%% When generating documentation from crypto.erl, the macro ?CRYPTO_VSN is not defined.
-%% That causes the doc generation to stop...
--ifndef(CRYPTO_VSN).
--define(CRYPTO_VSN, "??").
--endif.
-version() -> ?CRYPTO_VSN.
-spec start() -> ok | {error, Reason::term()}.
start() ->
@@ -769,11 +801,9 @@ cipher_info(Type) ->
FlagOrOptions :: crypto_opts() | boolean(),
State :: crypto_state() .
crypto_init(Cipher, Key, FlagOrOptions) ->
- ng_crypto_init_nif(Cipher,
- iolist_to_binary(Key),
- <<>>,
- get_crypto_opts(FlagOrOptions)).
-
+ ?nif_call(ng_crypto_init_nif(alias(Cipher,Key), Key, <<>>, FlagOrOptions),
+ {1,2,-1,3}
+ ).
-spec crypto_init(Cipher, Key, IV, FlagOrOptions) -> State | descriptive_error()
when Cipher :: cipher_iv(),
@@ -782,40 +812,7 @@ crypto_init(Cipher, Key, FlagOrOptions) ->
FlagOrOptions :: crypto_opts(),
State :: crypto_state() .
crypto_init(Cipher, Key, IV, FlagOrOptions) ->
- ng_crypto_init_nif(Cipher,
- iolist_to_binary(Key),
- iolist_to_binary(IV),
- get_crypto_opts(FlagOrOptions)).
-
-%%%----------------------------------------------------------------
-get_crypto_opts(Options) when is_list(Options) ->
- lists:foldl(fun chk_opt/2,
- #{encrypt => true,
- padding => undefined
- },
- Options);
-get_crypto_opts(Flag) when is_boolean(Flag) ->
- #{encrypt => Flag,
- padding => undefined
- };
-get_crypto_opts(X) ->
- error({badarg,{bad_option,X}}).
-
-
-chk_opt({Tag,Val}, A) ->
- case ok_opt(Tag,Val) of
- true ->
- A#{Tag => Val};
- false ->
- error({badarg,{bad_option,{Tag,Val}}})
- end;
-chk_opt(X, _) ->
- error({badarg,{bad_option,X}}).
-
-
-ok_opt(encrypt, V) -> lists:member(V, [true, false, undefined]);
-ok_opt(padding, V) -> lists:member(V, [none, pkcs_padding, zero, random, undefined]);
-ok_opt(_, _) -> false.
+ ?nif_call(ng_crypto_init_nif(alias(Cipher,Key), Key, IV, FlagOrOptions)).
%%%----------------------------------------------------------------
-spec crypto_dyn_iv_init(Cipher, Key, FlagOrOptions) -> State | descriptive_error()
@@ -825,10 +822,10 @@ ok_opt(_, _) -> false.
State :: crypto_state() .
crypto_dyn_iv_init(Cipher, Key, FlagOrOptions) ->
%% The IV is supposed to be supplied by calling crypto_update/3
- ng_crypto_init_nif(Cipher,
- iolist_to_binary(Key),
- undefined,
- get_crypto_opts(FlagOrOptions)).
+ ?nif_call(ng_crypto_init_nif(alias(Cipher,Key), Key, undefined, FlagOrOptions),
+ [Cipher, Key, FlagOrOptions],
+ {1,2,-1,3}
+ ).
%%%----------------------------------------------------------------
%%%
@@ -842,7 +839,7 @@ crypto_dyn_iv_init(Cipher, Key, FlagOrOptions) ->
Data :: iodata(),
Result :: binary() .
crypto_update(State, Data) ->
- ng_crypto_update_nif(State, iolist_to_binary(Data)).
+ ?nif_call(ng_crypto_update_nif(State, Data)).
%%%----------------------------------------------------------------
-spec crypto_dyn_iv_update(State, Data, IV) -> Result | descriptive_error()
@@ -851,7 +848,7 @@ crypto_update(State, Data) ->
IV :: iodata(),
Result :: binary() .
crypto_dyn_iv_update(State, Data, IV) ->
- ng_crypto_update_nif(State, iolist_to_binary(Data), iolist_to_binary(IV)).
+ ?nif_call(ng_crypto_update_nif(State, Data, IV)).
%%%----------------------------------------------------------------
%%%
@@ -863,7 +860,7 @@ crypto_dyn_iv_update(State, Data, IV) ->
when State :: crypto_state(),
FinalResult :: binary() .
crypto_final(State) ->
- ng_crypto_final_nif(State).
+ ?nif_call(ng_crypto_final_nif(State)).
%%%----------------------------------------------------------------
%%%
@@ -873,7 +870,7 @@ crypto_final(State) ->
when State :: crypto_state(),
Result :: map() .
crypto_get_data(State) ->
- ng_crypto_get_data_nif(State).
+ ?nif_call(ng_crypto_get_data_nif(State)).
%%%----------------------------------------------------------------
%%%
@@ -890,11 +887,10 @@ crypto_get_data(State) ->
Result :: binary() .
crypto_one_time(Cipher, Key, Data, FlagOrOptions) ->
- ng_crypto_one_time_nif(Cipher,
- iolist_to_binary(Key),
- <<>>,
- iolist_to_binary(Data),
- get_crypto_opts(FlagOrOptions)).
+ ?nif_call(ng_crypto_one_time_nif(alias(Cipher,Key), Key, <<>>, Data, FlagOrOptions),
+ [Cipher, Key, Data, FlagOrOptions],
+ {1,2,-1,3,4}
+ ).
-spec crypto_one_time(Cipher, Key, IV, Data, FlagOrOptions) ->
@@ -907,11 +903,9 @@ crypto_one_time(Cipher, Key, Data, FlagOrOptions) ->
Result :: binary() .
crypto_one_time(Cipher, Key, IV, Data, FlagOrOptions) ->
- ng_crypto_one_time_nif(Cipher,
- iolist_to_binary(Key),
- iolist_to_binary(IV),
- iolist_to_binary(Data),
- get_crypto_opts(FlagOrOptions)).
+ ?nif_call(ng_crypto_one_time_nif(alias(Cipher,Key), Key, IV, Data, FlagOrOptions),
+ [Cipher, Key, IV, Data, FlagOrOptions],
+ {}).
%%%----------------------------------------------------------------
-spec crypto_one_time_aead(Cipher, Key, IV, InText, AAD, EncFlag::true) ->
@@ -927,7 +921,9 @@ crypto_one_time(Cipher, Key, IV, Data, FlagOrOptions) ->
OutTag :: binary().
crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, true) ->
- crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, aead_tag_len(Cipher), true).
+ ?nif_call(aead_cipher_nif(alias(Cipher,Key), Key, IV, PlainText, AAD, aead_tag_len(Cipher), true),
+ {1,2,3,4,5,-1,6}
+ ).
-spec crypto_one_time_aead(Cipher, Key, IV, InText, AAD, TagOrTagLength, EncFlag) ->
@@ -949,8 +945,10 @@ crypto_one_time_aead(Cipher, Key, IV, PlainText, AAD, true) ->
OutPlainText :: binary().
crypto_one_time_aead(Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg) ->
- aead_cipher(Cipher, iolist_to_binary(Key), IV,
- TextIn, AAD, TagOrTagLength, EncFlg).
+ ?nif_call(aead_cipher_nif(alias(Cipher,Key), Key, IV, TextIn, AAD, TagOrTagLength, EncFlg),
+ [Cipher, Key, IV, TextIn, AAD, TagOrTagLength, EncFlg],
+ {}
+ ).
aead_tag_len(aes_ccm ) -> 12;
@@ -968,12 +966,7 @@ aead_tag_len(_) ->
%%%----------------------------------------------------------------
%%% Cipher NIFs
-ng_crypto_init_nif(Cipher, Key, IVec, #{encrypt := EncryptFlag,
- padding := Padding}) ->
- ng_crypto_init_nif(alias(Cipher,Key), Key, IVec, EncryptFlag, Padding).
-
-ng_crypto_init_nif(_Cipher, _Key, _IVec, _EncryptFlag, _Padding) -> ?nif_stub.
-
+ng_crypto_init_nif(_Cipher, _Key, _IVec, _OptionsMap) -> ?nif_stub.
ng_crypto_update_nif(_State, _Data) -> ?nif_stub.
ng_crypto_update_nif(_State, _Data, _IV) -> ?nif_stub.
@@ -982,15 +975,7 @@ ng_crypto_final_nif(_State) -> ?nif_stub.
ng_crypto_get_data_nif(_State) -> ?nif_stub.
-ng_crypto_one_time_nif(Cipher, Key, IVec, Data, #{encrypt := EncryptFlag,
- padding := Padding}) ->
- ng_crypto_one_time_nif(alias(Cipher,Key), Key, IVec, Data, EncryptFlag, Padding).
-
-ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _EncryptFlag, _Padding) -> ?nif_stub.
-
-%% The default tag length is EVP_GCM_TLS_TAG_LEN(16),
-aead_cipher(Cipher, Key, IVec, AAD, In, TagOrLength, EncFlg) ->
- aead_cipher_nif(alias(Cipher,Key), Key, IVec, AAD, In, TagOrLength, EncFlg).
+ng_crypto_one_time_nif(_Cipher, _Key, _IVec, _Data, _OptionsMap) -> ?nif_stub.
aead_cipher_nif(_Type, _Key, _Ivec, _AAD, _In, _TagOrTagLength, _EncFlg) -> ?nif_stub.
@@ -1000,13 +985,13 @@ cipher_info_nif(_Type) -> ?nif_stub.
%%% Cipher aliases
%%%
-alias(aes_cbc, Key) -> alias1(aes_cbc, size(Key));
-alias(aes_cfb8, Key) -> alias1(aes_cfb8, size(Key));
-alias(aes_cfb128, Key) -> alias1(aes_cfb128, size(Key));
-alias(aes_ctr, Key) -> alias1(aes_ctr, size(Key));
-alias(aes_ecb, Key) -> alias1(aes_ecb, size(Key));
-alias(aes_gcm, Key) -> alias1(aes_gcm, size(Key));
-alias(aes_ccm, Key) -> alias1(aes_ccm, size(Key));
+alias(aes_cbc, Key) -> alias1(aes_cbc, iolist_size(Key));
+alias(aes_cfb8, Key) -> alias1(aes_cfb8, iolist_size(Key));
+alias(aes_cfb128, Key) -> alias1(aes_cfb128, iolist_size(Key));
+alias(aes_ctr, Key) -> alias1(aes_ctr, iolist_size(Key));
+alias(aes_ecb, Key) -> alias1(aes_ecb, iolist_size(Key));
+alias(aes_gcm, Key) -> alias1(aes_gcm, iolist_size(Key));
+alias(aes_ccm, Key) -> alias1(aes_ccm, iolist_size(Key));
alias(Alg, _) -> Alg.
@@ -2511,3 +2496,24 @@ choose_otp_test_engine([LibName | T], Type, Acc) ->
end;
choose_otp_test_engine([], _, Acc) ->
Acc.
+
+%%%----------------------------------------------------------------
+%%% Error internals
+
+err_find_args(undefined, [{?MODULE,_F,Args,_Info}|_]) -> Args;
+err_find_args(Args, _) -> Args.
+
+
+err_remap_C_argnum(ArgNum, ArgMap) ->
+ try
+ element(ArgNum + 1, ArgMap) % 0-numbered in C-file's argv[], 1-numbered in the tuple
+ of
+ N when is_integer(N), N>0 -> N;
+ _ -> undefined
+ catch
+ error:badarg when ArgNum >= 0 -> ArgNum+1; % short ArgMap
+ error:badarg -> undefined
+ end.
+
+
+%%%----------------------------------------------------------------
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 499a4928de..2f91f7037a 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -988,22 +988,6 @@ expected_ec_size({{prime_field,_}, _, _, Order, _}) -> byte_size(Order);
expected_ec_size({{characteristic_two_field, _, _}, _, _, Order, _}) -> size(Order).
%%--------------------------------------------------------------------
-no_aead() ->
- [{doc, "Test disabled aead ciphers"}].
-no_aead(Config) when is_list(Config) ->
- EncArg4 =
- case lazy_eval(proplists:get_value(cipher, Config)) of
- [{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag, TagLen, _Info} | _] ->
- {AAD, PlainText, TagLen};
- [{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag, _Info} | _] ->
- {AAD, PlainText}
- end,
- EncryptArgs = [Type, Key, Nonce, EncArg4],
- DecryptArgs = [Type, Key, Nonce, {AAD, CipherText, CipherTag}],
- notsup(fun crypto:block_encrypt/4, EncryptArgs),
- notsup(fun crypto:block_decrypt/4, DecryptArgs).
-
-%%--------------------------------------------------------------------
no_aead_ng() ->
[{doc, "Test disabled aead ciphers"}].
no_aead_ng(Config) when is_list(Config) ->
diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl
index bac30ba51a..e75485f2bf 100644
--- a/lib/crypto/test/engine_SUITE.erl
+++ b/lib/crypto/test/engine_SUITE.erl
@@ -174,7 +174,7 @@ init_per_group(engine_fakes_rsa, Config) ->
#{link_type := static} ->
ct:log("~p:~p Statically linked",[?MODULE,?LINE]),
{skip, "Statically linked"};
- Info ->
+ _Info ->
%% Dynamically linked; use fake engine rsa implementation
group_load_engine(Config, [])
end;
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index 2fc0767a01..32dcb25544 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -725,14 +725,14 @@ pp_type(Type) ->
Form = {attribute, erl_anno:new(0), type, {t, Type, []}},
TypeDef = erl_pp:form(Form, [{quote_singleton_atom_types, true}]),
{match, [S]} = re:run(TypeDef, <<"::\\s*(.*)\\.\\n*">>,
- [{capture, all_but_first, list}, dotall]),
+ [{capture, all_but_first, list}, dotall, unicode]),
S.
pp_spec(Spec) ->
Form = {attribute, erl_anno:new(0), spec, {{a,b,0}, Spec}},
Sig = erl_pp:form(Form, [{quote_singleton_atom_types, true}]),
{match, [S]} = re:run(Sig, <<"-spec a:b\\s*(.*)\\.\\n*">>,
- [{capture, all_but_first, list}, dotall]),
+ [{capture, all_but_first, list}, dotall, unicode]),
S.
parse_types_and_literals(Src) ->
diff --git a/lib/dialyzer/test/dialyzer_common.erl b/lib/dialyzer/test/dialyzer_common.erl
index beaf126344..392c41306e 100644
--- a/lib/dialyzer/test/dialyzer_common.erl
+++ b/lib/dialyzer/test/dialyzer_common.erl
@@ -154,7 +154,7 @@ check(TestCase, Opts, Dir, OutDir) ->
_ ->
case file:open(NewResFile,[?output_file_mode]) of
{ok, OutFile} ->
- io:format(OutFile,"\n~s",[Warns]),
+ file:write(OutFile, [$\n, unicode:characters_to_binary(Warns)]),
file:close(OutFile);
Other -> erlang:error(Other)
end
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/unicode b/lib/dialyzer/test/opaque_SUITE_data/results/unicode
new file mode 100644
index 0000000000..9cdab6d60d
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/unicode
@@ -0,0 +1,2 @@
+
+exposer.erl:5:26: The call problematic:'🔍'('bug') does not have an opaque term of type problematic:'🐛'() as 1st argument
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/unicode/exposer.erl b/lib/dialyzer/test/opaque_SUITE_data/src/unicode/exposer.erl
new file mode 100644
index 0000000000..618f053532
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/unicode/exposer.erl
@@ -0,0 +1,5 @@
+-module(exposer).
+
+-export(['💣'/0]).
+
+'💣'() -> problematic:'🔍'(bug).
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/unicode/problematic.erl b/lib/dialyzer/test/opaque_SUITE_data/src/unicode/problematic.erl
new file mode 100644
index 0000000000..c841b1a511
--- /dev/null
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/unicode/problematic.erl
@@ -0,0 +1,9 @@
+-module(problematic).
+
+-opaque '🐛'() :: bug.
+-export_type(['🐛'/0]).
+
+-export(['🔍'/1]).
+
+-spec '🔍'('🐛'()) -> true.
+'🔍'(bug) -> true.
diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css
index 915782ec8c..7a45a3a4f7 100644
--- a/lib/erl_docgen/priv/css/otp_doc.css
+++ b/lib/erl_docgen/priv/css/otp_doc.css
@@ -1,24 +1,26 @@
/* standard OTP style sheet */
+/* We use three responsive breakpoints:
+ * 768px - mobile
+ * 992px - small screen
+ * 1200px - medium screen
+ * default - large screen
+*/
body {
- background: #fefefe;
- color: #1a1a1a;
- font-family: sans-serif;
- margin: 0;
- padding: 0;
- border: 0;
- overflow: scroll;
- height: 100%;
- max-height: 100%;
- line-height: 1.2em;
- font-size: 16px;
+ background: #fefefe;
+ color: #1a1a1a;
+ font-family: sans-serif;
+ margin: 0;
+ padding: 0;
+ border: 0;
+ max-height: 100%;
+ line-height: 1.2em;
+ font-size: 16px;
}
h1, h2, h3, h4, h5, h6{
- line-height: 1.2em;
+ line-height: 1.2em;
}
-p { max-width: 42em }
-
.header { background: #222; color: #fefefe }
.top { background: #efe }
.otp { background: #efe }
@@ -31,143 +33,310 @@ a:active { color: #1c7cd6; text-decoration: none }
a:visited { color: #1b6ec2; text-decoration: none }
#container {
- width: 100%;
- margin: 0;
- background-color: #fefefe;
+ display: grid;
+ grid-template-columns: 1fr 5fr;
+ grid-template-areas: "leftnav content";
}
#leftnav {
- position: fixed;
- float: left;
- top: 0;
- bottom: 0;
- left: 0;
- width: 300px;
- overflow:auto;
- margin: 0;
- padding: 1px;
- border-right: 1px solid #ccc;
+ grid-area: leftnav;
}
-.leftnav-tube
-{
- margin: 15px;
+.leftnav-tube {
+ top: 0;
+ margin-left: 15px;
+ position: sticky;
+ height: 100vh;
+ max-width: 250px;
+ overflow: auto;
+ border-right: 1px solid #ccc;
}
#content {
- margin-left: 340px; /* set left value to WidthOfFrameDiv */
- max-width: 52em;
- overflow-x: hidden;
+ grid-area: content;
+ max-width: 52em;
+ margin-left: 30px;
+}
+
+@media screen and (max-width: 1200px) {
+ #content {
+ margin-left: 0px;
+ }
+}
+
+@media screen and (max-width: 992px) {
+ #content {
+ max-width: 35em;
+ }
+}
+
+.topbar {
+ grid-area: topbar;
+ display: none;
+}
+
+@media screen and (max-width: 768px) {
+
+ #container {
+ grid-template-columns: 100%;
+ grid-template-areas:
+ "topbar"
+ "leftnav"
+ "content";
+ }
+
+ /* styling for the top bar */
+ .topbar {
+ display: flex;
+ position: relative;
+ top: 0px;
+ padding: 0.5em;
+ width: 100%;
+ box-sizing: border-box;
+ border-bottom: 1px solid #ccc;
+ box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.05),
+ inset 0 -1px 0 rgba(0,0,0,0.15);
+ text-align: center;
+ }
+ .topbar button {
+ padding: 1 6 1 6;
+ margin: 0;
+ height: auto;
+ display: inline-block;
+ border-radius: .25rem;
+ border: 1px solid transparent;
+ background: transparent;
+ }
+ .topbar-expand:not(.show) > button {
+ /* When we add the "show" class we rotate the button 180deg */
+ transform: rotate(180deg);
+ }
+ .topbar-expand > button {
+ transition: transform 0.35s ease;
+ }
+ .topbar-expand.show-permanent > button {
+ display: none;
+ }
+ .topbar-title {
+ text-align: center;
+ flex-grow: 2;
+ }
+ .topbar-title > h1 {
+ font-size: 1.17em;
+ margin: 0px;
+ }
+
+ /* Break words on mobile */
+ #content {
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ margin-left: 0px;
+ max-width: 100%;
+ }
+ p {
+ max-width: 100%;
+ }
+ /* The h1 is part of the topbar on mobile */
+ #content h1 {
+ display: none;
+ }
+
+ /* Styling of the navbar when shown/hidden */
+ #leftnav {
+ overflow: hidden;
+ }
+ #leftnav:not(.show) {
+ max-height: 0px;
+ border-bottom: 0px;
+ transition: max-height 0.35s ease;
+ }
+ #leftnav.show {
+ max-height: 60vh;
+ border-bottom: 1px solid #ccc;
+ box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.05),
+ inset 0 -1px 0 rgba(0,0,0,0.15);
+ transition: max-height 0.35s ease;
+ }
+
+ .leftnav-tube {
+ max-height: 60vh;
+ max-width: 100%;
+ position: unset;
+ border-right: 0px;
+ margin-right: 0px;
+ margin-left: 0px;
+ padding: 0px 15px 0px 15px;
+ }
+ #leftnav.show-permanent {
+ max-height: none;
+ }
+ .show-permanent > .leftnav-tube {
+ overflow: initial;
+ max-height: none;
+ height: inherit;
+ }
+ .hide-mobile {
+ opacity: 0;
+ }
+
+}
+
+@media (prefers-reduced-motion: reduce){
+ #leftnav.collapsing{
+ transition: none;
+ }
+ .topbar-expand > button {
+ transition: none;
+ }
+}
+
+.frontpage {
+ padding-top: 50px; /* Magins for inner DIV inside each DIV (to provide padding) */
+}
+
+.mobile-only {
+ display: none;
+}
+
+@media screen and (max-width: 768px) {
+ .mobile-only {
+ display: revert;
+ }
+}
+
+.innertube, .exports-tube {
+ margin-left: 15px;
+ margin-right: 15px;
+}
+
+@media screen and (max-width: 1200px) {
+ .innertube, .exports-tube {
+ margin-left: 0px;
+ margin-right: 15px;
+ }
+}
+
+@media screen and (max-width: 768px) {
+ .innertube, .exports-tube {
+ margin-left: 15px;
+ margin-right: 15px;
+ }
+}
+
+.footer {
+ margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
+ text-align: center;
}
-.frontpage
-{
- padding-top: 50px; /* Magins for inner DIV inside each DIV (to provide padding) */
-}
+.bold_code { font-family: mono, Courier, monospace; font-weight: bold }
-.innertube
-{
- margin-left: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
- margin-right: 11em;
+.title-link {
+ display: flex;
}
-.footer
-{
- margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
- text-align: center;
+.cref-head, .func-head, .data-type-name {
+ margin: 0 0 0 -4em;
+ padding-bottom: 0.2em;
+ padding-top: 0.2em;
}
-.bold_code { font-family: mono, Courier, monospace; font-weight: bold }
-
-/* Invisible table for function specs,
- * just to get since-version out in right margin */
-.func-table, .func-tr, .func-td, .cfunc-td, .func-since-td {
- width: 100%;
- border: 0;
- padding: 0;
+.cref-head h4, .func-head h4, .data-type-name h4 {
margin: 0;
}
-.func-tr:nth-child(n) {
- background: inherit /* turn off zebra striped rows */
-}
-
-.func-td {
- width: 38em;
+.cref-head:hover, .func-head:hover, .data-type-name:hover {
+ background-color: #f5f5f5;
}
-.cfunc-td {
- width: 31em;
+/* This small trick is in order to make all but the first line of the function
+ * head indented by 7em. So that it looks like this:
+ * int enif_alloc_binary(
+ * size_t size,
+ * ErlNifBinary* bin)
+ */
+.cref-head .title-name {
padding-left: 7em;
text-indent: -7em;
}
-.func-since-td {
- width: auto;
- padding-left: 1em;
+.title-since {
+ margin-left: auto;
}
-.func-td:hover {
- background-color: #f5f5f5;
+@media screen and (max-width: 768px) {
+ .cref-head, .func-head, .data-type-name {
+ margin-left: 0em;
+ padding-bottom: 0em;
+ padding-top: 0em;
+ }
+ .title-link {
+ flex-direction: column;
+ }
+ .title-anchors {
+ display: none;
+ }
+ .title-since {
+ margin-left: 1em;
+ }
}
.code {
- font-family: mono, Courier, monospace;
- font-weight: normal;
- background-color: #f3f3f3;
+ font-family: mono, Courier, monospace;
+ font-weight: normal;
+ background-color: #f3f3f3;
}
.note, .warning, .do, .dont {
- border: 1px solid #495057;
- margin: 1em 0;
+ border: 1px solid #495057;
+ margin: 1em 0;
}
.note .label {
- background-color: #2b8a3e;
- color: #fefefe;
- font-weight: bold;
- padding: 0.5em 1em;
+ background-color: #2b8a3e;
+ color: #fefefe;
+ font-weight: bold;
+ padding: 0.5em 1em;
}
.note .content {
- background: #f8f9fa;
- line-height: 120%;
- font-size: 0.9em;
- padding: 0.5em 1em;
+ background: #f8f9fa;
+ line-height: 120%;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.warning .label {
- background: #c92a2a;
- color: #fefefe;
- font-weight: bold;
- padding: 0.5em 1em;
+ background: #c92a2a;
+ color: #fefefe;
+ font-weight: bold;
+ padding: 0.5em 1em;
}
.warning .content {
- background-color: #f8f9fa;
- line-height: 120%;
- font-size: 0.9em;
- padding: 0.5em 1em;
+ background-color: #f8f9fa;
+ line-height: 120%;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.do .label {
- background-color: #2b8a3e;
- color: #fefefe;
- font-weight: bold;
- padding: 0.5em 1em;
+ background-color: #2b8a3e;
+ color: #fefefe;
+ font-weight: bold;
+ padding: 0.5em 1em;
}
.do .content {
- background: #f8f9fa;
- line-height: 120%;
- font-size: 0.9em;
- padding: 0.5em 1em;
+ background: #f8f9fa;
+ line-height: 120%;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.dont .label {
- background: #c92a2a;
- color: #fefefe;
- font-weight: bold;
- padding: 0.5em 1em;
+ background: #c92a2a;
+ color: #fefefe;
+ font-weight: bold;
+ padding: 0.5em 1em;
}
.dont .content {
- background-color: #f8f9fa;
- line-height: 120%;
- font-size: 0.9em;
- padding: 0.5em 1em;
+ background-color: #f8f9fa;
+ line-height: 120%;
+ font-size: 0.9em;
+ padding: 0.5em 1em;
}
.quote {
@@ -175,61 +344,70 @@ a:visited { color: #1b6ec2; text-decoration: none }
}
.example {
- background-color:#f1f3f5;
- border: 1px solid #dee2e6;
- padding: 0.5em 1em;
- margin: 1em 0;
- font-size: 0.7em;
+ background-color:#f1f3f5;
+ border: 1px solid #dee2e6;
+ padding: 0.5em 1em;
+ margin: 1em 0;
+ font-size: 0.7em;
+ overflow-x: auto;
+ max-width: min(100%, 48em);
}
.extrafrontpageinfo {
- color: #C00;
- font-weight: bold;
- font-size: 1.2em;
+ color: #C00;
+ font-weight: bold;
+ font-size: 1.2em;
}
pre {
- font-family: mono, Courier, monospace;
- font-weight: normal;
- margin: 0;
+ font-family: mono, Courier, monospace;
+ font-weight: normal;
+ margin: 0;
}
-.data-types-body, .REFBODY{
- margin-left: 2em;
+.data-types-body, .REFBODY {
+ margin-left: 2em;
}
.REFTYPES { margin-left: 1.5em }
.exports-body {
margin-left: 3em;
}
-.exports-tube
-{
- margin-right: 11em;
+
+@media screen and (max-width: 768px) {
+ .data-types-body, .REFBODY{
+ margin-left: 1em;
+ }
+ .REFTYPES { margin-left: 0.75em }
+ .exports-body {
+ margin-left: 1em;
+ }
}
footer { }
.erlang-logo-wrapper{
- text-align: center;
- margin-bottom: 1em;
+ text-align: center;
+ margin-top: 1em;
+ margin-bottom: 1em;
}
.main-title{
- text-align: center;
+ text-align: center;
}
.main-description{
- text-align: center;
- margin: 2em 0;
- font-size: 1.5em;
- line-height: 1.5em;
+ text-align: center;
+ margin: 2em 0;
+ font-size: 1.5em;
+ line-height: 1.5em;
}
.doc-table-wrapper, .doc-image-wrapper{
- width: 100%;
+ width: 100%;
}
.doc-image-wrapper{
- text-align: center;
+ text-align: center;
}
.doc-svg {
@@ -237,60 +415,60 @@ footer { }
}
.doc-table, .doc-image{
- min-width: 50%;
- margin: 0 auto;
- font-size: 0.7em;
+ min-width: 50%;
+ margin: 0 auto;
+ font-size: 0.7em;
}
.doc-table-caption, .doc-image-caption{
- margin-top: 1em;
- font-style: italic;
- text-align: center;
+ margin-top: 1em;
+ font-style: italic;
+ text-align: center;
}
table {
- border-collapse: collapse;
- min-width: 50%;
- margin: 1em;
+ border-collapse: collapse;
+ min-width: 50%;
+ margin: 1em;
}
table, th, td {
- border: 1px solid #666;
+ border: 1px solid #666;
}
th, td {
- padding: 0.5em;
- text-align: left;
+ padding: 0.5em;
+ text-align: left;
}
tr:hover {
- background-color: #f5f5f5;
+ background-color: #f5f5f5;
}
tr:nth-child(even) {
- background-color: #f2f2f2;
+ background-color: #f2f2f2;
}
th {
- background-color: #777;
- color: #fefefe;
+ background-color: #777;
+ color: #fefefe;
}
.section-title, .section-subtitle, .section-version{
- text-align: center;
- margin: 0;
+ text-align: center;
+ margin: 0;
}
.section-title{
- font-weight: bold;
+ font-weight: bold;
}
.section-version{
- font-size: small;
+ font-size: small;
}
.expand-collapse-items{
- font-size: small;
+ font-size: small;
}
.title_link {
@@ -299,7 +477,6 @@ th {
}
.ghlink-before {
- margin-left: -4em;
visibility: hidden;
}
@@ -340,24 +517,24 @@ th {
}
hr{
- border: 0;
- border-top: 1px solid #aaa;
+ border: 0;
+ border-top: 1px solid #aaa;
}
.section-links, .panel-sections, .expand-collapse-items{
- padding: 0 1em;
+ padding: 0 1em;
}
.section-links, .panel-sections{
- margin-top: 0;
+ margin-top: 0;
}
a > .code {
- color: #1862ab;
+ color: #1862ab;
}
.func-types-title{
- font-size: 1em;
+ font-size: 1em;
}
.since{
diff --git a/lib/erl_docgen/priv/js/flipmenu/Makefile b/lib/erl_docgen/priv/js/flipmenu/Makefile
index be0bed74fb..33cce4e6d6 100644
--- a/lib/erl_docgen/priv/js/flipmenu/Makefile
+++ b/lib/erl_docgen/priv/js/flipmenu/Makefile
@@ -76,7 +76,7 @@ release_spec: opt
release_html_spec: html
$(INSTALL_DIR) "$(RELEASE_PATH)/doc/js/flipmenu"
$(INSTALL_DATA) $(JS_FILES) $(GIF_FILES) "$(RELEASE_PATH)/doc/js/flipmenu"
- $(INSTALL_DATA) ../highlight.js ../highlight.pack.js "$(RELEASE_PATH)/doc/js/"
+ $(INSTALL_DATA) ../highlight.js ../highlight.pack.js ../topbar.js "$(RELEASE_PATH)/doc/js/"
release_docs_spec: $(DOC_TARGETS:%=release_%_spec)
diff --git a/lib/erl_docgen/priv/js/topbar.js b/lib/erl_docgen/priv/js/topbar.js
new file mode 100644
index 0000000000..ef36f09c8c
--- /dev/null
+++ b/lib/erl_docgen/priv/js/topbar.js
@@ -0,0 +1,16 @@
+
+function toggleDisplay() {
+ var leftnav=document.getElementById('leftnav');
+ var topbar=document.getElementsByClassName('topbar-expand')[0];
+ if (leftnav.classList.contains('show')) {
+ leftnav.classList.remove('show');
+ topbar.classList.remove('show');
+ setTimeout(() => {
+ leftnav.classList.add('hide-mobile');
+ }, 350);
+ } else {
+ leftnav.classList.add('show');
+ topbar.classList.add('show');
+ leftnav.classList.remove('hide-mobile');
+ }
+}
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index 655d1a61e8..730c5d1447 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -229,30 +229,22 @@
<xsl:variable name="curModule" select="ancestor::erlref/module"/>
<xsl:variable name="mfas"
select="key('mfa',
- concat($curModule,':',$name,'/',$arity))"/>
- <xsl:choose>
- <xsl:when test="generate-id($mfas[1]) != generate-id(.)">
- <!-- Avoid duplicated anchors. See also menu.funcs. -->
- </xsl:when>
- <xsl:otherwise>
- <a name="{$name}-{$arity}"></a>
- </xsl:otherwise>
- </xsl:choose>
+ concat($curModule,':',$name,'/',$arity))"/>
<!-- Insert an anchor for "anchor" attribute -->
<xsl:if test="string-length($anchor) > 0">
- <a name="{$anchor}"></a>
+ <a name="{$anchor}"></a>
</xsl:if>
<xsl:variable name="global_types" select="ancestor::erlref/datatypes"/>
<xsl:variable name="local_types"
select="../type[string-length(@name) > 0]"/>
- <xsl:apply-templates select="$spec/contract/clause/head">
- <xsl:with-param name="ghlink" select="ancestor-or-self::*[@ghlink]/@ghlink"/>
- <xsl:with-param name="local_types" select="$local_types"/>
- <xsl:with-param name="global_types" select="$global_types"/>
- <xsl:with-param name="since" select="$since"/>
- </xsl:apply-templates>
+ <xsl:apply-templates select="$spec/contract/clause/head">
+ <xsl:with-param name="ghlink" select="ancestor-or-self::*[@ghlink]/@ghlink"/>
+ <xsl:with-param name="local_types" select="$local_types"/>
+ <xsl:with-param name="global_types" select="$global_types"/>
+ <xsl:with-param name="since" select="$since"/>
+ </xsl:apply-templates>
</xsl:when>
</xsl:choose>
</xsl:template>
@@ -264,31 +256,51 @@
<xsl:param name="since"/>
<xsl:variable name="mfa" select="concat(concat(../../../name,'-'),../../../arity)"/>
<xsl:variable name="id" select="concat(concat($mfa,'-'),generate-id(.))"/>
- <table class="func-table">
- <tr class="func-tr">
- <td class="func-td">
- <div class="bold_code func-head"
- onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
- onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
- <xsl:call-template name="ghlink">
+ <h4 id="{$mfa}" class="bold_code title-link func-head"
+ onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
+ onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
+ <div class="title-anchors">
+ <xsl:call-template name="ghlink">
<xsl:with-param name="mfa" select="$mfa"/>
<xsl:with-param name="ghlink" select="$ghlink"/>
<xsl:with-param name="id" select="$id"/>
- </xsl:call-template>
- <xsl:apply-templates mode="local_type">
+ </xsl:call-template>
+ </div>
+ <xsl:variable name="name">
+ <xsl:apply-templates mode="local_type">
<xsl:with-param name="local_types" select="$local_types"/>
<xsl:with-param name="global_types" select="$global_types"/>
- </xsl:apply-templates>
- </div>
- </td>
- <td class="func-since-td">
+ </xsl:apply-templates>
+ </xsl:variable>
+ <!-- We do not include the erlang: prefix in what is selected by
+ .title-name. This is so that webcrawlers can select the true
+ function name, i.e. decode_packet instead of erlang:decode_packet.
+ -->
+ <xsl:variable name="head" select="exsl:node-set($name)/text()[1]"/>
+ <xsl:variable name="tail" select="exsl:node-set($name)/node()[position() > 1]"/>
+ <xsl:choose>
+ <xsl:when test="substring($head,1,7) = 'erlang:'">
+ <div>
+ <xsl:text>erlang:</xsl:text>
+ <span class="title-name">
+ <xsl:value-of select="substring-after($head,':')"/>
+ <xsl:copy-of select="$tail"/>
+ </span>
+ </div>
+ </xsl:when>
+ <xsl:otherwise>
+ <span class="title-name">
+ <xsl:copy-of select="$name"/>
+ </span>
+ </xsl:otherwise>
+ </xsl:choose>
<xsl:if test="string-length($since) > 0">
- <span class="since"><xsl:value-of select="$since"/>
- </span>
+ <div class="title-since">
+ <span class="since"><xsl:value-of select="$since"/>
+ </span>
+ </div>
</xsl:if>
- </td>
- </tr>
- </table>
+ </h4>
</xsl:template>
<!-- The *last* <name name="..." arity=".."/> -->
@@ -317,7 +329,7 @@
(there is no spec with more than one clause) -->
<xsl:if test="count($clause/guard) > 0 or count($type) > 0">
<div class="REFBODY fun-types">
- <h3 class="func-types-title">Types</h3>
+ <h3 id="types" class="func-types-title">Types</h3>
<xsl:choose>
<xsl:when test="$output_subtypes">
@@ -479,17 +491,15 @@
<!-- Datatype Title, is the really needed? not used by anything -->
<xsl:template match="datatype_title">
<xsl:variable name="title" select="."/>
- <h4>
- <xsl:call-template name="title_link">
- <xsl:with-param name="title"><xsl:apply-templates/></xsl:with-param>
- <xsl:with-param name="link" select="$title"/>
- </xsl:call-template>
- </h4>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title"><xsl:apply-templates/></xsl:with-param>
+ <xsl:with-param name="link" select="$title"/>
+ </xsl:call-template>
</xsl:template>
<!-- Datatype -->
<xsl:template match="datatype">
- <div class="data-types-body">
+ <article class="data-types-body">
<xsl:choose>
<xsl:when test="string-length(name/@name) > 0">
<xsl:variable name="apostrophe">'</xsl:variable>
@@ -509,15 +519,19 @@
<xsl:with-param name="by" select="$slash_encoded" />
</xsl:call-template>
</xsl:variable>
- <div class="data-type-name"
+ <h4 id="{$id}" class="title-link data-type-name"
onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
- <xsl:call-template name="ghlink">
- <xsl:with-param name="mfa" select="$id"/>
- <xsl:with-param name="id" select="$id"/>
- </xsl:call-template>
- <xsl:apply-templates select="name"/>
- </div>
+ <div class="title-anchors">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="mfa" select="$id"/>
+ <xsl:with-param name="id" select="$id"/>
+ </xsl:call-template>
+ </div>
+ <div class="title-name">
+ <xsl:apply-templates select="name"/>
+ </div>
+ </h4>
</xsl:when>
<xsl:otherwise>
<div class="data-type-name">
@@ -526,7 +540,7 @@
</xsl:otherwise>
</xsl:choose>
<div class="data-type-desc"><xsl:apply-templates select="desc"/></div>
- </div>
+ </article>
</xsl:template>
<!-- The "mode" attribute of apply has been used to separate the case
@@ -774,6 +788,8 @@
<xsl:param name="curModule"/>
<html>
<head>
+ <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
+ <meta charset="utf-8"></meta>
<xsl:choose>
<xsl:when test="string-length($stylesheet) > 0">
<link rel="stylesheet" href="{$topdocdir}/{$stylesheet}" type="text/css"/>
@@ -792,32 +808,18 @@
</xsl:choose>
</head>
<body>
-
<div id="container">
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
<script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script>
+ <script id="js3" type="text/javascript" src="{$topdocdir}/js/topbar.js"></script>
<script language="JavaScript" type="text/javascript">
<xsl:text disable-output-escaping="yes"><![CDATA[
<!--
- function getWinHeight() {
- var myHeight = 0;
- if( typeof( window.innerHeight ) == 'number' ) {
- //Non-IE
- myHeight = window.innerHeight;
- } else if( document.documentElement && ( document.documentElement.clientWidth ||
- document.documentElement.clientHeight ) ) {
- //IE 6+ in 'standards compliant mode'
- myHeight = document.documentElement.clientHeight;
- } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
- //IE 4 compatible
- myHeight = document.body.clientHeight;
- }
- return myHeight;
- }
-
function setscrollpos() {
- var objf=document.getElementById('loadscrollpos');
- document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2;
+ var objf = document.getElementById('loadscrollpos');
+ if (objf) {
+ document.getElementById("leftnav").firstChild.scrollTop = objf.offsetTop - 10;
+ }
}
function addEvent(obj, evType, fn){
@@ -834,8 +836,41 @@
addEvent(window, 'load', setscrollpos);
- //-->]]></xsl:text>
+ //-->
+]]></xsl:text>
</script>
+ <div class="topbar">
+ <xsl:variable name="show">
+ <xsl:if test="(local-name() = 'application') or (local-name() = 'part') or (local-name() = 'releasenotes')">
+ <!-- For index pages we want to always show the navbar for mobile -->
+ <xsl:text>show show-permanent</xsl:text>
+ </xsl:if>
+ </xsl:variable>
+ <div class="topbar-expand {$show}">
+ <button onclick="toggleDisplay();">
+ <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54" width="24" height="24">
+ <g>
+ <path style="fill:#000000;" d="M27,54c-0.552,0-1-0.448-1-1V8c0-0.552,0.448-1,1-1s1,0.448,1,1v45C28,53.552,27.552,54,27,54z"/>
+ <path style="fill:#000000;" d="M11,25c-0.256,0-0.512-0.098-0.707-0.293c-0.391-0.391-0.391-1.023,0-1.414l16-16
+ c0.391-0.391,1.023-0.391,1.414,0s0.391,1.023,0,1.414l-16,16C11.512,24.902,11.256,25,11,25z"/>
+ <path style="fill:#000000;" d="M43,25c-0.256,0-0.512-0.098-0.707-0.293l-16-16c-0.391-0.391-0.391-1.023,0-1.414
+ s1.023-0.391,1.414,0l16,16c0.391,0.391,0.391,1.023,0,1.414C43.512,24.902,43.256,25,43,25z"/>
+ <path style="fill:#000000;" d="M43,2H11c-0.552,0-1-0.448-1-1s0.448-1,1-1h32c0.552,0,1,0.448,1,1S43.552,2,43,2z"/>
+ </g>
+ </svg>
+ </button>
+ </div>
+ <div class="topbar-title">
+ <h1 id="{header/title}">
+ <xsl:if test="string-length($chapnum) > 0">
+ <xsl:value-of select="$chapnum"/>&#160;
+ </xsl:if>
+ <xsl:value-of select="header/title"/>
+ </h1>
+ </div>
+ <div class="search-expand {$show}">
+ </div>
+ </div>
<!-- Generate menu -->
<xsl:call-template name="menu">
<xsl:with-param name="chapnum" select="$chapnum"/>
@@ -913,10 +948,22 @@
<xsl:template name="menu">
<xsl:param name="chapnum"/>
<xsl:param name="curModule"/>
+ <xsl:variable name="show">
+ <xsl:choose>
+ <xsl:when test="(local-name() = 'application') or (local-name() = 'part') or (local-name() = 'releasenotes')">
+ <!-- For index pages we want to always show the navbar for mobile -->
+ <xsl:text>show show-permanent</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>hide-mobile</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
<xsl:if test="(local-name() = 'part') or ((local-name() = 'chapter') and ancestor::part)">
<!-- .../part or .../part/chapter -->
<xsl:call-template name="menu.ug">
<xsl:with-param name="chapnum" select="$chapnum"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:if>
@@ -930,12 +977,14 @@
<!-- .../internal or .../internal/chapter -->
<xsl:call-template name="menu.internal.ug">
<xsl:with-param name="chapnum" select="$chapnum"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="(local-name() = 'internal' and descendant::erlref) or (((local-name() = 'erlref') or (local-name() = 'comref') or (local-name() = 'cref') or (local-name() = 'fileref') or (local-name() = 'appref')) and ancestor::internal)">
<!-- .../internal,.../internal/erlref, .../internal/comref or .../internal/cref or .../internal/fileref or .../internal/appref -->
<xsl:call-template name="menu.internal.ref">
<xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
@@ -943,12 +992,14 @@
<!-- .../application,.../application/erlref, .../application/comref or .../application/cref or .../application/fileref or .../application/appref -->
<xsl:call-template name="menu.ref">
<xsl:with-param name="curModule" select="$curModule"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:if>
<xsl:if test="(local-name() = 'releasenotes') or ((local-name() = 'chapter') and ancestor::releasenotes)">
<!-- releasenotes -->
<xsl:call-template name="menu.rn">
<xsl:with-param name="chapnum" select="$chapnum"/>
+ <xsl:with-param name="show" select="$show"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
@@ -981,7 +1032,7 @@
<li><a href="internal_docs.html">Internal Documentation</a></li>
</xsl:if>
<xsl:if test="boolean(/book/releasenotes)">
- <li><a href="release_notes.html">Release Notes</a></li>
+ <li><a href="notes.html">Release Notes</a></li>
</xsl:if>
<xsl:choose>
<xsl:when test="string-length($pdfname) > 0">
@@ -1050,17 +1101,16 @@
<!-- Chapter/Section, subsection level 1-->
<xsl:template match="chapter/section">
<xsl:param name="chapnum"/>
- <h3>
- <xsl:for-each select="marker">
- <xsl:call-template name="marker-before-title"/>
- </xsl:for-each>
- <xsl:call-template name="title_link">
- <xsl:with-param name="title">
- <xsl:value-of select="$chapnum"/>.<xsl:number/>&#160;
- <xsl:value-of select="title"/>
- </xsl:with-param>
- </xsl:call-template>
- </h3>
+ <xsl:for-each select="marker">
+ <xsl:call-template name="marker-before-title"/>
+ </xsl:for-each>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title">
+ <xsl:value-of select="$chapnum"/>.<xsl:number/>&#160;
+ <xsl:value-of select="title"/>
+ </xsl:with-param>
+ <xsl:with-param name="header" select="'h3'"/>
+ </xsl:call-template>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
<xsl:with-param name="sectnum"><xsl:number/></xsl:with-param>
@@ -1071,17 +1121,15 @@
<xsl:template match="section/section">
<xsl:param name="chapnum"/>
<xsl:param name="sectnum"/>
- <h4>
- <xsl:for-each select="marker">
- <xsl:call-template name="marker-before-title"/>
- </xsl:for-each>
- <!-- xsl:value-of select="$partnum"/>.<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$sectnum"/>.<xsl:number/ -->
- <xsl:call-template name="title_link">
- <xsl:with-param name="title">
- <xsl:value-of select="title"/>
- </xsl:with-param>
- </xsl:call-template>
- </h4>
+ <xsl:for-each select="marker">
+ <xsl:call-template name="marker-before-title"/>
+ </xsl:for-each>
+ <!-- xsl:value-of select="$partnum"/>.<xsl:value-of select="$chapnum"/>.<xsl:value-of select="$sectnum"/>.<xsl:number/ -->
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title">
+ <xsl:value-of select="title"/>
+ </xsl:with-param>
+ </xsl:call-template>
<xsl:apply-templates>
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:apply-templates>
@@ -1106,8 +1154,7 @@
<!-- *ref/Section -->
<xsl:template match="erlref/section|cref/section|comref/section|fileref/section|appref/section|funcs/fsdescription">
<xsl:param name="chapnum"/>
- <div class="innertube">
- <h3>
+ <section class="innertube">
<xsl:for-each select="marker">
<xsl:call-template name="marker-before-title"/>
</xsl:for-each>
@@ -1115,28 +1162,30 @@
<xsl:with-param name="title">
<xsl:value-of select="title"/>
</xsl:with-param>
+ <xsl:with-param name="header" select="'h3'"/>
</xsl:call-template>
- </h3>
- <div class="REFBODY rb-3">
- <xsl:apply-templates>
- <xsl:with-param name="chapnum" select="$chapnum"/>
- </xsl:apply-templates>
- </div>
- </div>
+ <div class="REFBODY rb-3">
+ <xsl:apply-templates>
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:apply-templates>
+ </div>
+ </section>
</xsl:template>
<!-- *ref/Subsection -->
<xsl:template match="erlref/section/section|cref/section/section|comref/section/section|fileref/section/section|appref/section/section">
<xsl:param name="chapnum"/>
<xsl:param name="sectnum"/>
- <h4>
- <xsl:value-of select="title"/>
- </h4>
- <div class="REFBODY rb-4">
- <xsl:apply-templates>
- <xsl:with-param name="chapnum" select="$chapnum"/>
- </xsl:apply-templates>
- </div>
+ <section>
+ <h4 id="{title}">
+ <xsl:value-of select="title"/>
+ </h4>
+ <div class="REFBODY rb-4">
+ <xsl:apply-templates>
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:apply-templates>
+ </div>
+ </section>
</xsl:template>
@@ -1445,9 +1494,10 @@
<!-- Menu.internal.chapter -->
<xsl:template name="menu.internal.ug">
<xsl:param name="chapnum"/>
+ <xsl:param name="show"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -1459,7 +1509,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Chapters</h3>
+ <h3 id="chapters">Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -1467,15 +1517,17 @@
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
<!-- Menu.internal.ref -->
<xsl:template name="menu.internal.ref">
<xsl:param name="curModule"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <xsl:param name="show"/>
+
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -1487,7 +1539,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Table of Contents</h3>
+ <h3 id="toc">Table of Contents</h3>
<ul class="flipMenu">
<xsl:call-template name="menu.ref2">
@@ -1496,14 +1548,15 @@
<xsl:with-param name="curModule" select="$curModule"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
<!-- Menu.internal.chapter combined when we have both modules and free-form chapters -->
<xsl:template name="menu.internal.ug_ref">
- <div id="leftnav">
- <div class="leftnav-tube">
+ <xsl:param name="show"/>
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
<p class="section-title"><xsl:value-of select="/book/header/title"/></p>
@@ -1514,7 +1567,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Chapters</h3>
+ <h3 id="chapters">Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -1522,7 +1575,7 @@
</xsl:call-template>
</ul>
- <h3>Modules</h3>
+ <h3 id="modules">Modules</h3>
<ul class="flipMenu">
<xsl:call-template name="menu.ref2">
@@ -1530,8 +1583,8 @@
<!--xsl:with-param name="genFuncMenu" select="true"/-->
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
<!--Users Guide -->
@@ -1573,9 +1626,10 @@
<!-- Menu.ug -->
<xsl:template name="menu.ug">
<xsl:param name="chapnum"/>
+ <xsl:param name="show"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -1587,7 +1641,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Chapters</h3>
+ <h3 id="chapters">Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -1595,8 +1649,8 @@
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
@@ -1681,7 +1735,7 @@
<xsl:param name="chapnum"/>
<!-- center-->
- <h1>
+ <h1 id="{header/title}">
<xsl:value-of select="$chapnum"/>&#160;<xsl:value-of select="header/title"/>
</h1>
<!-- /center-->
@@ -1735,8 +1789,10 @@
<!-- Menu.ref -->
<xsl:template name="menu.ref">
<xsl:param name="curModule"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <xsl:param name="show"/>
+
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -1748,7 +1804,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Table of Contents</h3>
+ <h3 id="toc">Table of Contents</h3>
<ul class="flipMenu">
<xsl:call-template name="menu.ref2">
@@ -1757,8 +1813,8 @@
<xsl:with-param name="curModule" select="$curModule"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
@@ -2266,18 +2322,20 @@
<xsl:template match="description">
<xsl:param name="partnum"/>
- <div class="innertube">
- <xsl:call-template name="h3_title_link">
- <xsl:with-param name="title">Description</xsl:with-param>
- </xsl:call-template>
- <div class="REFBODY description-body">
- <p>
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </p>
- </div>
- </div>
+ <section class="description">
+ <div class="innertube">
+ <xsl:call-template name="h3_title_link">
+ <xsl:with-param name="title">Description</xsl:with-param>
+ </xsl:call-template>
+ <div class="REFBODY description-body">
+ <p>
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </p>
+ </div>
+ </div>
+ </section>
</xsl:template>
<!-- Funcs -->
@@ -2305,18 +2363,18 @@
<!-- Func -->
<xsl:template match="func">
<xsl:param name="partnum"/>
-
- <xsl:apply-templates select="name"/>
- <xsl:apply-templates
- select="name[string-length(@arity) > 0 and position()=last()]"
- mode="types"/>
-
- <div class="exports-tube">
- <xsl:apply-templates select="fsummary|type|desc">
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </div>
-
+ <article class="func">
+ <xsl:apply-templates select="name"/>
+ <xsl:apply-templates
+ select="name[string-length(@arity) > 0 and position()=last()]"
+ mode="types"/>
+
+ <div class="exports-tube">
+ <xsl:apply-templates select="fsummary|type|desc">
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
+ </div>
+ </article>
</xsl:template>
<xsl:template match="name">
@@ -2370,23 +2428,13 @@
<xsl:choose>
<xsl:when test="ancestor::cref">
- <table class="func-table">
- <tr class="func-tr">
- <td class="cfunc-td">
- <span class="bold_code bc-7">
- <xsl:call-template name="title_link">
- <xsl:with-param name="link" select="substring-before(nametext, '(')"/>
- <xsl:with-param name="where" select="'before'"/>
- </xsl:call-template>
- </span>
- </td>
- <td class="func-since-td">
- <xsl:if test="string-length(@since) > 0">
- <span class="since"><xsl:value-of select="@since"/></span>
- </xsl:if>
- </td>
- </tr>
- </table>
+ <div class="cref-head bold_code bc-7">
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="link" select="substring-before(nametext, '(')"/>
+ <xsl:with-param name="where" select="'before'"/>
+ <xsl:with-param name="since" select="@since"/>
+ </xsl:call-template>
+ </div>
</xsl:when>
<xsl:when test="ancestor::erlref">
<xsl:variable name="fname">
@@ -2418,26 +2466,16 @@
</div>
</xsl:when>
<xsl:otherwise>
- <table class="func-table">
- <tr class="func-tr">
- <td class="func-td">
- <div class="bold_code fun-type">
- <xsl:call-template name="title_link">
- <xsl:with-param name="link" select="concat(concat($fname,'-'),$arity)"/>
- <xsl:with-param name="where" select="'before'"/>
- <xsl:with-param name="title">
- <xsl:apply-templates/>
- </xsl:with-param>
- </xsl:call-template>
- </div>
- </td>
- <td class="func-since-td">
- <xsl:if test="string-length(@since) > 0">
- <span class="since"><xsl:value-of select="@since"/></span>
- </xsl:if>
- </td>
- </tr>
- </table>
+ <div class="bold_code func-head">
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="link" select="concat(concat($fname,'-'),$arity)"/>
+ <xsl:with-param name="where" select="'before'"/>
+ <xsl:with-param name="since" select="@since"/>
+ <xsl:with-param name="title">
+ <xsl:apply-templates/>
+ </xsl:with-param>
+ </xsl:call-template>
+ </div>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
@@ -2456,7 +2494,7 @@
<xsl:if test="string-length(@name) = 0 and string-length(@variable) = 0">
<div class="REFBODY rb-5">
- <h3 class="func-types-title">Types</h3>
+ <h3 id="types" class="func-types-title">Types</h3>
<xsl:apply-templates>
<xsl:with-param name="partnum" select="$partnum"/>
@@ -2492,33 +2530,43 @@
<xsl:template name="h3_title_link">
<xsl:param name="title"/>
- <h3>
- <xsl:call-template name="title_link">
- <xsl:with-param name="title" select="$title"/>
- <xsl:with-param name="link" select="erl:to-link($title)"/>
- </xsl:call-template>
- </h3>
+ <xsl:call-template name="title_link">
+ <xsl:with-param name="title" select="$title"/>
+ <xsl:with-param name="link" select="erl:to-link($title)"/>
+ </xsl:call-template>
</xsl:template>
<xsl:template name="title_link">
<xsl:param name="title" select="'APPLY'"/>
<xsl:param name="link" select="erl:to-link(title)"/>
<xsl:param name="where" select="'after'"/>
+ <xsl:param name="header" select="'h4'"/>
+ <xsl:param name="since"/>
<xsl:param name="ghlink" select="ancestor-or-self::*[@ghlink][position() = 1]/@ghlink"/>
<xsl:variable name="id" select="concat(concat($link,'-'), generate-id(.))"/>
- <span onMouseOver="document.getElementById('ghlink-{$id}').style.visibility = 'visible';"
- onMouseOut="document.getElementById('ghlink-{$id}').style.visibility = 'hidden';">
+
+ <xsl:element name="{$header}">
+ <xsl:attribute name="id"><xsl:value-of select="$link"/></xsl:attribute>
+ <xsl:attribute name="class">title-link</xsl:attribute>
+ <xsl:attribute name="onMouseOver">
+ <xsl:text>document.getElementById('ghlink-</xsl:text><xsl:value-of select="$id"/><xsl:text>').style.visibility = 'visible';</xsl:text>
+ </xsl:attribute>
+ <xsl:attribute name="onMouseOut">
+ <xsl:text>document.getElementById('ghlink-</xsl:text><xsl:value-of select="$id"/><xsl:text>').style.visibility = 'hidden';</xsl:text>
+ </xsl:attribute>
<xsl:choose>
<xsl:when test="$where = 'before'">
- <xsl:call-template name="ghlink">
- <xsl:with-param name="mfa" select="$link"/>
- <xsl:with-param name="id" select="$id"/>
- <xsl:with-param name="ghlink" select="$ghlink"/>
- <xsl:with-param name="where" select="$where"/>
- </xsl:call-template>
+ <div class="title-anchors">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="mfa" select="$link"/>
+ <xsl:with-param name="id" select="$id"/>
+ <xsl:with-param name="ghlink" select="$ghlink"/>
+ <xsl:with-param name="where" select="$where"/>
+ </xsl:call-template>
+ </div>
</xsl:when>
</xsl:choose>
- <a class="title_link" name="{$link}">
+ <div class="title-name">
<xsl:choose>
<xsl:when test="$title = 'APPLY'">
<xsl:apply-templates/> <!-- like <ret> and <nametext> -->
@@ -2527,18 +2575,26 @@
<xsl:copy-of select="$title"/>
</xsl:otherwise>
</xsl:choose>
- </a>
+ </div>
<xsl:choose>
<xsl:when test="$where = 'after'">
- <xsl:call-template name="ghlink">
- <xsl:with-param name="mfa" select="$link"/>
- <xsl:with-param name="id" select="$id"/>
- <xsl:with-param name="ghlink" select="$ghlink"/>
- <xsl:with-param name="where" select="$where"/>
- </xsl:call-template>
+ <div class="title-anchors">
+ <xsl:call-template name="ghlink">
+ <xsl:with-param name="mfa" select="$link"/>
+ <xsl:with-param name="id" select="$id"/>
+ <xsl:with-param name="ghlink" select="$ghlink"/>
+ <xsl:with-param name="where" select="$where"/>
+ </xsl:call-template>
+ </div>
</xsl:when>
</xsl:choose>
- </span>
+ <xsl:if test="string-length($since) > 0">
+ <div class="title-since">
+ <span class="since"><xsl:value-of select="$since"/>
+ </span>
+ </div>
+ </xsl:if>
+ </xsl:element>
</xsl:template>
<xsl:template name="ghlink">
@@ -2566,11 +2622,9 @@
<xsl:template match="desc">
<xsl:param name="partnum"/>
<div class="REFBODY rb-7">
- <p>
- <xsl:apply-templates>
- <xsl:with-param name="partnum" select="$partnum"/>
- </xsl:apply-templates>
- </p>
+ <xsl:apply-templates>
+ <xsl:with-param name="partnum" select="$partnum"/>
+ </xsl:apply-templates>
</div>
</xsl:template>
@@ -2784,9 +2838,10 @@
<!-- Menu.rn -->
<xsl:template name="menu.rn">
<xsl:param name="chapnum"/>
+ <xsl:param name="show"/>
- <div id="leftnav">
- <div class="leftnav-tube">
+ <aside class="{$show}" id="leftnav">
+ <nav class="leftnav-tube">
<xsl:call-template name="erlang_logo"/>
@@ -2798,7 +2853,7 @@
<xsl:call-template name="menu_middle"/>
- <h3>Chapters</h3>
+ <h3 id="chapters">Chapters</h3>
<ul class="flipMenu" imagepath="{$topdocdir}/js/flipmenu">
<xsl:call-template name="menu.chapter">
@@ -2806,8 +2861,8 @@
<xsl:with-param name="chapnum" select="$chapnum"/>
</xsl:call-template>
</ul>
- </div>
- </div>
+ </nav>
+ </aside>
</xsl:template>
<!-- Special templates to calculate the arity of functions -->
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
index 1c17004aa0..68d1984c7f 100644
--- a/lib/kernel/doc/src/logger.xml
+++ b/lib/kernel/doc/src/logger.xml
@@ -1189,6 +1189,18 @@ logger:set_proxy_config(maps:merge(Old, Config)).
</desc>
</func>
+ <func>
+ <name name="reconfigure" arity="0" since="OTP @OTP-17375@"/>
+ <fsummary>Reconfigure Logger.</fsummary>
+ <desc>
+ <p>Reconfigure Logger using updated <c>kernel</c> configuration
+ that was set after <c>kernel</c> application was loaded.</p>
+ <p>Beware, that this is meant to be run only by the build tools,
+ not manually during application lifetime, as this may cause
+ missing log entries.</p>
+ </desc>
+ </func>
+
</funcs>
diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl
index ea75c8d720..9107bf0e61 100644
--- a/lib/kernel/src/logger.erl
+++ b/lib/kernel/src/logger.erl
@@ -51,9 +51,9 @@
get_primary_config/0, get_handler_config/1,
get_handler_config/0, get_handler_ids/0, get_config/0,
get_proxy_config/0,
- add_handlers/1]).
+ add_handlers/1,
+ reconfigure/0]).
-%% Private configuration
-export([internal_init_logger/0]).
%% Misc
@@ -794,6 +794,31 @@ print_module_levels(Modules,M) ->
[print_module_levels(Module,M) || Module <- Modules],
ok.
+-spec reconfigure() -> ok | {error,term()}.
+%% This function is meant to be used by the build tools like Rebar3 or Mix
+%% to ensure that the logger configuration is reset to the expected state
+%% before running main application.
+reconfigure() ->
+ try
+ [case logger:remove_handler(Id) of
+ ok -> ok;
+ {error, Reason} -> throw({remove, Id, Reason})
+ end || #{id := Id} <- logger:get_handler_config()],
+ ok=logger:add_handler(simple,logger_simple_h,
+ #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS}),
+ logger:unset_module_level(),
+ internal_init_logger()
+ of
+ ok ->
+ logger:add_handlers(kernel);
+ Error ->
+ Error
+ catch
+ throw:Reason ->
+ {error, Reason}
+ end.
+
-spec internal_init_logger() -> ok | {error,term()}.
%% This function is responsible for config of the logger
%% This is done before add_handlers because we want the
@@ -807,6 +832,7 @@ internal_init_logger() ->
ok = logger:set_primary_config(metadata, get_primary_metadata()),
ok = logger:set_primary_config(filter_default,
get_primary_filter_default(Env)),
+ ok = logger:set_primary_config(filters, []),
[case logger:add_primary_filter(Id, Filter) of
ok -> ok;
diff --git a/lib/kernel/test/logger_SUITE.erl b/lib/kernel/test/logger_SUITE.erl
index 82533ab572..5545759b5d 100644
--- a/lib/kernel/test/logger_SUITE.erl
+++ b/lib/kernel/test/logger_SUITE.erl
@@ -24,6 +24,7 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/logger.hrl").
-include_lib("kernel/src/logger_internal.hrl").
+-include_lib("stdlib/include/assert.hrl").
-define(str,"Log from "++atom_to_list(?FUNCTION_NAME)++
":"++integer_to_list(?LINE)).
@@ -1009,15 +1010,14 @@ app_config(Config) ->
%% start, it is not possible to see code coverage in that test.
kernel_config(Config) ->
%% Start a node with simple handler only, then simulate kernel
- %% start by calling internally exported
- %% internal_init_logger(). This is to test all variants of kernel
- %% config, including bad config, and see the code coverage.
+ %% start by calling logger:reconfigure(). This is to test all
+ %% variants of kernel config, including bad config, and see
+ %% the code coverage.
{ok,#{handlers:=[#{id:=simple,filters:=DF}]}=LC,Node} =
logger_test_lib:setup(Config,[{error_logger,false}]),
%% Same once more, to get coverage
ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
LC = rpc:call(Node,logger,get_config,[]),
%% This shall mean the same as above, but using 'logger' parameter
@@ -1025,15 +1025,13 @@ kernel_config(Config) ->
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{handler,default,undefined}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
- LC = rpc:call(Node,logger,get_config,[]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
+ ?assertEqual(LC, rpc:call(Node,logger,get_config,[])),
%% Silent
ok = rpc:call(Node,application,unset_env,[kernel,logger]),
ok = rpc:call(Node,application,set_env,[kernel,error_logger,silent]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
@@ -1041,30 +1039,25 @@ kernel_config(Config) ->
%% Default
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,unset_env,[kernel,logger]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,config:=#{type:=standard_io}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% error_logger=tty (same as default)
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,set_env,[kernel,error_logger,tty]),
ok = rpc:call(Node,application,unset_env,[kernel,logger]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,config:=#{type:=standard_io}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% error_logger={file,File}
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
F = filename:join(?config(priv_dir,Config),
atom_to_list(?FUNCTION_NAME)++".log"),
ok = rpc:call(Node,application,set_env,[kernel,error_logger,{file,F}]),
ok = rpc:call(Node,application,unset_env,[kernel,logger]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,
config:=#{type:=file,file:=F,modes:=Modes}}],
@@ -1073,55 +1066,47 @@ kernel_config(Config) ->
%% Same, but using 'logger' parameter instead of 'error_logger'
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,[kernel,logger,
[{handler,default,logger_std_h,
#{config=>#{type=>{file,F}}}}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,
config:=#{type:=file,file:=F,modes:=Modes}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% Same, but with type={file,File,Modes}
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
M = [raw,write],
ok = rpc:call(Node,application,set_env,[kernel,logger,
[{handler,default,logger_std_h,
#{config=>#{type=>{file,F,M}}}}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,
config:=#{type:=file,file:=F,modes:=[delayed_write|M]}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% Same, but with disk_log handler
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,[kernel,logger,
[{handler,default,logger_disk_log_h,
#{config=>#{file=>F}}}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=log,filters:=[]},
handlers:=[#{id:=default,filters:=DF,config:=#{file:=F}}],
module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
%% Set primary filters and module level. No default handler.
- ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{handler,default,undefined},
{filters,stop,[{f1,{fun(_,_) -> log end,ok}}]},
{module_level,debug,[?MODULE]}]]),
- ok = rpc:call(Node,logger,internal_init_logger,[]),
- ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ ok = rpc:call(Node,logger,reconfigure,[]),
#{primary:=#{filter_default:=stop,filters:=[_]},
- handlers:=[],
+ handlers:=[#{id:=simple}],
module_levels:=[{?MODULE,debug}]} = rpc:call(Node,logger,get_config,[]),
%% Bad config
@@ -1129,38 +1114,38 @@ kernel_config(Config) ->
ok = rpc:call(Node,application,set_env,[kernel,error_logger,bad]),
{error,{bad_config,{kernel,{error_logger,bad}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
ok = rpc:call(Node,application,set_env,[kernel,logger_level,bad]),
{error,{bad_config,{kernel,{logger_level,bad}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,unset_env,[kernel,logger_level]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{filters,stop,[bad]}]]),
{error,{bad_config,{kernel,{invalid_filters,[bad]}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{filters,stop,[bad]}]]),
{error,{bad_config,{kernel,{invalid_filters,[bad]}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{filters,stop,[{f1,bad}]}]]),
{error,{bad_config,{kernel,{invalid_filter,{f1,bad}}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,MF=[{filters,stop,[]},{filters,log,[]}]]),
{error,{bad_config,{kernel,{multiple_filters,MF}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok = rpc:call(Node,application,set_env,
[kernel,logger,[{module_level,bad,[?MODULE]}]]),
{error,{bad_config,{kernel,{invalid_level,bad}}}} =
- rpc:call(Node,logger,internal_init_logger,[]),
+ rpc:call(Node,logger,reconfigure,[]),
ok.
diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml
index f39d64b6ab..7fe31c08d8 100644
--- a/lib/mnesia/doc/src/mnesia.xml
+++ b/lib/mnesia/doc/src/mnesia.xml
@@ -1464,14 +1464,6 @@ mnesia:create_table(person,
</desc>
</func>
<func>
- <name name="install_fallback" arity="1" since=""/>
- <fsummary>Installs a backup as fallback.</fsummary>
- <desc>
- <p>Calls <c>mnesia:install_fallback(Opaque, Args)</c>, where
- <c>Args</c> is <c>[{scope, global}, {module, BackupMod}]</c>.</p>
- </desc>
- </func>
- <func>
<name name="install_fallback" arity="2" since=""/>
<fsummary>Installs a backup as fallback.</fsummary>
<desc>
@@ -2645,8 +2637,8 @@ mnesia:create_table(employee,
add_family({family, F, M, Children}) ->
ChildOids = lists:map(fun oid/1, Children),
Trans = fun() ->
- mnesia:write(F#person{children = ChildOids},
- mnesia:write(M#person{children = ChildOids},
+ mnesia:write(F#person{children = ChildOids}),
+ mnesia:write(M#person{children = ChildOids}),
Write = fun(Child) -> mnesia:write(Child) end,
lists:foreach(Write, Children)
end,
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index b7e7f98499..b0b4ac023f 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -180,7 +180,7 @@ do_get_disc_copy2(Tab, Reason, Storage = {ext, Alias, Mod}, _Type) ->
%%
%% Grab read lock on table
%% Block dirty updates
-%% Update wherabouts
+%% Update whereabouts
%%
%% Cancel the update subscription
%% Process the subscription events
diff --git a/lib/snmp/src/app/snmp_app.erl b/lib/snmp/src/app/snmp_app.erl
index dbc1ec0b6d..486b276383 100644
--- a/lib/snmp/src/app/snmp_app.erl
+++ b/lib/snmp/src/app/snmp_app.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2021. 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.
@@ -155,7 +155,7 @@ stop() ->
get_env() ->
Env = application:get_all_env(snmp),
- DeleteElem = [included_applications],
+ DeleteElem = [included_applications, test_inet_backends],
F = fun({Key, _}) -> lists:member(Key, DeleteElem) end,
lists:dropwhile(F, Env).
diff --git a/lib/ssl/doc/src/standards_compliance.xml b/lib/ssl/doc/src/standards_compliance.xml
index cc74067ecf..3673372fdc 100644
--- a/lib/ssl/doc/src/standards_compliance.xml
+++ b/lib/ssl/doc/src/standards_compliance.xml
@@ -166,7 +166,7 @@
</cell>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>@OTP-16590@</em></cell>
+ <cell align="left" valign="middle"><em>24.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -178,7 +178,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">RSASSA-PSS signature schemes</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>@OTP-16590@</em></cell>
+ <cell align="left" valign="middle"><em>24.1</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
@@ -190,7 +190,7 @@
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle">signature_algorithms_cert extension</cell>
<cell align="left" valign="middle"><em>C</em></cell>
- <cell align="left" valign="middle"><em>@OTP-16590@</em></cell>
+ <cell align="left" valign="middle"><em>24.1</em></cell>
</row>
<row>
diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml
index fae2ca80e7..257f260d31 100644
--- a/lib/ssl/doc/src/using_ssl.xml
+++ b/lib/ssl/doc/src/using_ssl.xml
@@ -169,7 +169,7 @@ ok</code>
</code>
<p>In OTP 20 it is desirable to remove all cipher suites
- that uses rsa kexchange (removed from default in 21) </p>
+ that uses rsa key exchange (removed from default in 21) </p>
<code type="erl">2> NoRSA =
ssl:filter_cipher_suites(Default,
[{key_exchange, fun(rsa) -> false;
@@ -354,7 +354,7 @@ ok
<p>Step 3 - Explicit Session Reuse </p>
<code type="erl">
-%% Preform a full handshake and the session will not be saved for reuse
+%% Perform a full handshake and the session will not be saved for reuse
12&gt; {ok, C9} = ssl:connect("localhost", 9999, [{verify, verify_peer},
{versions, ['tlsv1.2']},
{cacertfile, "cacerts.pem"},
@@ -433,7 +433,7 @@ ok
<seeguide marker="ssl:using_ssl#anti-replay-protection-in-tls-1.3">
Anti-Replay Protection in TLS 1.3</seeguide>
</p>
- <p>Session tickets are sent by servers on newly estalished TLS connections.
+ <p>Session tickets are sent by servers on newly established TLS connections.
The number of tickets sent and their lifetime are configurable by application variables. See also
<seeapp marker="ssl:ssl_app#configuration"> SSL's configuration</seeapp>.</p>
<p>Session tickets are protected by application traffic keys, and in stateless
diff --git a/lib/ssl/test/tls_api_SUITE.erl b/lib/ssl/test/tls_api_SUITE.erl
index 229ba5c19d..453ccf12ee 100644
--- a/lib/ssl/test/tls_api_SUITE.erl
+++ b/lib/ssl/test/tls_api_SUITE.erl
@@ -180,6 +180,7 @@ init_per_testcase(_, Config) ->
Config.
end_per_testcase(_TestCase, Config) ->
Config.
+
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/stdlib/src/shell_docs.erl b/lib/stdlib/src/shell_docs.erl
index 5aaeedde52..f4be20e26c 100644
--- a/lib/stdlib/src/shell_docs.erl
+++ b/lib/stdlib/src/shell_docs.erl
@@ -590,6 +590,8 @@ normalize_format(Docs, #docs_v1{ format = <<"text/", _/binary>> }) when is_binar
%%% Functions for rendering reference documentation
render_function([], _D, _Config) ->
{error,function_missing};
+render_function(FDocs, D, Config) when is_map(Config) ->
+ render_function(FDocs, D, init_config(D, Config));
render_function(FDocs, #docs_v1{ docs = Docs } = D, Config) ->
Grouping =
lists:foldl(
@@ -602,7 +604,7 @@ render_function(FDocs, #docs_v1{ docs = Docs } = D, Config) ->
end, #{}, lists:sort(FDocs)),
lists:map(
fun({Group,Members}) ->
- Signatures = lists:flatmap(fun render_signature/1,lists:reverse(Members)),
+ Signatures = lists:flatmap(fun render_signature/1, lists:reverse(Members)),
case lists:search(fun({_,_,_,Doc,_}) ->
Doc =/= #{}
end, Members) of
@@ -625,7 +627,7 @@ render_function(FDocs, #docs_v1{ docs = Docs } = D, Config) ->
render_signature({{_Type,_F,_A},_Anno,_Sigs,_Docs,#{ signature := Specs } = Meta}) ->
lists:flatmap(
fun(ASTSpec) ->
- PPSpec = erl_pp:attribute(ASTSpec,[{encoding,utf8}]),
+ PPSpec = erl_pp:attribute(ASTSpec,[{encoding,unicode}]),
Spec =
case ASTSpec of
{_Attribute, _Line, opaque, _} ->
@@ -672,6 +674,8 @@ render_headers_and_docs(Headers, DocContents, #config{} = Config) ->
render_docs(DocContents, 2, Config)].
%%% Functions for rendering type/callback documentation
+render_signature_listing(Module, Type, D, Config) when is_map(Config) ->
+ render_signature_listing(Module, Type, D, init_config(D, Config));
render_signature_listing(Module, Type, #docs_v1{ docs = Docs } = D, Config) ->
Slogan = [{h2,[],[<<"\t",(atom_to_binary(Module))/binary>>]},{br,[],[]}],
case lists:filter(fun({{T, _, _},_Anno,_Sig,_Doc,_Meta}) ->
@@ -705,7 +709,7 @@ render_typecb_docs(Docs, D, Config) ->
%%% General rendering functions
render_docs(DocContents, #config{} = Config) ->
render_docs(DocContents, 0, Config).
-render_docs(DocContents, D, Config) when is_map(Config) ->
+render_docs(DocContents, D, Config) when is_record(D, docs_v1) ->
render_docs(DocContents, 0, init_config(D, Config));
render_docs(DocContents, Ind, D = #config{}) when is_integer(Ind) ->
init_ansi(D),
@@ -716,7 +720,7 @@ render_docs(DocContents, Ind, D = #config{}) when is_integer(Ind) ->
clean_ansi()
end.
-init_config(D, Config) ->
+init_config(D, Config) when is_map(Config) ->
DefaultOpts = io:getopts(),
DefaultEncoding = proplists:get_value(encoding, DefaultOpts, latin1),
Columns =
@@ -735,7 +739,9 @@ init_config(D, Config) ->
encoding = maps:get(encoding, Config, DefaultEncoding),
ansi = maps:get(ansi, Config, undefined),
columns = Columns
- }.
+ };
+init_config(D, Config) ->
+ Config#config{ docs = D }.
render_docs(Elems,State,Pos,Ind,D) when is_list(Elems) ->
lists:mapfoldl(fun(Elem,P) ->
@@ -873,13 +879,13 @@ render_element({dt,_,Content},[dl | _] = State,Pos,Ind,D) ->
render_element({dd,_,Content},[dl | _] = State,Pos,Ind,D) ->
trimnlnl(render_docs(Content, [li | State], Pos, Ind + 2, D));
-render_element(B, State, Pos, Ind,#config{ columns = Cols }) when is_binary(B) ->
+render_element(B, State, Pos, Ind, D) when is_binary(B) ->
case lists:member(pre,State) of
true ->
Pre = string:replace(B,"\n",[nlpad(Ind)],all),
{Pre, Pos + lastline(Pre)};
_ ->
- render_words(split_to_words(B),State,Pos,Ind,[[]],Cols)
+ render_words(split_to_words(B),State,Pos,Ind,[[]],D)
end;
render_element({Tag,Attr,Content}, State, Pos, Ind,D) ->
@@ -892,33 +898,42 @@ render_element({Tag,Attr,Content}, State, Pos, Ind,D) ->
end,
render_docs(Content, State, Pos, Ind,D).
-render_words(Words,[_,types|State],Pos,Ind,Acc,Cols) ->
+render_words(Words,[_,types|State],Pos,Ind,Acc,D) ->
%% When we render words and are in the types->type state we indent
%% the extra lines two additional spaces to make it look nice
- render_words(Words,State,Pos,Ind+2,Acc,Cols);
-render_words([Word|T],State,Pos,Ind,Acc,Cols) when is_binary(Word) ->
+ render_words(Words,State,Pos,Ind+2,Acc,D);
+render_words([UnicodeWord|T],State,Pos,Ind,Acc,#config{ columns = Cols } = D)
+ when is_binary(UnicodeWord) ->
+ Word = translate(UnicodeWord, D),
WordLength = string:length(Word),
NewPos = WordLength + Pos,
%% We do not want to add a newline if this word is only a punctuation
- IsPunct = is_tuple(re:run(Word,"^\\W$",[unicode])),
+ IsPunct = re:run(Word,"^\\W$",[unicode]) =/= nomatch,
+
if
NewPos > (Cols - 10 - Ind), Word =/= <<>>, not IsPunct ->
%% Word does not fit, time to add a newline and also pad to Indent level
- render_words(T,State,WordLength+Ind+1,Ind,[[[nlpad(Ind), Word]]|Acc],Cols);
+ render_words(T,State,WordLength+Ind+1,Ind,[[[nlpad(Ind), Word]]|Acc],D);
true ->
%% Word does fit on line
[Line | LineAcc] = Acc,
%% Add + 1 to length for space
NewPosSpc = NewPos+1,
- render_words(T,State,NewPosSpc,Ind,[[Word|Line]|LineAcc],Cols)
+ render_words(T,State,NewPosSpc,Ind,[[Word|Line]|LineAcc],D)
end;
-render_words([],_State,Pos,_Ind,Acc,_Cols) ->
+render_words([],_State,Pos,_Ind,Acc,_D) ->
Lines = lists:map(fun(RevLine) ->
Line = lists:reverse(RevLine),
lists:join($ ,Line)
end,lists:reverse(Acc)),
{iolist_to_binary(Lines), Pos}.
+%% If the encoding is not unicode, we translate all nbsp to sp
+translate(UnicodeWord, #config{ encoding = unicode }) ->
+ UnicodeWord;
+translate(UnicodeWord, #config{ encoding = latin1 }) ->
+ string:replace(UnicodeWord, [160], " ", all).
+
render_type_signature(Name, #config{ docs = #docs_v1{ metadata = #{ types := AllTypes }}}) ->
case [Type || Type = {TName,_} <- maps:keys(AllTypes), TName =:= Name] of
[] ->
diff --git a/lib/stdlib/test/shell_docs_SUITE.erl b/lib/stdlib/test/shell_docs_SUITE.erl
index 06a564620e..4f83fb7047 100644
--- a/lib/stdlib/test/shell_docs_SUITE.erl
+++ b/lib/stdlib/test/shell_docs_SUITE.erl
@@ -118,29 +118,34 @@ render_smoke(_Config) ->
lists:foreach(
fun(Config) ->
try
- shell_docs:render(Mod, D, Config),
- shell_docs:render_type(Mod, D, Config),
- shell_docs:render_callback(Mod, D, Config),
+ E = fun({error,_}) ->
+ ok;
+ (Doc) ->
+ unicode:characters_to_binary(Doc)
+ end,
+ E(shell_docs:render(Mod, D, Config)),
+ E(shell_docs:render_type(Mod, D, Config)),
+ E(shell_docs:render_callback(Mod, D, Config)),
Exports = try Mod:module_info(exports)
catch _:undef -> []
end, %% nif file not available on this platform
[try
- shell_docs:render(Mod, F, A, D, Config)
+ E(shell_docs:render(Mod, F, A, D, Config))
catch _E:R:ST ->
io:format("Failed to render ~p:~p/~p~n~p:~p~n~p~n",
[Mod,F,A,R,ST,shell_docs:get_doc(Mod,F,A)]),
erlang:raise(error,R,ST)
end || {F,A} <- Exports],
[try
- shell_docs:render_type(Mod, T, A, D, Config)
+ E(shell_docs:render_type(Mod, T, A, D, Config))
catch _E:R:ST ->
io:format("Failed to render type ~p:~p/~p~n~p:~p~n~p~n",
[Mod,T,A,R,ST,shell_docs:get_type_doc(Mod,T,A)]),
erlang:raise(error,R,ST)
end || {{type,T,A},_,_,_,_} <- Docs],
[try
- shell_docs:render_callback(Mod, T, A, D, Config)
+ E(shell_docs:render_callback(Mod, T, A, D, Config))
catch _E:R:ST ->
io:format("Failed to render callback ~p:~p/~p~n~p:~p~n~p~n",
[Mod,T,A,R,ST,shell_docs:get_callback_doc(Mod,T,A)]),
@@ -155,8 +160,8 @@ render_smoke(_Config) ->
#{ ansi => true },
#{ columns => 5 },
#{ columns => 150 },
- #{ encoding => unicode},
- #{ encoding => latin1}])
+ #{ encoding => unicode },
+ #{ encoding => latin1 }])
end),
ok.
diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk
index a2ba51c9cf..f525368d7a 100644
--- a/make/otp_release_targets.mk
+++ b/make/otp_release_targets.mk
@@ -187,11 +187,15 @@ local_docs: local_copy_of_topdefs docs
local_html: TOPDOCDIR=.
local_html: local_copy_of_topdefs html
-local_copy_of_topdefs:
- $(INSTALL) $(DOCGEN)/priv/css/otp_doc.css $(HTMLDIR)
+$(HTMLDIR)/otp_doc.css:
+ ln -s $(DOCGEN)/priv/css/otp_doc.css $(HTMLDIR)/otp_doc.css
+
+local_copy_of_topdefs: $(HTMLDIR)/otp_doc.css
+ cd $(ERL_TOP) && make mod2app
$(INSTALL) $(DOCGEN)/priv/images/erlang-logo.png $(HTMLDIR)
$(INSTALL) $(DOCGEN)/priv/images/erlang-logo.gif $(HTMLDIR)
$(INSTALL_DIR) $(HTMLDIR)/js/flipmenu
+ $(INSTALL) $(DOCGEN)/priv/js/*.js $(HTMLDIR)/js
$(INSTALL) $(DOCGEN)/priv/js/flipmenu/flip_closed.gif \
$(DOCGEN)/priv/js/flipmenu/flip_open.gif \
$(DOCGEN)/priv/js/flipmenu/flip_static.gif \
diff --git a/make/otp_version_tickets b/make/otp_version_tickets
index 553ca835d2..b8220e1a87 100644
--- a/make/otp_version_tickets
+++ b/make/otp_version_tickets
@@ -1,8 +1 @@
-OTP-17393
-OTP-17657
-OTP-17658
-OTP-17659
-OTP-17666
-OTP-17668
-OTP-17670
-OTP-17672
+DEVELOPMENT
diff --git a/make/otp_version_tickets_in_merge b/make/otp_version_tickets_in_merge
index e69de29bb2..553ca835d2 100644
--- a/make/otp_version_tickets_in_merge
+++ b/make/otp_version_tickets_in_merge
@@ -0,0 +1,8 @@
+OTP-17393
+OTP-17657
+OTP-17658
+OTP-17659
+OTP-17666
+OTP-17668
+OTP-17670
+OTP-17672
diff --git a/scripts/otp_html_check b/scripts/otp_html_check
index 893d2b55f1..3606ed22d4 100755
--- a/scripts/otp_html_check
+++ b/scripts/otp_html_check
@@ -226,7 +226,7 @@ sub get_page_links {
($html =~ m/
<
\s*
- A
+ (?: A|H[1-6])
[^>]*
\s (?: NAME|ID) \s* = \s*
(?: \"([^\"]*)\" | \'([^\']*)\' | ([^>\s]+) )
diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile
index 3ebee96c08..803f907994 100644
--- a/system/doc/top/Makefile
+++ b/system/doc/top/Makefile
@@ -260,9 +260,9 @@ $(TOP_PDF_FILE): $(XML_FILES)
pdf: $(TOP_PDF_FILE)
-html: $(INDEX_FILES) $(JAVASCRIPT)
+html: $(INDEX_FILES) $(JAVASCRIPT) $(MAN_INDEX)
-man: $(MAN_INDEX)
+man:
debug opt:
@@ -287,10 +287,10 @@ $(RELSYSDIR)/docbuild:
$(INSTALL_DIR) $(RELSYSDIR)/docbuild
release_man_spec: man $(RELSYSDIR)/docbuild
- $(INSTALL_DATA) $(MAN_INDEX) $(RELSYSDIR)
- $(INSTALL_DATA) $(MAN_INDEX_SRC) $(MAN_INDEX_SCRIPT) $(RELSYSDIR)/docbuild
release_html_spec: html $(RELSYSDIR)/docbuild
+ $(INSTALL_DATA) $(MAN_INDEX) $(RELSYSDIR)
+ $(INSTALL_DATA) $(MAN_INDEX_SRC) $(MAN_INDEX_SCRIPT) $(RELSYSDIR)/docbuild
$(INSTALL_DIR) $(RELSYSDIR)/js
$(INSTALL_DATA) $(JAVASCRIPT) $(RELSYSDIR)/js
$(INSTALL_DATA) $(INDEX_FILES) $(RELSYSDIR)
diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src
index ec53a5b3c5..0c899efe0c 100644
--- a/system/doc/top/templates/index.html.src
+++ b/system/doc/top/templates/index.html.src
@@ -20,20 +20,45 @@ limitations under the License.
-->
<html>
-<head>
+ <head>
+ <meta name="viewport" content="width=device-width, initial-scale=1"></meta>
+ <meta charset="utf-8"></meta>
<link rel="stylesheet" href="otp_doc.css" type="text/css"/>
<title>Erlang/OTP #otp_base_vsn#</title>
<script id="js" type="text/javascript" language="JavaScript" src="js/flipmenu/flipmenu.js">
-
+</script>
+<script id="js2" type="text/javascript" language="JavaScript" src="js/topbar.js">
</script>
</head>
<body>
-
-<div id="container">
-<div id="leftnav">
-<div class="leftnav-tube">
+ <div id="container">
+ <div class="topbar">
+ <div class="topbar-expand">
+ <button onclick="toggleDisplay();">
+ <svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54" width="24" height="24">
+<g>
+ <path style="fill:#000000;" d="M27,54c-0.552,0-1-0.448-1-1V8c0-0.552,0.448-1,1-1s1,0.448,1,1v45C28,53.552,27.552,54,27,54z"/>
+ <path style="fill:#000000;" d="M11,25c-0.256,0-0.512-0.098-0.707-0.293c-0.391-0.391-0.391-1.023,0-1.414l16-16
+ c0.391-0.391,1.023-0.391,1.414,0s0.391,1.023,0,1.414l-16,16C11.512,24.902,11.256,25,11,25z"/>
+ <path style="fill:#000000;" d="M43,25c-0.256,0-0.512-0.098-0.707-0.293l-16-16c-0.391-0.391-0.391-1.023,0-1.414
+ s1.023-0.391,1.414,0l16,16c0.391,0.391,0.391,1.023,0,1.414C43.512,24.902,43.256,25,43,25z"/>
+ <path style="fill:#000000;" d="M43,2H11c-0.552,0-1-0.448-1-1s0.448-1,1-1h32c0.552,0,1,0.448,1,1S43.552,2,43,2z"/>
+</g>
+ </svg>
+ </button>
+ </div>
+ <div class="topbar-title">
+ <h1>
+ Erlang/OTP #otp_base_vsn#
+ </h1>
+ </div>
+ <div class="search-expand">
+ </div>
+ </div>
+<aside id="leftnav">
+<nav class="leftnav-tube">
<div class="erlang-logo-wrapper">
<img alt="Erlang logo" src="erlang-logo.png" class="erlang-logo"/ >
</div>
@@ -78,8 +103,8 @@ limitations under the License.
#applinks#
</ul>
-</div>
-</div>
+</nav>
+</aside>
<div id="content">
@@ -92,7 +117,18 @@ limitations under the License.
<h2>Some hints that may get you started faster</h2>
<ul>
-
+ <li class="mobile-only">
+ The navigation menu can be accessed by clicking the <svg style="transform: rotate(180deg);" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 54 54" width="24" height="24">
+<g>
+ <path style="fill:#000000;" d="M27,54c-0.552,0-1-0.448-1-1V8c0-0.552,0.448-1,1-1s1,0.448,1,1v45C28,53.552,27.552,54,27,54z"/>
+ <path style="fill:#000000;" d="M11,25c-0.256,0-0.512-0.098-0.707-0.293c-0.391-0.391-0.391-1.023,0-1.414l16-16
+ c0.391-0.391,1.023-0.391,1.414,0s0.391,1.023,0,1.414l-16,16C11.512,24.902,11.256,25,11,25z"/>
+ <path style="fill:#000000;" d="M43,25c-0.256,0-0.512-0.098-0.707-0.293l-16-16c-0.391-0.391-0.391-1.023,0-1.414
+ s1.023-0.391,1.414,0l16,16c0.391,0.391,0.391,1.023,0,1.414C43.512,24.902,43.256,25,43,25z"/>
+ <path style="fill:#000000;" d="M43,2H11c-0.552,0-1-0.448-1-1s0.448-1,1-1h32c0.552,0,1,0.448,1,1S43.552,2,43,2z"/>
+</g>
+ </svg> symbol in the top left corner.
+ </li>
<li>
The Erlang language is described in the
<a href="reference_manual/users_guide.html">Erlang Reference Manual</a>.